为什么 fgets 可以在两次调用时正常工作?
Why fgets works fine with two calls?
我是 C 语言的新手(几年)。我想知道为什么 fgets()
可以很好地处理两个调用,而不是一个。变量是:
FILE *dat;
int i;
char buff [22];
char *file;
i = 0;
dat = fopen(file__dat, "r");
这是包含两个调用的代码:
for (i = 0; i < num; i++) {
fgets(buff, 22, dat);
printf("%s\n", buff);
file = strtok(buff, ",");
strcpy (aparell [i].Name, file);
file = strtok(NULL, ",");
strcpy(aparell[i].MAC, file);
fgets(buff, 22, dat);
}
一次调用:
for (i = 0; i < num; i++) {
fgets(buff, 22, dat);
printf("%s\n", buff);
file = strtok(buff, ",");
strcpy(aparell [i].Name, file);
file = strtok(NULL, ",");
strcpy(aparell[i].MAC, file);
}
文件是:
CTRL-000,31A0E321456C
CTRL-001,AE45F3123BAA
CTRL-002,2956FECA24A3
CTRL-003,AA345FCC23FA
CTRL-004,FA345778123A
CTRL-502,34F45A3423DD
提前致谢。 :)
有
fgets (buff, 22, dat);
你读正好字符的数量就行了,除了一个: 换行在行尾。
如果您只读取 22 个字符,fgets
将不会读取换行符,留给第二个 fgets
读取(作为空 "line")。
将 buff
的大小增加一(至 23
)并使用 sizeof buff
作为大小。然后 fgets
将从文件中读取所有行,包括换行符。 (希望文件的格式不会随着行数的增加而改变。)
这种行为有据可查。来自例如this fgets
reference:
Reads at most count - 1
characters from the given file stream...
第一个fgets(buff, 22, dat);
最多从流中读取21个字节,正好是换行序列前第一行的字节数:CTRL-000,31A0E321456C
.
随后的 strtok()
调用确实找到了标记并且该行被正确解析。
在循环的下一次迭代中,fgets(buff, 22, dat);
读取换行符并停在那里,导致第二个 strtok
失败并 return NULL
。由于您没有测试 return 值,因此 strcpy (aparell[i].MAC,file);
具有未定义的行为,因为 file
是空指针。
当您添加 extra fgets()
时,换行符被读取并被忽略,下一次迭代读取下一行。
您应该通过增加缓冲区大小并测试 fgets()
和 strtok()
的 return 值来修复代码以避免未定义的行为。您还应该将 \n
视为分隔符,以避免将其包含在最后一个字段中。
这是一个改进的版本:
char buff[128];
for (i = 0; i < num; i++) {
if (!fgets(buff, sizeof buf, dat)) {
fprintf(stderr, "missing input\n");
break;
}
printf("%s", buff);
file = strtok(buff, ",\n");
if (file == NULL) {
fprintf(stderr, "invalid input\n");
break;
}
strcpy(aparell[i].Name, file);
file = strtok(NULL, ",\n");
if (file == NULL) {
fprintf(stderr, "invalid input\n");
break;
}
strcpy(aparell[i].MAC, file);
}
请注意,在使用 strcpy()
复制到结构字段之前,您还应该检查字符串的长度。
另请注意,strtok()
在解析输入时有一个缺点:它将任何分隔符序列视为单个分隔符。因此它不能处理空字段,例如 ,31A0E321456C
或 CTRL-000,
我是 C 语言的新手(几年)。我想知道为什么 fgets()
可以很好地处理两个调用,而不是一个。变量是:
FILE *dat;
int i;
char buff [22];
char *file;
i = 0;
dat = fopen(file__dat, "r");
这是包含两个调用的代码:
for (i = 0; i < num; i++) {
fgets(buff, 22, dat);
printf("%s\n", buff);
file = strtok(buff, ",");
strcpy (aparell [i].Name, file);
file = strtok(NULL, ",");
strcpy(aparell[i].MAC, file);
fgets(buff, 22, dat);
}
一次调用:
for (i = 0; i < num; i++) {
fgets(buff, 22, dat);
printf("%s\n", buff);
file = strtok(buff, ",");
strcpy(aparell [i].Name, file);
file = strtok(NULL, ",");
strcpy(aparell[i].MAC, file);
}
文件是:
CTRL-000,31A0E321456C
CTRL-001,AE45F3123BAA
CTRL-002,2956FECA24A3
CTRL-003,AA345FCC23FA
CTRL-004,FA345778123A
CTRL-502,34F45A3423DD
提前致谢。 :)
有
fgets (buff, 22, dat);
你读正好字符的数量就行了,除了一个: 换行在行尾。
如果您只读取 22 个字符,fgets
将不会读取换行符,留给第二个 fgets
读取(作为空 "line")。
将 buff
的大小增加一(至 23
)并使用 sizeof buff
作为大小。然后 fgets
将从文件中读取所有行,包括换行符。 (希望文件的格式不会随着行数的增加而改变。)
这种行为有据可查。来自例如this fgets
reference:
Reads at most
count - 1
characters from the given file stream...
第一个fgets(buff, 22, dat);
最多从流中读取21个字节,正好是换行序列前第一行的字节数:CTRL-000,31A0E321456C
.
随后的 strtok()
调用确实找到了标记并且该行被正确解析。
在循环的下一次迭代中,fgets(buff, 22, dat);
读取换行符并停在那里,导致第二个 strtok
失败并 return NULL
。由于您没有测试 return 值,因此 strcpy (aparell[i].MAC,file);
具有未定义的行为,因为 file
是空指针。
当您添加 extra fgets()
时,换行符被读取并被忽略,下一次迭代读取下一行。
您应该通过增加缓冲区大小并测试 fgets()
和 strtok()
的 return 值来修复代码以避免未定义的行为。您还应该将 \n
视为分隔符,以避免将其包含在最后一个字段中。
这是一个改进的版本:
char buff[128];
for (i = 0; i < num; i++) {
if (!fgets(buff, sizeof buf, dat)) {
fprintf(stderr, "missing input\n");
break;
}
printf("%s", buff);
file = strtok(buff, ",\n");
if (file == NULL) {
fprintf(stderr, "invalid input\n");
break;
}
strcpy(aparell[i].Name, file);
file = strtok(NULL, ",\n");
if (file == NULL) {
fprintf(stderr, "invalid input\n");
break;
}
strcpy(aparell[i].MAC, file);
}
请注意,在使用 strcpy()
复制到结构字段之前,您还应该检查字符串的长度。
另请注意,strtok()
在解析输入时有一个缺点:它将任何分隔符序列视为单个分隔符。因此它不能处理空字段,例如 ,31A0E321456C
或 CTRL-000,