Почему важно размещение объявления переменной? - PullRequest
1 голос
/ 11 марта 2020

Основная задача моего кода - извлечь данные из внешних файлов, а затем присвоить число в начале. Проблема в том, что приведенный ниже код работает просто отлично.

#include <stdio.h>

int main(void) {
    char name[20], surname[30], group[2];
    puts("Now i download data from file");
    int n = 1, number;
    while (!feof(stdin)) {
        scanf ("%s %s %d %s", name, surname, &number, group);
        printf("%d. %s | %s | %d | %s", n, name, surname, number, group);
    }
    return 0;
}

Но когда я меняю положение одной строки, он устанавливает значение n в 0 и не увеличивается.

#include <stdio.h>

int main(void) {
    int n = 1, number;
    char name[20], surname[30], group[2];
    puts("Now I download data from file");
    while (!feof(stdin)) {
        scanf ("%s %s %d %s", name, surname, &number, group);
        printf("%d. %s | %s | %d | %s", n, name, surname, number, group);
    }
    return 0;
}

1 Ответ

2 голосов
/ 11 марта 2020

Ваш код имеет потенциально неопределенное поведение: если файл данных содержит поля, размер которых превышает максимальную длину, хранимую в целевых массивах, fscanf() вызовет переполнение буфера и перезапишет что-то еще в памяти, возможно, другую локальную переменную .... Изменение порядка определения локальных переменных может изменить побочные эффекты этой ошибки. Неопределенное поведение может привести к чему угодно, от невидимого эффекта до программы cra sh или даже рынка cra * sh.

Также обратите внимание, что while (!feof(stdin)) всегда неверно .

Вот как вы можете изменить свой код, чтобы избежать этого неопределенного поведения и убедиться, что файл данных правильно преобразован:

#include <stdio.h>

int main(void) {
    char buf[128];
    char name[20], surname[30], group[2];
    int n = 1, number;
    char dummy;

    puts("Now I download data from file");

    while (fgets(buf, sizeof buf, stdin)) {
        if (sscanf("%19s %29s %d %1s %c", name, surname, &number, group, &dummy) == 4) {
            printf("%d. %s | %s | %d | %s\n", n++, name, surname, number, group);
        } else {
            printf("Invalid format: %s", buf);
        }
    }
    printf("%d records\n", n);
    return 0;
}

Любые записи с group больше, чем один символ, будут вызвать ошибку формата. Если group может иметь 2 символа, вы должны определить массив как char group[3] и преобразовать его в %2s. Это же замечание относится ко всем строковым полям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...