Читання рядка за допомогою scanf () не добре?

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

Мій друг запропонував, що використання fgets() для читання рядка як введення буде набагато краще, ніж використовувати scanf() , як у викладі вище. Він виправданий?

12
fgets() краще. Але це більше як scanf ("% [^ \ n]", line); (без пробілу у форматі). "% [^ \ n]" OP буде використовувати основний пробіл без збереження в рядку . fgets() з збереженням провідного пробілу (тобто не \ n ).
додано Автор chux, джерело
fgets() краще. Але це більше як scanf ("% [^ \ n]", line); (без пробілу у форматі). "% [^ \ n]" OP буде використовувати основний пробіл без збереження в рядку . fgets() з збереженням провідного пробілу (тобто не \ n ).
додано Автор chux, джерело
Будь-який scanf з % s або % [ без специфікатора довжини слід вважати помилкою. Тепер, якщо ви вказали довжину, це було б цікаво питанням.
додано Автор Cubbi, джерело
Будь-який scanf з % s або % [ без специфікатора довжини слід вважати помилкою. Тепер, якщо ви вказали довжину, це було б цікаво питанням.
додано Автор Cubbi, джерело
це має бути scanf ("% [^ \ n]", рядок); закрийте фігуру в аргументі ..
додано Автор Raghu Srikanth Reddy, джерело
Він абсолютно є. Я завжди пропоную використовувати fgets() і повністю уникати scanf() .
додано Автор user529758, джерело
@RaghuSrikanthReddy Ідеальний приклад того, чому не слід використовувати scanf() .
додано Автор user529758, джерело
@RaghuSrikanthReddy Ідеальний приклад того, чому не слід використовувати scanf() .
додано Автор user529758, джерело

11 Відповіді

char * fgets ( char * str, int num, FILE * stream ); is safe to use because it avoid buffer overflow problem, it scans only num-1 number of char.

Читає символи з потоку та зберігає їх як рядок C в стрі, доки не буде прочитано символи (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 ( і відкидають інші додаткові символи введення, просто зберігає п'ять символів у str [] ).

У той час як scanf ("% [^ \ n]", str); буде прочитати, поки \ n не знайдено, а якщо довжина вводу довша, то 4 chars scanf() призведе до переповнення буферу (як scanf спробує отримати доступ до пам'яті за межами максимального індексу 4 в str [] ).

18
додано
@mulous: пан Юхао дав дуже хороший зв'язок. Читайте там, серія функцій scanf() , printf() хороша для форматованого введення/виведення
додано Автор Grijesh Chauhan, джерело
Дякую за детальне пояснення. Чи буде scanf() кращим вибором, якщо я не знаю, як довго буде мій рядок введення?
додано Автор amulous, джерело

char * fgets ( char * str, int num, FILE * stream ); is safe to use because it avoid buffer overflow problem, it scans only num-1 number of char.

Читає символи з потоку та зберігає їх як рядок C в стрі, доки не буде прочитано символи (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 ( і відкидають інші додаткові символи введення, просто зберігає п'ять символів у str [] ).

У той час як scanf ("% [^ \ n]", str); буде прочитати, поки \ n не знайдено, а якщо довжина вводу довша, то 4 chars scanf() призведе до переповнення буферу (як scanf спробує отримати доступ до пам'яті за межами максимального індексу 4 в str [] ).

18
додано
@mulous: пан Юхао дав дуже хороший зв'язок. Читайте там, серія функцій scanf() , printf() хороша для форматованого введення/виведення
додано Автор Grijesh Chauhan, джерело
Дякую за детальне пояснення. Чи буде scanf() кращим вибором, якщо я не знаю, як довго буде мій рядок введення?
додано Автор amulous, джерело

C FAQ has some detailed explanation about scanf's problem:

Загалом, scanf призначений для відносно структурованого форматованого введення (його назва фактично походить від "відформатованого сканування"). Якщо ви звернете увагу, він скаже вам, чи це вдалося або не вдалося, але він може розповісти вам лише приблизно про те, де він зазнав невдачі, і взагалі не як і чому. У вас дуже мало можливостей для виправлення помилок.

Докладніше про це див тут .

7
додано
дуже хороша ланка. Спасибі
додано Автор Grijesh Chauhan, джерело
Це дуже корисна посилання. Дякую!
додано Автор amulous, джерело

C FAQ has some detailed explanation about scanf's problem:

Загалом, scanf призначений для відносно структурованого форматованого введення (його назва фактично походить від "відформатованого сканування"). Якщо ви звернете увагу, він скаже вам, чи це вдалося або не вдалося, але він може розповісти вам лише приблизно про те, де він зазнав невдачі, і взагалі не як і чому. У вас дуже мало можливостей для виправлення помилок.

Докладніше про це див тут .

7
додано
дуже хороша ланка. Спасибі
додано Автор Grijesh Chauhan, джерело
Це дуже корисна посилання. Дякую!
додано Автор amulous, джерело

fgets will be better than this scanf. There may be following issues with scanf as given in OP

1) переповнення буфера, як це було запропоновано @Grijesh

2) Можливо наступний scanf після цього не буде працювати, тому що новий рядок залишиться у потоці введення (якщо ви пропустите порожнє місце)

3
додано

Простіше кажучи: так, fgets - кращий вибір.

Я подивився на ваш специфікатор формату scanf , і я був містифікований. Розуміння точно, що воно вимагає деякого часу, читаючи через сторінки man .

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

Зберігайте це простим способом, і ви зменшите витрати на технічне обслуговування та уникнути важких помилок!

3
додано
Переповнення буфера - це диявол. Зрозумів. Дякую.
додано Автор amulous, джерело

Простіше кажучи: так, fgets - кращий вибір.

Я подивився на ваш специфікатор формату scanf , і я був містифікований. Розуміння точно, що воно вимагає деякого часу, читаючи через сторінки man .

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

Зберігайте це простим способом, і ви зменшите витрати на технічне обслуговування та уникнути важких помилок!

3
додано
Переповнення буфера - це диявол. Зрозумів. Дякую.
додано Автор amulous, джерело

Так fgets - це кращий і безпечний спосіб прочитати рядок зі стандартного вводу.

Крім того, в коді буде більше читабельності. Подивіться на скановане твердження, надане вами.

Будь-яка друга людина, яка її бачить, буде досконало плутатися. Але в той час, як буде більше readeablity для fgets, і це легко зрозуміти.

3
додано
Ви суперечили собі. можливо, ви мали на увазі fgets у першому реченні.
додано Автор Jim Balter, джерело
@ Джим Балтер дякую за корекцію
додано Автор Kranthi Kumar, джерело

Так fgets - це кращий і безпечний спосіб прочитати рядок зі стандартного вводу.

Крім того, в коді буде більше читабельності. Подивіться на скановане твердження, надане вами.

Будь-яка друга людина, яка її бачить, буде досконало плутатися. Але в той час, як буде більше readeablity для fgets, і це легко зрозуміти.

3
додано
Ви суперечили собі. можливо, ви мали на увазі fgets у першому реченні.
додано Автор Jim Balter, джерело
@ Джим Балтер дякую за корекцію
додано Автор Kranthi Kumar, джерело

Не використовуйте fgets (...), замість цього скористайтеся наступним фрагментом:

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

Не використовуйте fgets (...), замість цього скористайтеся наступним фрагментом:

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