【问题标题】:What is the difference between scanf("%s", &str) and scanf("%s\n", &str)?scanf(\"%s\", &str) 和 scanf(\"%s\\n\", &str) 有什么区别?
【发布时间】:2022-12-10 03:00:28
【问题描述】:

输入

输入中将有几行以包含单个* 的行结尾。这最后一行 不应该被处理。每行将包含 HajjUmrah

输出

对于输入的每一行,在单独的行中输出 Hajj-e-AkbarHajj-e-Asghar 报价单。有关确切格式,请参阅示例。

这是我解决这个问题的代码。

#include <stdio.h>

int main()
{
    char str[100];
    int i = 1;

    while (scanf("%s", &str))
    {
        if (str[0] == '*')
            break;
        else if (str[0] == 'H')
            printf("Case %d: Hajj-e-Akbar\n", i);
        else
            printf("Case %d: Hajj-e-Asghar\n", i);
        i++;
    }
}

对于输入

Hajj
Umrah
*

当我一次给出这个输入时,程序通过打印提供预期的输出

Hajj
Case 1: Hajj-e-Akbar
Umrah
Case 2: Hajj-e-Asghar
*

但是在获得*作为输入后,程序正在等待Enter。点击Enter 后,程序终止。但我希望我的程序在输入* 时终止,而不是按Enter。请在这里帮助我。但这不是我的问题。我的问题是针对相同的输入-

Hajj
Umrah
*

当我通过scanf("%s\n", &amp;str) 接受输入时。该程序在第一个输入Hajj 后不打印输出Case 1: Hajj-e-Akbar,但它在接受第二个输入Umrah 后打印第一个输入的输出。然后程序等待输入*Enter。 输出是这样的

Hajj
Umrah
Case 1: Hajj-e-Akbar
*

然后我按Enter,它为第二个输入Umrah打印输出Case 2: Hajj-e-Asghar 然后等待另一个输入。按Enter 后的输出看起来像这样。

Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Case 2: Hajj-e-Asghar

我不明白 \nscanf 有何影响。

谢谢你。

如果我不能正确解释我的问题,我很抱歉。我是编程新手。

【问题讨论】:

  • 您不应在数组上使用 &amp; 运算符。它们已经衰减为指针。您不会注意到,因为值是相同的,但您实际上提供了不正确的类型。

标签: c scanf


【解决方案1】:

scanf 读取格式化输入,因此当您使用 %s ”, &str 时,字符串将被消耗并存储在 str 中,换行符也是如此,当您按回车键时,它将出现在缓冲区中,字符串将被存储,换行符字符将被丢弃。

注意正确的用法是“%s ”, strstr已经是一个指针,你不应该使用&amp;

当你使用“%s”, &amp;str时,换行符将留在缓冲区中并在下一次循环中被消耗,因此str将在第一次迭代中存储,而" "将在下一次迭代中存储在str中迭代,然后才会在第三次迭代中再次要求您输入。

对于完成,如以下 cmets 中所述,根据 scanf 的定义:

...格式字符串中的任何单个空白字符都会消耗输入中所有可用的连续空白字符(就像通过在循环中调用isspace 一样确定)。请注意,“之间没有区别 "、" "、" " 或格式字符串中的其他空格。

我还建议您限制scanf 期望的字符串的大小,以避免容器溢出,例如%99s,就像您拥有的 100 个字符的容器,并检查scanf 返回,在这种情况下,它必须每个周期都是= 1

要做你想做的事,我收集到的是从stdin获取一个字符而不按回车键,你将需要一个 SO 特定的方法,这里是 Windows 使用&lt;conio.h&gt;库和getch()的一个小例子:

#include <stdio.h>
#include <conio.h>

int main()
{
    int i = 1, c;

    while (1)
    {
        if ((c = getch()) == '*')
            return 0;
        else if (c == 'H')
            printf("Case %d: Hajj-e-Akbar
", i);
        else
            printf("Case %d: Hajj-e-Asghar
", i);
        i++;
    }
}

对于 Linux,一种选择是也使用 &lt;ncurses.h&gt; 库中的 getch(),你是 might need to install

PS:别担心,你的问题很好,特别是在网站上只排在第二位。

【讨论】:

  • 实际上,我不知道指针。这就是我使用&amp; 的原因。当我使用scanf("%s", str) 并一次输入以下内容时,可能会发生这种情况。 Hajj Umrah *首先,它接受字符串Hajj,并显示它的输出。然后它接受第二个输入Umrah并显示它的输出。这两个输出显示时没有击中任何Enter,因为它在每个输入后都有两个新行。但是当程序获得*作为输入时,它不会在没有命中Enter的情况下执行。这就是为什么我必须在最后输入时点击Enter。我的解释正确吗?
  • @EhsanulKarimPappu 做你想做的事没有可移植的解决方案,如果你使用的是 Windows,你可以尝试 getch()&lt;conio.h&gt; 库,或者对于 linux,&lt;ncurses.h&gt; 库从 stdin 读取而不输入。您描述的行为可能是由于 UB 给出了错误的类型分配。
  • @EhsanulKarimPappu,我编辑了答案,为您提供一些我认为可能满足您需要的选项。
【解决方案2】:

scanf 中的尾随 是个坏主意:格式字符串中的任何空白字符都会导致从输入流中丢弃任何空白字符序列。如果从文件读取,你不一定会有问题,但如果你从终端读取,scanf() 将在你键入下一个项目之前不会返回,这会在你体验时造成很大的混乱,因为程序的输出将对应于上一项,而不是刚刚键入的项目...切勿在 scanf() 格式字符串中添加尾随空格或换行符。

您应该测试 scanf() 是否返回 1 以避免在文件末尾返回 EOF 时出现无限循环。

另请注意,传递 &amp;str 是不正确的:str 是一个数组,将其传递为 str 将有效地传递指向其第一个元素的指针,这是正确的。

此外,您应该告诉scanf()可以存储到目标数组中的最大字符数,以避免在超长输入时出现未定义的行为。由于数组的大小定义为100,因此格式字符串应为"%99s",以便为空终止符留出空间。

最后,你需要打进入在最后的 * 之后,出于 3 个综合原因,每个原因都会强制执行此行为:

  • 默认情况下,终端设备驱动程序是行缓冲的,因此在您键入之前,程序无法使用输入进入.
  • 标准输入流(stdin)默认是行缓冲的,所以它会从系统句柄中读取数据,直到它得到一个换行符,然后scanf()才有机会看到换行符的第一个字符输入行。
  • scanf("%s", str) 将保留其输入流,直到它到达单词结尾、空白字符或文件结尾,因此当您仅键入 * 时它不会返回。

这是修改后的版本:

#include <stdio.h>

int main() {
    char str[100];
    int i = 1;

    while (scanf("%99s", str) == 1 && str[0] != '*') {
        if (str[0] == 'H') {
            printf("Case %d: Hajj-e-Akbar
", i);
        } else {
            printf("Case %d: Hajj-e-Asghar
", i);
        }
        i++;
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-14
    • 2016-12-05
    • 2011-01-10
    • 2021-04-02
    • 1970-01-01
    • 2017-06-22
    • 2016-07-20
    相关资源
    最近更新 更多