将文件读入动态分配的数组

时间:2019-01-20 00:14:58

标签: c

如何写入此文件

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 :(得分:1)

这个问题的基本前提已经被回答了很多次,但是每种实现都基于数据文件格式而变化得足够大,这使得很难找到确切的重复项。

从注释继续,方法是相同的,但是如何处理读取的详细信息将根据输入文件格式和struct成员而有所不同。在第一行中指定了接下来需要阅读的内容时,处理stuct数组存储的最简单方法是简单地使用malloc为那么多结构分配存储(您可以使用calloc(如果您希望在分配时将所有字节清零)。虽然可以使用VLA(可变长度数组),但为'n'结构分配也很容易。

在您的情况下阅读成为挑战。您需要将两行中的数据读取到一个结构中。虽然我通常建议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;
}

注意%19s中的fscanf可以读取19个以上的字符(加上两个{ {1}}变量以防止超出其数组范围写入)

使用/输出示例

firstName, lastName

仔细检查一下,如果还有其他问题,请告诉我。有许多不同的方法可以做到这一点,并且使用VLA可以避免分配,但是这可能与任何简单的方法都差不多。您总可以使用其他验证,但以上内容涵盖了重要的验证。