有几点需要说明 (1) 永远不要吝啬缓冲区大小。 20 对于大部分正在使用的名称来说是非常不足的。 64 可能是一个合理的大小,然后你取那个合理的大小并将其 加倍。
接下来,(2)不清楚name 在您的代码中做了什么,但由于它用于for 循环限制,这似乎是您希望限制读取的名称数量。您必须控制您的读取循环,使其在 1 时退出 - 您的读取索引不再小于您的 name 限制 && fgets() 返回一个有效指针,例如
#include <stdio.h>
#include <string.h>
#define MAXNM 128 /* if you need a constant, #define one (or more) */
#define NUMNM 10 /* ( Don't skimp on buffer size! ) */
int main (int argc, char **argv) {
char buffer[MAXNM];
size_t ndx = 0, name = NUMNM;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
...
while (ndx < name && fgets (buffer, MAXNM, fp)) {
buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
}
上面使用了一个简单的ndx(索引)变量以及fgets 的返回值来控制您的读取循环。这消除了文件中的行数少于 names 的问题,然后盲目地从错误状态的流中读取,直到发生 name 迭代。通过使用ndx < NUMNM && fgets (buf, MAXC, fp) 作为循环控制,您可以在任一条件不再为真时优雅地退出,从而避免未定义的行为。
(3) 如果您打算存储每个buffer 中的名称,则需要为每个名称分配存储空间并将buffer 复制到下一次迭代之前的新存储空间,否则之前的名称将在@ 时丢失987654336@已充值。
(4) fgets 最多读取并包括填充缓冲区末尾的尾随 '\n'。您不希望将您的姓名与'\n's 悬垂在末尾。 strcspn 是确定buffer 中'\n' 之前的字符数的最简单和最可靠的方法之一,然后简单地用nul-character 覆盖'\n'。您只需要上面显示的内容,例如
buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
请参阅strspn(3) - Linux manual page,看看您是否能准确了解其工作原理。
(5)总是检查每个文件打开(以及在流被写入后关闭)的返回,并且总是检查每个用户输入函数的返回。在您的代码中,没有比验证您从文件或用户收到的数据在尝试处理该数据之前更关键的步骤了。否则,您只是在邀请未定义的行为,只需轻轻一击键或一个拼写错误。
将它完全放在一个程序中,该程序将要打开的文件名作为程序的第一个参数(如果没有提供参数,则默认从 stdin 读取),您可以执行以下操作:
#include <stdio.h>
#include <string.h>
#define MAXNM 128 /* if you need a constant, #define one (or more) */
#define NUMNM 10 /* ( Don't skimp on buffer size! ) */
int main (int argc, char **argv) {
char buffer[MAXNM];
size_t ndx = 0, name = NUMNM;
/* 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 (ndx < name && fgets (buffer, MAXNM, fp)) {
buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
输入文件示例
现在使用包含 11 个名称的文件练习您的输入例程,比 NUMNM 允许读取的名称多一个,例如
$ cat dat/namesonly.txt
Zeda'Taxu
Khano'Balme
Goni
Ryan,Elizabeth
McIntyre,Osborne
DuMond,Kristin
Larson,Lois
Thorpe,Trinity
Ruiz,Pedro
Ali,Mohammed
Vashti,Indura
使用/输出示例
读取和停止 NUMNM 个名称
$ ./bin/fgetsnames <dat/namesonly.txt
name[ 1] : Zeda'Taxu
name[ 2] : Khano'Balme
name[ 3] : Goni
name[ 4] : Ryan,Elizabeth
name[ 5] : McIntyre,Osborne
name[ 6] : DuMond,Kristin
name[ 7] : Larson,Lois
name[ 8] : Thorpe,Trinity
name[ 9] : Ruiz,Pedro
name[10] : Ali,Mohammed
查看一下,如果您还有其他问题,请告诉我。