Чтение файла в динамически размещенный массив - PullRequest
0 голосов
/ 20 января 2019

Как можно написать этот файл

5 
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`

в динамически размещенный массив

typedef struct KnightsBallLottoPlayer{
char firstName[20];
char lastName[20];
int  numbers[6]
} KBLottoPlayer;

первая строка файла указывает количество отдельных имен и наборов номеров.

Я пытался использовать приведенный ниже код для динамического выделения памяти, необходимой для n людей, использующих структуру, но я теряюсь в том, как читать информацию, после первого чтения, чтобы получить n пользователей.

  int n; 
  FILE *fin;
  fin = fopen("text.in","r");

  if (fin == NULL){
   printf("Error: No File!");
  }

  fscanf(fin, "%d", &n);
  printf("%d",n); //reads file correctly

  struct KnightsBallLottoPlayer *p = calloc(sizeof(KBLottoPlayer), n);

1 Ответ

0 голосов
/ 20 января 2019

Несмотря на то, что на базовую предпосылку вопроса отвечали много раз, каждая реализация достаточно разная в зависимости от формата файла данных, что затрудняет поиск точного дубликата.

Продолжая из комментария,подход тот же, но детали того, как вы обрабатываете чтение, будут различаться в зависимости от формата входного файла и членов структуры.Когда вам дается первая строка, указывающая, сколько из того, что будет дальше, вам нужно будет прочитать, самый простой способ обработать хранилище для вашего массива 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 позволит избежать распределения, но это, вероятно, наравне с любым из простых подходов. Всегда есть дополнительные проверки, которые вы можете использовать, но вышеохватывает наиболее важные.

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