【问题标题】:Is there difference between scanf("%c",&x) and x=getchar()?scanf("%c",&x) 和 x=getchar() 有区别吗?
【发布时间】:2019-03-25 15:12:16
【问题描述】:

我写这篇文章是为了尽可能多地理解我尝试计算的以下程序,因为我认为它在日常生活中有一些可能的应用。

程序是这样的(它是一个密码):

#include <stdio.h>

void cifrario(int k) {
    char b, d;
    scanf("%c", &d);
    d = getchar();
    putchar(d);
    scanf("%c", &b);
    b = getchar();
    while (b != d) {
        if (('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')) {
            b = b + k;
            printf("%c", b);
            scanf("%c", &b);
            b = getchar();
        } else 
            printf("%c", b);
    }
}

int main() {
    int h;
    scanf("%d", &h);
    cifrario(h);
    return 0;
}

如您所见,我正在尝试移动输入中给定的某个常量的字母表。

我不太了解和不太了解的事情是为什么程序在没有scanfgetchar 的情况下不能运行,并且两者在相同的值上都是必需的,让我们在这里说:

scanf("%c", &d);
d = getchar(); 

我认为这两者是完全等价的;事实上,我在网上搜索时发现了这个问题getchar

此函数将读取的字符作为unsigned char 强制转换为文件结尾或错误时的intEOF

这就是我所期望的scanf() 所做的。

我发现:

  • 如果我将所有字符都放在不带空格的位置,我会得到(我认为)双字母而不是两个字符的相同字符的移位。

  • while 中的 else 无法按预期工作,因为一旦我输入了与字母字符不同的字符并看到结果,输出就会在该字符的无限字符串中失败。

【问题讨论】:

  • scanf() 的新线管理很糟糕。只需停止使用scanf() 进行用户输入并切换到fgets()(可能后跟sscanf())。
  • '\n' 是一个字符。
  • getchar() 的返回类型为int,您使用char 类型变量来保存其返回值。
  • 是的,它们更有用。 fgets() 允许从错误的用户输入中恢复错误,并且可以自然地管理输入行(包括尾随的 '\n')。
  • @jacopoburelli 了解getchar()getchar() 返回类型是 int,因为它在失败时返回 EOF

标签: c function scanf getchar


【解决方案1】:

是的,有一些区别。

主要是读取字符失败时的行为。 (通常这可能是由于输入流被关闭,但也有其他原因导致读取失败。

scanf 函数通过其返回值指示失败。如果您不检查返回值(因为您没有在代码中检查),那么您将无法知道读取是否失败。在这种失败情况下,d 可能会保留其旧值,尽管我不确定标准是否保证这一点。

getchar() 通过返回 EOF 表示失败,这是一个负整数值(通常是 -1,但不保证是)。在您的代码中,您编写了d=getchar(),这意味着您无法将此结果与对具有与EOF 相同字符代码的字符的有效读取区分开来。 (常见系统的字符范围为-128127)。 d 永远不会为此代码保留其先前的值。

为了正确处理错误,您可以使用scanf 并测试返回值为1;或将getchar() 的结果存储在int 中并检查该值不是EOF,然后再将其分配给char


成功案例也存在理论上的差异。这与现代系统无关。 scanf 版本会将成功字符存储在d 中。但是,getchar() 版本返回一个非负整数,即转换为unsigned char 的字符。然后代码d=getchar() 涉及将此值转换为char。如果char 被签名,这将调用实现定义的行为,它可能会导致与您从scanf 获得的字符代码不同。我不知道曾经存在的任何系统实际上会有所不同。


两个版本都从流中读取下一个可用字符。在您问题的底部,您描述了一些其他行为,但我认为您将scanf"%d" 的行为与"%c" 的行为混淆了。

在您的程序中,如果您从未遇到与 d 相同的另一个字符,while (b != d) 将永远不会终止,您需要解决此问题并确保它在读取失败时终止。

【讨论】:

  • 这可能是由于输入流被关闭而发生的:并非如此。如果流已关闭,则调用 getchar()scanf() 具有未定义的行为。您可能是指输入流是否位于文件末尾。
  • 我不确定标准是否保证这一点。标准提到存储转换后的值仅用于成功的转换,因此如果转换失败,目标变量应该保持不变.
  • @chqrlie 在实践中我不会依赖于没有存储,多年来有很多错误的 stdio 实现。 “流被关闭”是指由操作系统或其他任何东西关闭,以响应输入耗尽等条件。我猜你说的是用户调用fclose
  • 表达式输入流被关闭有点模棱两可:C确实将FILE *对象称为流指针,它们被@关闭987654354@... 您指的是可以通过外部方式关闭的管道和终端连接的系统句柄。这些通常不称为。关于实现的怪癖和缺点,我相信您的防御方法植根于经验。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
  • 2013-09-18
相关资源
最近更新 更多