【问题标题】:C fgets semantic errorC fgets 语义错误
【发布时间】:2015-10-16 18:53:40
【问题描述】:

我是 C 世界的新手,我对 fgets() 函数有疑问。 我用谷歌搜索了将近 2 个小时的错误,找到了不同的解决方案,但没有一个有效。

我的班级太大了,不能只展示它的每个部分,但让我向你展示有问题的部分:

//... kivansag is a struct(!)
if(check == 1){
        char name;
        printf("Please give me your nickname!\n");
        scanf("%s", &name);
        strcpy(kivansag.name,&name);

        char city;
        printf("Please give me your city!\n");
        scanf("%s", &city);
        strcpy(kivansag.city,&city);

        char *address = malloc(100);
        printf("Please give me your address!\n");           
        fgets(address,100,stdin);

        if((strlen(address)>0) && address[strlen(address)-1] == '\n'){
            address[strlen(address)-1] = '\0';
        }

        strcpy(kivansag.address,address);
        free(address);
}//...

问题是:每次我运行这段代码时,运行的服务器在写出“给我你的地址”后会跳过fgets(),并执行以下功能。

我可以得到任何建议吗?

更新:

现在我只有这个:

        printf("Please give me your address!\n");           
        fgets(kivansag.address,sizeof(kivansag.address),stdin);

        if((strlen(kivansag.address)>0) && kivansag.address[strlen(kivansag.address)-1] == '\n'){
            kivansag.address[strlen(kivansag.address)-1] = '\0';
        }

结构看起来像这样:

struct Kivansag{
  //...
  char address[100];
};

是的,仍然跳过我的部分...我也尝试使用fflush(stdin),以确保一切都清楚,但没有工作。

【问题讨论】:

  • char name; 是一个有足够空间容纳 一个 字符的变量。
  • 提示:什么样的字符不匹配scanf("%s")(留在输入流中),但导致fgets()立即返回?
  • 始终检查 (!=NULL) malloc() 的返回值以确保操作成功。
  • 函数 fflush() 仅用于输出流,不适用于标准输入。 C 标准明确指出 fflush(stdin) 是未定义的行为。
  • 这一行:scanf("%s", &city); 将失败,因为输入流中留下的换行符将阻止 scanf() 输入任何内容。建议阅读 scanf() 的手册页

标签: c whitespace scanf fgets


【解决方案1】:
 scanf("%s", &name);      //you cant use %s to take input in a char variable
 ...
 scanf("%s", &city);

在这些namecity 中是两个字符变量,而不是null terminated 字符串。因此,在这里使用 -

strcpy(kivansag.name,&name);

导致UB

您可以将它们声明为数组 -

char name[20];
char city[20];
fgets(name,20,stdin);    
...
fgets(city,20,stdin); 
strcpy(kivansag.name,name);      // note address of name is not required 
/* similarly for copying city */

所以由于这个原因,下一个fgets 也不会被跳过。

然后照你的做。

【讨论】:

  • 我试过了,没用。对于最后一种情况,我注释了姓名和城市输入,现在我只有地址部分.. 仍在跳过。
【解决方案2】:

char 只是一个字符,你不能用它来读取scanf 中的%s 格式的字符串。您需要提供一个字符数组。无需扫描到一个变量然后复制到另一个变量,您可以直接扫描到结构成员。

scanf("%s", kivansag.name);

你也可以直接在变量中使用fgets()

fgets(kivansag.address, sizeof kivansag.address, stdin);
size_t len = strlen(kivansag.address);
if((len>0) && kivansag.address[len-1] == '\n'){
    kivansag.address[len-1] = '\0';
}

请参阅fgets doesn't work after scanf,了解您的程序跳过fgets 的原因以及如何解决它。

【讨论】:

  • 我可以用它来读取字符串:)。但是你的报告是公平的。但代码工作正常,除了“地址”部分。
  • 您也可以使用fgets 直接读入结构。我已经更新了答案以显示这一点。
  • 谢谢,真的比我的好,我用过……还是有问题,我更新了帖子。
【解决方案3】:

这两行总是会产生未定义的行为。

未定义的行为可能导致任何事情,包括段错误事件

    char name;
    ....
    scanf("%s", &name);

函数 scanf() 总是将一个 NUL 字节附加到输入的字符串。

char name 中只定义了一个字节。

“%s”没有限制,因此用户可以/将始终超出该一个字节缓冲区。

建议类似:

    char name[30];
    ....
    if( 1 != scanf("%29s", &name) { // handle error }

这一行:

scanf("%s", &city);

在输入流中留下一个换行符。

以下对 fgets() 的调用将看到该换行符,并立即返回,输入缓冲区中除了换行符和 NUL 字节之外什么都没有放入

这非常凌乱的线条:

if((strlen(address)>0) && address[strlen(address)-1] == '\n'){
        address[strlen(address)-1] = '\0';
    }

可能会或可能不会找到嵌入的换行符并用 NUL 字节覆盖它 建议:

if( char* newline = strstr( address, "\n" ) )
    *newline = '\0';

还有更“简洁”的方法来替换字符串中的换行符 但是这个方法很容易理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-19
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多