Забудьте, что функция gets()
существует - она смертельна.Вместо этого используйте fgets()
(но обратите внимание, что он не удаляет символ новой строки в конце строки).
Вы хотите поместить один символ за раз: используйте putchar()
, чтобы записать его в стандартный вывод.Не забудьте добавить новую строку в выход после цикла.
Кроме того, for (length = length; length >= 0; length--)
не является идиоматическим C. Используйте одно из:
for ( ; length >= 0; length--)
for (length = strlen(string) - 1; length >= 0; length--)
for (int length = strlen(string) - 1; length >= 0; length--)
В последней альтернативе используется функция, добавленная в C99 (которая была доступна в C ++ задолго до этого).
Такжемы могли бы обсудить, является ли length
подходящим именем для переменной.Лучше было бы переименовать его в i
или pos
или что-то подобное, потому что, хотя оно инициализируется длиной входного файла, оно фактически используется как индекс массива, а не как длина чего-либо.
Субъективный : не ставьте пробел между именем функции и списком ее параметров.Отцы-основатели C этого не делают - и вы не должны.
Почему «получает () смертельно?»
Первый интернет-червь - Моррис червь 1988 года - использовал программу fingerd
, которая использовала gets()
вместо fgets()
.С тех пор многие программы были повреждены, потому что они использовали gets()
, а не fgets()
или другую альтернативу.
Фундаментальная проблема заключается в том, что gets()
не знает, сколько места доступно для хранения данных.читает.Это приводит к «переполнению буфера» - термину, который можно искать в вашей любимой поисковой системе, который будет возвращать огромное количество записей.
Если кто-то введет 150 символов ввода в пример программы, то gets()
будет хранить 150 символов в массиве длиной 100. Это никогда не приводит к счастью - обычно это приводит к дампу ядра, но с тщательно выбранными входными данными - часто генерируемыми скриптами Perl или Python - вы, вероятно, можете заставить программу выполнятьсяпроизвольный другой код.Это действительно имеет значение, если программа когда-либо будет запускаться пользователем с «повышенными привилегиями».
Кстати, gets()
, вероятно, будет удален из библиотеки Standard C в следующем выпуске (C1x - см. N1494 из WG14 ).Он еще долго не исчезнет из реальных библиотек C (20 лет?), Но его следует заменить на эту реализацию (или что-то подобное):
#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
assert("Probability of using gets() safely" == 0);
}
Oneдругие мелкие детали, частично обсуждаемые под комментариями к основному вопросу.
Показанный код явно для C99;объявление length
на полпути через функцию недопустимо в C89.Учитывая это, для функции main()
все в порядке, чтобы она не возвращала значение явно, потому что стандарт C99 следует примеру стандарта C ++ и позволяет пропустить возврат из main()
, а эффект такой же, какreturn(0);
или return 0;
в конце.
Таким образом, программа в этом вопросе не может быть строго ошибочной из-за отсутствия return
в конце.Тем не менее, я рассматриваю это как одно из более специфических решений по стандартизации, и я бы предпочел, чтобы стандарты исключили это положение - или сделали что-то более радикальное, например, разрешив вездесущему, но ошибочному void main()
наблюдать это, когда контроль возвращается из этогоВ результате статус успеха возвращается в среду.К сожалению, не стоит бороться за изменение этого аспекта стандарта, но в качестве личного стиля я не использую лицензию, предоставленную для исключения финального return
из main()
.Если код должен работать с компиляторами C89, в конце он должен иметь явное return 0;
(но тогда объявление length
также должно быть исправлено).