Чтение строки с помощью scanf() не очень хорошо?

scanf(" %[^\n]",line);

Один мой друг предположил, что использование fgets() для чтения строки в качестве входного сигнала было бы гораздо лучшей идеей, чем использование scanf(), как в приведенном выше утверждении. Он оправдан?

Ответ 1

char * fgets ( char * str, int num, FILE * stream ); безопасен в использовании, поскольку он избегает проблемы с переполнением буфера , он сканирует только num-1 число char.

Считывает символы из потока и сохраняет их как строку C в str до тех пор, пока не будут прочитаны (num-1) символы или не будет достигнута новая строка или конечный файл, в зависимости от того, что произойдет раньше.

здесь второй аргумент num - максимальное количество символов, подлежащих копированию на str (включая завершающий нуль-символ).

Например, предположим, что в вашем коде размер массива строк равен 5 символам, как показано ниже.

 char str[5];
 fgets (str, 5, fp);  //5 =you have provision to avoid buffer overrun 

Используя вышеприведенный код, если ввод из fp длиннее, чем 4 символов, fgets() будет читать только первые 4 символы, а затем добавляет \0 (и отбрасывает другие дополнительные входные символы, просто сохраняет пять char в str[]).

В то время как scanf(" %[^\n]",str); будет читать до тех пор, пока \n не будет найден, и если длина ввода будет длиннее, то 4 chars scanf() вызовет переполнение буфера (as scanf попытается получить доступ к памяти за пределами максимального индекса 4 в str[]).

Ответ 2

C FAQ содержит подробное объяснение проблемы scanf:

В более общем плане scanf предназначен для относительно структурированного отформатированного ввода (его имя фактически получено из "отформатированного сканирования" ). Если вы обратите внимание, он скажет вам, удалось ли это или не удалось, но он может сказать вам только примерно, где это не удалось, и совсем не так, как и почему. У вас очень мало возможностей для восстановления любой ошибки.

см. здесь для подробностей.

Ответ 3

fgets будет лучше, чем этот scanf. Возможны следующие проблемы с scanf, как указано в OP

1) переполнение буфера, предложенное @Grijesh

2) возможно следующий scanf после этого не будет работать, потому что новая строка оставлена ​​во входном потоке (если вы пропустили пробел)

Ответ 4

Да fgets - лучший и безопасный способ чтения строки со стандартного ввода.

Кроме того, в коде будет больше читаемости. Посмотрите на инструкцию scanf, предоставленную вами.

Любой второй человек, который его видит, будет полностью запутан. Но в то время как для fgets будет больше readeablity, и это легко понять.

Ответ 5

Проще говоря: да, fgets - лучший выбор.

Я посмотрел на ваш спецификатор формата scanf, и я был озадачен. Понимая, что именно он делает, требуется некоторое время, просматривая страницы man.

Кроме того, ваш код scanf восприимчив к переполнениям буфера.

Держите его простым, и вы уменьшите затраты на обслуживание и избегаете поиска ошибок!

Ответ 6

не используйте fgets (...) вместо этого следующий фрагмент:

char _x[7000];
    char* y;
while ( ! feof (_f) )
{
    fscanf(_f,"%[^\n]\n",_x);
            y=x;
}