Несмотря на то, что на базовую предпосылку вопроса отвечали много раз, каждая реализация достаточно разная в зависимости от формата файла данных, что затрудняет поиск точного дубликата.
Продолжая из комментария,подход тот же, но детали того, как вы обрабатываете чтение, будут различаться в зависимости от формата входного файла и членов структуры.Когда вам дается первая строка, указывающая, сколько из того, что будет дальше, вам нужно будет прочитать, самый простой способ обработать хранилище для вашего массива stuct - просто выделить хранилище для этого множества структур с помощью malloc
(вы можете использовать calloc
если вы хотите обнулить все байты во время выделения).Хотя вы можете использовать VLA (массив переменной длины), его так же легко выделить для 'n'
struct.
Чтение в вашем случае становится проблемой.Вам необходимо прочитать данные из двух отдельных строк в одну структуру.Хотя я бы обычно предлагал fgets
прочитать каждую строку и затем вызвать sscanf
для анализа данных (что вы все равно могли бы сделать здесь), fscanf
с его строкой формата упростит процесс, позволив вам прочитать обе строкиданные за один вызов тогда и только тогда, когда вы уже знаете количество элементов в вашем массиве элементов (ваш numbers
).В вашем случае он установлен на 6
, поэтому, если это так, вы можете выбрать простой маршрут.
При чтении с помощью любой функции ввода (и особенно семейства функций scanf
), вы должны проверить правильность возврата функции, чтобы убедиться в успешном преобразовании для каждого спецификатора преобразования в строке формата .Семейство функций scanf
возвращает количество успешных конверсий (или EOF, если конец файла был обнаружен до того, как конверсия произошла).Поскольку fscanf
будет игнорировать промежуточный '\n'
, вы можете прочитать обе строки ваших данных для каждой структуры следующим образом:
int rtn = fscanf (fp, "%19s %19s %d %d %d %d %d %d",
players[i].firstName, players[i].lastName,
&players[i].numbers[0], &players[i].numbers[1],
&players[i].numbers[2], &players[i].numbers[3],
&players[i].numbers[4], &players[i].numbers[5]);
Вы подтвердите, что успешное чтение произошло, прежде чем вы увеличите i
с чем-то вроде следующего:
if (rtn == EOF) /* validate fscanf return not EOF */
break;
else if (rtn != 8) { /* check for matching or input failure */
fputs ("error: matching or input failure occurred.\n", stderr);
break;
}
else /* all struct values read, increment counter */
i++;
Вы помещаете это в цикл и цикл до тех пор, пока ваш индекс не достигнет числа элементов, которые вам сказали прочитать (или произойдет EOF
), и вы по существу сделали это (донне забудьте закрыть файл, из которого вы читаете, и free
выделенную память).Короткий пример, выражающий это в целом:
#include <stdio.h>
#include <stdlib.h>
typedef struct KnightsBallLottoPlayer {
char firstName[20];
char lastName[20];
int numbers[6];
} KBLottoPlayer;
int main (int argc, char **argv) {
size_t i = 0, n = 0;
KBLottoPlayer *players = NULL; /* pointer to players */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (fscanf (fp, "%zu", &n) != 1) { /* read first value into size_t */
fputs ("error: invalid format - 'n'\n", stderr);
return 1;
}
/* allocate/validate array of 'n' KBLottoPlayer */
if ((players = malloc (n * sizeof *players)) == NULL) {
perror ("malloc-players");
return 1;
}
while (i < n) { /* read until 'n' struct worth of data read */
int rtn = fscanf (fp, "%19s %19s %d %d %d %d %d %d",
players[i].firstName, players[i].lastName,
&players[i].numbers[0], &players[i].numbers[1],
&players[i].numbers[2], &players[i].numbers[3],
&players[i].numbers[4], &players[i].numbers[5]);
if (rtn == EOF) /* validate fscanf return not EOF */
break;
else if (rtn != 8) { /* check for matching or input failure */
fputs ("error: matching or input failure occurred.\n", stderr);
break;
}
else /* all struct values read, increment counter */
i++;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (i < n) { /* validate 'n' value read or reduce 'n' */
fputs ("error: less than all data read.\n", stderr);
n = i;
}
for (i = 0; i < n; i++) /* output results */
printf ("%s %s\n%d %d %d %d %d %d\n",
players[i].firstName, players[i].lastName,
players[i].numbers[0], players[i].numbers[1],
players[i].numbers[2], players[i].numbers[3],
players[i].numbers[4], players[i].numbers[5]);
free (players); /* don't forget to free the memory you allocate */
return 0;
}
( note: %19s
в fscanf
предотвращает чтение более 19 символов (плюс ноль ).завершающий символ для обеих firstName, lastName
переменных, чтобы предотвратить запись за пределы их массива)
Пример Использование / Вывод
$ ./bin/players_struct <dat/playerdata.txt
Llewellyn Mark
1 15 19 26 33 46
Young Brian
17 19 33 34 46 47
Cazalas Jonathan
1 4 9 16 25 36
Siu Max
7 19 34 46 47 48
Balci Murat
5 10 17 19 34 47
Просмотрите все и дайтеЯ знаю, если у вас есть дополнительные вопросы. Есть много разных способов сделать это, и использование VLA позволит избежать распределения, но это, вероятно, наравне с любым из простых подходов. Всегда есть дополнительные проверки, которые вы можете использовать, но вышеохватывает наиболее важные.