为什么fgets可以在两次通话时正常工作?

时间:2018-04-17 12:20:17

标签: c fgets

我是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 

提前谢谢你。 :)

2 个答案:

答案 0 :(得分:3)

第一个fgets(buff, 22, dat);从流中读取最多21个字节,恰好是换行符序列之前第一行的字节数:CTRL-000,31A0E321456C

后续strtok()次调用会找到令牌并正确解析该行。

在循环的下一次迭代中,fgets(buff, 22, dat);读取换行符并停在那里,导致第二个strtok失败并返回NULL。由于您不测试返回值,strcpy (aparell[i].MAC,file);具有未定义的行为,因为file是空指针。

当您添加 extra fgets()时,会读取并忽略换行符,下一次迭代将读取以下行。

您应该通过增加缓冲区大小并测试fgets()strtok()的返回值来修复代码,以避免未定义的行为。您还应该将\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()在解析输入时有一个缺点:它将任何分隔符序列视为单个分隔符。因此,它无法处理,31A0E321456CCTRL-000,

等空字段

答案 1 :(得分:1)

使用

fgets (buff, 22, dat);

你读完全该行上的字符数 除了一个 换行符结束时这条线。

如果您只读取22个字符,则fgets将不会读取换行符,而是将其留给第二个fgets读取(作为空“行”)。

buff的大小增加一(到23)并使用sizeof buff作为大小。然后fgets将读取包含文件换行符在内的所有行。 (并希望文件的格式不会随着更长的行而改变。)

此行为已有详细记录。从例如this fgets reference

  

从给定的文件流中读取最多count - 1个字符...