如果您想要一个简短的示例来帮助您入门,那么在将字符串读入字符数组(缓冲区)时要记住的第一件事是不要吝啬缓冲区大小!. 使用10and20可能会为您显示的一小部分数据削减它,但是当您尝试阅读时会发生什么Mandheling Black?使用您最长的预期字符串,并且在使用固定数组时至少将字符数加倍(如果它是一个要重复使用的缓冲区,例如读取每一行,1K 缓冲区大小就可以了,2K 也可以)
尽量避免使用像and之类的MagicNumbers,而是:1020
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXNM 32 /* (don't skimp on buffer size) */
#define MAXCT 16
typedef struct cofeeshop { /* typedef avoid writing 'struct name' in code */
char cofeeName [MAXNM],
cofeeColor [MAXNM],
cofeeWorld [MAXNM];
int CofeePockets,
onePocketSize;
} cofeeshop;
...
如果您在上面注意到, a typedefofstruct cofeeshop是在 name 中创建的cofeeshop。通过创建typedef,您可以简单地将cofeeshop其用作代码中任何需要的类型,而不必struct cofeeshop每次都编写。
您需要从文件中实际读取的是一个足够大以容纳每一行的缓冲区(字符数组),一个用于跟踪您已读取多少咖啡类型的计数器,然后是一个cofeeshop用于保存每个包含的值的数组线。您可以这样做,同时将要读取的文件名作为程序的第一个参数(或者stdin如果没有给出参数,则从读取),如下所示:
int main (int argc, char **argv) {
char line[MAXC]; /* buffer to hold each line */
cofeeshop cofee[MAXCT] = {{.cofeeName = ""}}; /* array of chofeeshop */
size_t n = 0; /* cofeetype counter */
/* 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;
}
...
请注意,在您尝试从文件中读取之前,始终验证使用的任何输入/输出函数的返回,包括fopen()成功或失败。
然后,您可以将文件中的每一行读取fgets()到您的缓冲区中line,然后传递line给以sscanf()将部分分隔line到结构数组中的下一个可用元素中cofee,例如
...
/* while array not full, read each line in file and add to array */
while (n < MAXCT && fgets (line, MAXC, fp)) {
/* separate into name, color, world, pockets, size & VALIDATE return */
if (sscanf (line, "%s %s %s %d %d", cofee[n].cofeeName, cofee[n].cofeeColor,
cofee[n].cofeeWorld, &cofee[n].CofeePockets,
&cofee[n].onePocketSize) == 5) {
n++; /* increment cofeetype counter */
}
}
...
注意:您验证返回sscanf()以检查格式字符串中每个格式说明符的转换是否成功。格式字符串中有五个格式说明符,因此在考虑要使用来自的有效输入填充的变量之前检查一下。 "%s %s %s %d %d"return == 5line
至此,您已完成对输入的读取,因此,如果不读取stdin并输出存储在数组中的所有值,则只需关闭文件即可stdout,例如
...
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < n; i++) /* output stored values */
printf ("%-12s %-12s %-12s %4d %4d\n", cofee[i].cofeeName, cofee[i].cofeeColor,
cofee[i].cofeeWorld, cofee[i].CofeePockets, cofee[i].onePocketSize);
}
剩下的就是以您选择的格式将值写入输出文件 - 这留给您。
总而言之(即上面的完整代码),您将拥有:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXNM 32 /* (don't skimp on buffer size) */
#define MAXCT 16
typedef struct cofeeshop { /* typedef avoid writing 'struct name' in code */
char cofeeName [MAXNM],
cofeeColor [MAXNM],
cofeeWorld [MAXNM];
int CofeePockets,
onePocketSize;
} cofeeshop;
int main (int argc, char **argv) {
char line[MAXC]; /* buffer to hold each line */
cofeeshop cofee[MAXCT] = {{.cofeeName = ""}}; /* array of chofeeshop */
size_t n = 0; /* cofeetype counter */
/* 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;
}
/* while array not full, read each line in file and add to array */
while (n < MAXCT && fgets (line, MAXC, fp)) {
/* separate into name, color, world, pockets, size & VALIDATE return */
if (sscanf (line, "%s %s %s %d %d", cofee[n].cofeeName, cofee[n].cofeeColor,
cofee[n].cofeeWorld, &cofee[n].CofeePockets,
&cofee[n].onePocketSize) == 5) {
n++; /* increment cofeetype counter */
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < n; i++) /* output stored values */
printf ("%-12s %-12s %-12s %4d %4d\n", cofee[i].cofeeName, cofee[i].cofeeColor,
cofee[i].cofeeWorld, cofee[i].CofeePockets, cofee[i].onePocketSize);
}
编译
每次都在启用完整警告的情况下编译您的程序- 并且在没有警告的情况下编译之前不要接受代码,例如
gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -o bin/cofeeshop cofeeshop.c
-Wall -Wextra -pedantic启用 gcc/clang 的完整警告,添加-Wshadow以捕获任何隐藏的变量(例如i在代码中可能导致问题的两个不同范围内声明和使用)。对于 VS/W3用于完整警告。对于其他编译器,只需阅读选项文档以确定需要什么。
示例使用/输出
使用文件中的示例数据dat/cofeeshop.txt,您将拥有:
$ ./bin/cofeeshop dat/cofeeshop.txt
Lavazza Gray Europe 433 10
Machito Black Europe 433 10
Machito White Asia 24 18
Chiley Black Asia 198 17
Hucki White America 11 11
如果您想测试从 读取stdin,您可以将输入文件重定向到stdin,例如:
$ ./bin/cofeeshop < dat/cofeeshop.txt
Lavazza Gray Europe 433 10
Machito Black Europe 433 10
Machito White Asia 24 18
Chiley Black Asia 198 17
Hucki White America 11 11
如果您还有其他问题,请仔细查看并告诉我。
(注意:cofee通常拼写coffee- 但会与你所拥有的一起去:)