Окончательный диагноз
Вы не показываете свои объявления ... но вы должны выделить только 5 символов для строк:
Когда я настраиваю enum MAX_ASSESSMENTLEN от 10 до 5 (см. код ниже) Я получаю вывод:
Prog1Quiz 20
Quiz 20
Prog2Mdtm 20
Mdtm 15
Final 25
Вы не допустили нулевой терминал.И вы не показали нам, что вызвало ошибку!И тот факт, что вы пропустили переводы строк в распечатке, скрыл проблему.
То, что происходит, - то, что 'Prog1' занимает все 5 байтов строки, которую вы читаете, и записывает ноль в 6-м байте;затем читается викторина, начиная с шестого байта.Когда printf()
идет, чтобы прочитать строку для «Prog1», он останавливается на первом нулевом значении, которое является последующим после «z» в «Quiz», производя показанный результат.Повторите для «Prog2» и «Mtdm».Если после «Финала» будет запись, она тоже пострадает.Вам повезло, что вокруг достаточно нулевых байтов, чтобы предотвратить любые чудовищные переполнения.
Это базовое переполнение буфера (действительно, поскольку массив находится в стеке, это базовое переполнение стека );Вы пытаетесь втиснуть 6 символов (Prog1 плюс '\0'
) в 5-байтовое пространство, и оно просто не работает должным образом.
Предварительная диагностика
Сначала напечатайте новые строки послеваши данные.
Во-вторых, проверьте, что scanf () не возвращает ошибки - вероятно, это не так, но ни вы, ни мы не можем сказать точно.
В-третьих, вы уверены, чтофайл данных содержит то, что вы говорите?Вероятно, он содержит пару «Викторина» и пару строк «Mtdm».
Ваша переменная j
, кстати, не используется.
Возможно, было бы лучше иметь вводцикл запускается до тех пор, пока в приемных массивах не останется свободного места или произойдет сбой чтения.Тем не менее, код работал для меня, когда немного одет:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char assLabel[10][10];
int assPercent[10];
int i = 0;
int totalGradedItems = 5;
while (i < totalGradedItems)
{
if (scanf("%9s%d", assLabel[i], &assPercent[i]) != 2)
{
fprintf(stderr, "Error reading\n");
exit(1);
}
i++;
}
/* Print Statement */
i = 0;
while (i < totalGradedItems)
{
printf("%-9s %3d\n", assLabel[i], assPercent[i]);
i++;
}
return 0;
}
Для указанных входных данных, выходные результаты:
Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25
Я предпочитаю эту версию, хотя:
#include <stdio.h>
enum { MAX_GRADES = 10 };
enum { MAX_ASSESSMENTLEN = 10 };
int main(void)
{
char assLabel[MAX_GRADES][MAX_ASSESSMENTLEN];
int assPercent[MAX_GRADES];
int i = 0;
int totalGradedItems;
for (i = 0; i < MAX_GRADES; i++)
{
if (scanf("%9s%d", assLabel[i], &assPercent[i]) != 2)
break;
}
totalGradedItems = i;
for (i = 0; i < totalGradedItems; i++)
printf("%-9s %3d\n", assLabel[i], assPercent[i]);
return 0;
}
Конечно, если бы я установил строку формата scanf()
'правильно' (то есть безопасно), чтобы ограничить длину имен оценки, чтобы они соответствовали выделенному пространству, тогда циклпрекратите чтение со второй попытки:
...
char format[10];
...
snprintf(format, sizeof(format), "%%%ds%%d", MAX_ASSESSMENTLEN-1);
...
if (scanf(format, assLabel[i], &assPercent[i]) != 2)
При MAX_ASSESSMENTLEN в 5, snprintf()
генерирует строку формата "%4s%d"
.Скомпилированный код читает:
Prog 1
и останавливается.«1» происходит от 5-го символа «Prog1»;следующее имя оценки - «20», а затем преобразование «Викторины» в число завершается неудачно, в результате чего цикл ввода останавливается (поскольку был преобразован только один из двух ожидаемых элементов).
Несмотря на неудобство, если вы хотите, чтобы ваши строки scanf()
корректировались в соответствии с размером переменных данных, в которые они читают, вы должны сделать что-то похожее на то, что я сделал здесь - отформатировать строку, используя правильные значения размера.