【问题标题】:Reading file with fscanf in C在 C 中使用 fscanf 读取文件
【发布时间】:2025-12-04 01:45:02
【问题描述】:

我有 c 代码,它在 while 循环中读取文件,将所有信息 fscanf 到 url、num 和 rank 变量中,然后将其打印出来。但是,输出不正确。

主要问题:

  • 为什么浮点数只是零,如何解决这个问题?
  • 如何去掉url后面的逗号? Url 可以是任意长度(char url[10] 就是一个例子)。在每个逗号上先拆分行,然后使用 fscanf 将信息添加到变量中会更好吗?

我有一个包含以下信息的文件:

url31, 3, 0.2623546
url21, 1, 0.1843112
url34, 6, 0.1576851
url22, 4, 0.1520093
url32, 6, 0.0925755
url23, 4, 0.0776758
url11, 3, 0.0733884 

这是我得到的:

Link: url21,; Number: 1; Rank: 0.000000
Link: url34,; Number: 6; Rank: 0.000000
Link: url22,; Number: 4; Rank: 0.000000
Link: url32,; Number: 6; Rank: 0.000000
Link: url23,; Number: 4; Rank: 0.000000
Link: url11,; Number: 3; Rank: 0.000000
Link: url11,; Number: 3; Rank: 0.000000

预期输出:

Link: url31; Number: 3; Rank: 0.2623546
Link: url21; Number: 1; Rank: 0.1843112
Link: url34; Number: 6; Rank: 0.1576851
Link: url22; Number: 4; Rank: 0.1520093
Link: url32; Number: 6; Rank: 0.0925755
Link: url23; Number: 4; Rank: 0.0776758
Link: url11; Number: 3; Rank: 0.0733884

我的代码:

#define MAXSTR 1000

int main () {

    FILE *file;

    char url[10];
    int num;
    float rank;

    if ((file = fopen("pages.txt", "r")) == NULL) {
        printf("Error.\n");
        return -1;
    }

    while(fgets(lines, MAXSTR, file) != NULL) {

        fscanf(file, "%s %d %f", &url[0], &num, &rank);
        printf("Link: %s; Number: %d; Rank: %f\n", url, num, rank); 

    }
    return 0;
}    

【问题讨论】:

  • fscanf 格式字符串不会自动将逗号识别为字段分隔符。具体来说,例如,%s 将扫描后跟空格的字符串,该字符串会将url31, 作为第一个字符串读取(请记住,逗号只是fscanf 的另一个非空白字符)。该数字看起来被正确读取,但顺序错误。您确定您显示的是您阅读的文件中行的顺序吗? %d 在逗号处结束扫描,然后扫描尝试将逗号读取为浮点数,这将为您提供 0。
  • 这些是分号,不是逗号,但这就是问题所在——也许把它写成答案?
  • @lurker 是的,我明白为什么它将逗号读入 %s,有什么办法可以解决这个问题吗?我照原样复制文件,所以一切都应该按正确的顺序排列 - url (str)、number (int)、rank (float)。
  • @CarlNorum 分号在格式化的 printf 中,我选择添加它们,因此它将逗号读入字符串可以更加明显。
  • @CarlNorum 原来是逗号,阅读文本文件。

标签: c


【解决方案1】:

如果您已经在使用fscanf(继续扫描直到找到EOF),那么您不需要在while 循环中使用fgets。此外,您需要将, 正确定义为分隔符,否则第一个%s 也会将逗号读入字符串。这个while 循环有效:

while(fscanf(file, "%10[^,], %d, %f\n", url, &num, &rank) != EOF) {
    printf("Link: %s; Number: %d; Rank: %f\n", url, num, rank); 
}

我将分隔符定义为逗号,因此第一个字符串应该读取字符,直到通过%10[^,] 遇到逗号(读取最多 10 个字符,如格式说明符中所述),然后是逗号、整数、逗号,浮动,然后是换行符 (\n)。

输出:

Link: url31; Number: 3; Rank: 0.262355
Link: url21; Number: 1; Rank: 0.184311
Link: url34; Number: 6; Rank: 0.157685
Link: url22; Number: 4; Rank: 0.152009
Link: url32; Number: 6; Rank: 0.092575
Link: url23; Number: 4; Rank: 0.077676
Link: url11; Number: 3; Rank: 0.073388

【讨论】:

  • 如果/当链接字段超过 url 的长度时,您的代码将表现出缓冲区溢出行为。
  • 你的意思是说OP的代码,我建议使用动态分配的char *。正如他们在问题中所说的那样,OP 刚刚提到了大小作为示例,所以我认为他们对大小限制持谨慎态度。
  • 不,我的意思是 url 缓冲区的长度有限,而您没有通知 fscanf 这一事实。
  • 我明白你的意思,补充说。谢谢。
  • == 3 在这里比!= EOF 更有意义。 %10[^,]%9[^,] 更好。 10 是错误的宽度。建议" %9[^,] ,%d ,%f"`.
【解决方案2】:

我做了一些更改,因为您的代码中的行给了我错误(可能来自编译器或 IDE,不确定)。之所以这样工作,是因为逗号不被视为空格字符。

% 5 [^,] 表示阅读,直到遇到最多五个字符或逗号。

  • 例如,因为url31 有 5 个字符,所以我给出了这个,所以你可以为不同的操作给出不同的数字。

    #include

    int main () {

      FILE *fp;
    
      char url[10];
    
      int num;
    
      float rank;
    
      fp = fopen("pages.txt" , "r");
      if(fp == NULL) {
          perror("Error opening file");
          return(-1);
      }
          while(fscanf(fp, "%5[^,], %d, %f\n", url, &num, &rank) != EOF) {
          printf("Link: %s; Number: %d; Rank: %f\n", url, num, rank);
      }
      fclose(fp);
    
      return(0);
    

    }

【讨论】: