如何写入此文件
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);
答案 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可以避免分配,但是这可能与任何简单的方法都差不多。您总可以使用其他验证,但以上内容涵盖了重要的验证。