Почему scanf (); пропускаем первую строчку? - PullRequest
1 голос
/ 09 мая 2020

Итак, после scanf printf(); пропускает первую строку.
Я прочитал несколько вопросов, в которых говорится, что "%[^\n]" должен быть " %[^\n]", чтобы пропустить новую строку.
Я пробовал оба, но он все равно выводит тот же результат, и теперь я не знаю, почему это не работает.

Example input
Enter number of Materi: 4
Materia 1 name : a
Materia 2 name : b
materia 3 name : c
materia 4 name : d

Output:
Materia - 1 : R╒fu
Materia - 2 : a
Materia - 3 : b
Materia - 4 : c
#include<stdio.h>
#include<windows.h>

int main(int argc, const char *argv[]){

    int i;
    int V;

    printf("Enter number of Materi: ");
    scanf("%d", &V); fflush(stdin);

    //Insert materia
    char materia[V][50];
    for(i = 0; i < V; i++){
        printf("Materia %d name : ", i+1);scanf("%[^\n]", &materia[i][50]);fflush(stdin);
    }

    for(i = 0; i < V; i++){
        printf("Materia - %d: %s\n", i+1, materia[i]);
    }
    system("pause");

    return 0;
}


Ответы [ 3 ]

3 голосов
/ 09 мая 2020

В программе несколько ошибок

  • Массив, переданный в scanf, неверен.

  • fflush(stdin) не- стандартный, хотя Windows поддерживает его, он не переносится. Но вы не используете Windows, потому что он не поддерживает VLA char materia[V][50];

  • Новые строки, на которых остановится формат scanf "%[^\n]", уже являются следующими во входном буфере.

  • Возвращаемое значение из scanf не проверялось. Это количество успешно отсканированных элементов.

  • У вас может быть переполнение буфера, потому что длина входной строки не ограничена.

Вот скорректированный код:

#include<stdio.h>

int main(int argc, const char *argv[]){

    int i;
    int V;

    printf("Enter number of Materi: ");
    if(scanf("%d", &V) != 1) {
        /* add some error message */
        return 1;
    }
    // fflush(stdin);               // removed

    //Insert materia
    char materia[V][50];
    for(i = 0; i < V; i++){
        printf("Materia %d name : ", i+1);
        // add a space to filter the newline
        // correct the array passed
        // and restrict the length to prevent buffer overflow
        if(scanf(" %49[^\n]", materia[i]) != 1) {
            /* add some error message */
            return 1;
        }
        // fflush(stdin);           // removed
    }

    for(i = 0; i < V; i++){
        printf("Materia - %d: %s\n", i+1, materia[i]);
    }

    return 0;
}

О новых строках. Спецификации формата %d и %s и %f автоматически отфильтровывают начальные пробелы, но %c и %[] и %n этого не делают. Функции scanf останавливаются на первом символе, который они не могут преобразовать, который остается во входном буфере. %[^\n] говорит ему остановиться на первой новой строке. Но он уже есть, из первого %d scanf, и его необходимо удалить, также в последующих итерациях, и добавление пространства выполняет эту работу. Попытка удалить его после этого неуклюжа и не гарантирует работы.

Вы должны проверять возвращаемое значение из scanf каждый раз, когда оно используется. Это количество успешно отсканированных элементов. Здесь должно быть 1 в обоих случаях. Поэтому, если у вас есть два элемента в одном операторе, его возвращаемое значение должно быть 2.

1 голос
/ 09 мая 2020

В строке:

scanf("%[^\n]", &materia[i][50]); 

Вы сохраняете введенную строку по адресу materia[i][50], эффективно сохраняя ее за пределами массива.

Здесь происходит что-то интересное , Хранение 2D-массива является непрерывным, как если бы это был одномерный вектор, происходит то, что вы сохраняете первую строку в начале второй строки массива, вторую - в третьей и так далее, оставляя первую пустую. Это рациональный результат, который производит программа.

Исправьте код с помощью:

#include<stdlib.h>

//...

if(scanf(" %49[^\n]", materia[i] != 1) {
   puts("Read error");
   return EXIT_FAILURE;       
}

49 символов + терминатор nul, чтобы избежать переполнения, пробел в начале спецификатора позволяет избежать использования пустых символов, оставшихся в stdin буфер. Всегда проверяйте scanf return, чтобы избежать ошибок чтения.

Некоторые другие проблемы:

  • fflush(stdin) следует удалить, так как fflush должно быть вызывается в выходном потоке .

  • Массивы с переменной длиной могут вызвать переполнение стека, если используется достаточно памяти, в этом случае это маловероятно, но об этом следует помнить.

0 голосов
/ 09 мая 2020

Используйте fgets вместо scanf. Символ новой строки используется как символ вашим последующим scanf. Вот почему вы столкнулись с этой проблемой.

...