【问题标题】:compare string acquired with fgets and fscanf比较使用 fgets 和 fscanf 获取的字符串
【发布时间】:2012-09-05 19:02:49
【问题描述】:

我需要将 fgets 从标准输入获取的字符串与 fscanf 从文件获取的另一个字符串进行比较(并使用 fprintf 写入文件)。我必须使用这两个函数来读取标准输入和文件。 我怎么能这样做? 因为我看到 fgets 也存储“\0”字节,但 fscanf 没有。

这是代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct asd {
    char a[20];
    char b[20];
} struttura;


void stampa_file() {
struttura *tmp = NULL;
struttura *letto = NULL;
FILE *file;

tmp = (struttura *)malloc(sizeof(struttura));
letto = (struttura *)malloc(sizeof(struttura));
file = fopen("nuovoFile", "r");
printf("compare:\n");\
fgets(letto->a, sizeof(letto->a), stdin);
fgets(letto->b, sizeof(letto->b), stdin);
while(!feof(file)) {
    fscanf(file, "%s %s\n", tmp->a, tmp->b);
    printf("a: %s, b: %s\n", tmp->a, tmp->b);
    if(strcmp(letto->a, tmp->a) == 0 && strcmp(letto->b, tmp->b)) {
        printf("find matching\n");
    }
}
free(tmp);
free(letto);
}

int main() {
struttura *s = NULL;
FILE *file;

s = (struttura *)malloc(sizeof(struttura));

file = fopen("nuovoFile", "a+");
printf("");
fgets(s->a, sizeof(s->a), stdin);
printf("");
fgets(s->b, sizeof(s->b), stdin);
fprintf(file, "%s%s\n", s->a, s->b);
fclose(file);
stampa_file();

free(s);
return 0;
}

【问题讨论】:

    标签: c string unix fgets scanf


    【解决方案1】:

    这里有很多潜在问题,具体取决于您要执行的操作

    • fgets 读取一行(直到并包括换行符),而fscanf(.."%s"..) 读取由空格分隔的标记。完全不是一回事。

    • fscanf(.."%s"..) 不会检查您给它写入的缓冲区的边界。您确实希望fscanf(.."%19s"..) 确保它不会将超过 20 个字节(包括 NUL 终止符)写入您的 20 字节缓冲区。

    • while(!feof(fp)) 几乎总是错误的。 feof 不会告诉您是否在文件末尾,它会告诉您是否尝试读取文件末尾。因此,如果您刚刚读取到文件末尾并且还没有读取过去,feof 将返回 false,但下一次读取将失败。

    • 您确实想检查fscanf 的返回值,以确保它读取了您希望它读取的内容(并且实际上将某些内容写入了输出缓冲区。)结合上述内容,这意味着您可能希望循环是这样的:

      while (fscanf(fp, "%19s%19s", tmp->a, tmp->b) == 2) {
              :
      

    【讨论】:

      【解决方案2】:

      我该怎么做?因为我看到 fgets 也存储“\0”字节,但 fscanf 没有。

      我只是阅读了 fscanf 的文档并对其进行了测试,结果很好:

      #include <stdio.h>
      
      int main()
      {
          char str[100] = { 1 }; // intentionally initialized to nonzero junk
          fscanf(stdin, "%s", str);
          if (strcmp(str, "H2CO3") == 0)
              printf("This is me\n");
          else
              printf("This is not me\n");
          return 0;
      }
      

      【讨论】:

      • 所以如果fscanf 失败,你会将垃圾传递给strcmp
      • @cnicutar 不,这不是目标。如果fscanf() 没有 NUL 终止字符串,那么我传递垃圾。
      • 我指的是初始化。如果 fscanf 失败,它将保持 str 不变。并且str 不是 0 终止的。
      • @cnicutar 完全正确!然而,这不是重点——我不倾向于在快速示例代码中进行错误检查。这只是示例代码中的污染。
      • @H2CO3: 然而 giozh 的问题(以及许多类似的 newby 问题)的整个问题可以总结为“缺乏适当的错误检查导致代码在某些情况下无法正常工作,或者无法正常工作正确终止'。因此,在示例代码中省略错误检查只会使其具有误导性和不正确性。
      【解决方案3】:

      scanf 或 fscanf 与 %s 一起传递时会在换行符或空格字符上终止字符串。 fgets 在哪里等到 \n。

      所以如果你打电话

      fscanf(stdin, "%s", str);
      
      vs
      
      fgets(str);
      

      并且文件包含“Hello there”

      fscanf 只会包含“Hello”,因为 fgets 会返回整个字符串

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-15
        • 2014-04-15
        • 2021-11-09
        • 2018-03-21
        • 2022-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多