【问题标题】:scanf not printing or reading anything [duplicate]scanf不打印或读取任何内容[重复]
【发布时间】:2013-06-19 03:50:23
【问题描述】:

我的代码中有以下行:

char y[] = "a";
scanf("Letter: %s", y);
printf("%s\n", y);

第二行完全不影响第三行的输出。我已经加了<stdio.h>,我想不出有什么问题……

【问题讨论】:

  • 您通常会期望scanf 打印一些东西吗?
  • 当然,但是你不会在不知道它的作用的情况下使用函数,对吧?
  • 由于您不测试来自scanf() 的返回值,因此您不知道它是否成功。如果它没有成功,你在y 中没有任何可靠的东西。您还只为单个字符串分配了足够的空间。只要这是您想要的,就可以了,但建议您使用 %1s 指定最大长度,尤其是当长度仅为 1 时。
  • 检查我的答案,你会得到你想要的......

标签: c


【解决方案1】:

最大的错误之一是在scanf 函数中的引号之间包含除格式规范(如%s%d)之外的任何字符串。代码应该成为scanf("%s",y)。如果您选择其他角色,那么您将不得不挠头寻找问题。

(即使您包含任何字符,您也必须输入该字符,例如,如果您写 scanf("letter: %s",y);,那么在输入时您必须像 C:\>letter: 这样写 “您将输入的字母”) 这显然不是一个明智的主意。另外,scanf 函数不能打印出来,它只是从终端读取输入。要打印出来,你应该使用 printf("letter"); 就是这样。

假设您必须使用一个 scanf() 从两个 int 变量中获取输入,那么您将使用 scanf("%d%d",&a,&b);,正如您所见,除了引号中的格式规范外,我什么也没放。

【讨论】:

  • scanf() 格式字符串中包含空格或其他字符不一定是错误的。有时这是必要的。总是有必要了解它的含义,尤其是空格(尤其是尾随空格)的作用并不明显。但是说您不应该在格式字符串中包含除转换规范之外的任何其他字符是不正确的。在"%d%d" 的情况下,格式字符串中不需要空格,但" %d %d" 中的一个或两个空格都没有害处,尽管尾随空格几乎总是不合适的。
  • @jonathan 是的,它不一定是一个错误,但你确定它在所有情况下都有效,我的意思是在所有机器上。输入(在提示上)应该与 scanf() 内部相同并且在空格的情况下它并不重要。显然在 scanf() 中包含任何内容然后在输入提示上相应地写入它不是一个明智的主意。无论如何我已经考虑了您的意见并包含在答案中。谢谢!!
  • 并理解它意味着什么意味着可以在 printf() 中添加行,它绝对可以让您避免像在 scanf() 中添加行之后那样输入,我的意思不是“从不” “正如您所解释的那样。我的意思是,它是“错误”而不是“错误”。
  • scanf() 系列函数是标准 C 中最复杂的函数;它们非常难以理解。很难教正确使用这些功能。您会在 SO 中找到我的记录,指出通常使用 fgets()sscanf() 而不是普通的 scanf() 更好;它通常可以提供更好的控制,尤其是重试和错误报告。 scanf() 没有发出提示是正确的,这显然是 OP 认为会发生的情况。
  • 只要他们在输入的任何内容之前加上“字母:”就可以了,但可能不是预期的效果
【解决方案2】:

我假设你想要一个提示,而不是格式字符串:

printf("Letter: ");
fflush(stdout);
scanf("%s", y);

请注意,您的字符串只能包含一个字符。如果输入较长的字符串,则会出现缓冲区溢出。

您还应该养成测试scanf 的返回值的习惯。它返回成功读取的项目数。因此,在您的示例中,如果它读取一个字符串,它应该返回1。因为您没有对其进行测试,所以您花了很长时间试图找出问题所在,而实际上它会告诉您没有读取任何项目。

【讨论】:

  • 是因为我没有做fflush吗?
  • 不,这是因为 scanf 正在寻找一个看起来像 Letter: 的输入,然后是更多字符,然后它将放入您的数组 y
  • 顺便说一句,您应该阅读以下内容:stackoverflow.com/questions/4023895/…
【解决方案3】:

其他答案已经正确诊断出scanf()不输出任何数据(特别是不生成任何提示),而问题似乎预计scanf("Letter: %s", y)会输出提示Letter:然后阅读一个答复。还有一些问题,比如不检查来自scanf()的返回值,如果输入多个字符会导致缓冲区溢出。

其中一个答案建议格式字符串中不应出现转换规范以外的字符。这个答案主要是一个反例,展示了其他角色如何至关重要。您可以获取此示例代码并对其进行修改,以提高您对scanf() 系列函数工作原理的理解。请注意,它不是交互式程序;它使用sscanf() 转换数据,就好像数据已被fgets() 读取一样。 练习:为什么只是“几乎好像”而不是简单的“好像”?

上下文

假设您正在处理的文件格式如下:

centre (23, 41) size (19, 42)

假设您要读取这四个数字,您的格式字符串很可能是:

"centre (%d,%d) size (%d,%d)"

这几乎是正确的。但是,该格式无法发现缺少第二个右括号。为了确保最后的括号存在,您需要一个格式字符串,如:

"centre (%d ,%d ) size (%d ,%d %1[)]"

其中的空格允许输入间距的多种变化,而扫描集 (%1[)]) 需要一个右括号。您将测试 scanf() 返回 5 个字段。请注意,如果您使用扫描集 (%*1[)]) 禁止分配,则如果缺少括号,您将不会收到错误指示。这是一个判断要求,您希望在接受有效输入时有多灵活。

代码

#include <stdio.h>

int main(void)
{
    int x1, y1, x2, y2;
    char str[10];
    const char *data[] =
    {
        "centre ( 19, 43 ) size ( 21, 37 )",
        "centre (19, 43) size (21, 37)",
        "centre (19, 43) size (21, 37",
        "centre(19,43) size(21,37)",
        "centre(19,43) size(21,37",
        "centre ( 19 , 43 ) size ( 21 , 37 )",
    };
    enum { NUM_DATA = sizeof(data) / sizeof(data[0]) };

    const char *format5[] =
    {
        "centre (%d ,%d ) size (%d ,%d %[)]",
        "centre (%d,%d) size (%d,%d%[)]",
    };
    enum { NUM_FORMAT5 = sizeof(format5) / sizeof(format5[0]) };

    const char *format4[] =
    {
        "centre (%d ,%d ) size (%d ,%d )",
        "centre (%d,%d) size (%d,%d)",
    };
    enum { NUM_FORMAT4 = sizeof(format4) / sizeof(format4[0]) };

    printf("Format 5\n");
    for (int i = 0; i < NUM_FORMAT5; i++)
    {
        printf("Format:    <<%s>>\n", format5[i]);
        for (int j = 0; j < NUM_DATA; j++)
        {
            int rc;
            printf("   Data:   <<%s>>\n", data[j]);
            if ((rc = sscanf(data[j], format5[i], &x1, &y1, &x2, &y2, str)) != 5)
                printf("!! Failed: scanf() returned %d\n", rc);
            else
                printf("== Passed: centre(%d,%d) size(%d,%d)\n", x1, y1, x2, y2);
        }
    }

    printf("\nFormat 4\n");
    for (int i = 0; i < NUM_FORMAT4; i++)
    {
        printf("Format:    <<%s>>\n", format4[i]);
        for (int j = 0; j < NUM_DATA; j++)
        {
            int rc;
            printf("   Data:   <<%s>>\n", data[j]);
            if ((rc = sscanf(data[j], format4[i], &x1, &y1, &x2, &y2)) != 4)
                printf("!! Failed: scanf() returned %d\n", rc);
            else
                printf("== Passed: centre(%d,%d) size(%d,%d)\n", x1, y1, x2, y2);
        }
    }

    return 0;
}

输出

Format 5
Format:    <<centre (%d ,%d ) size (%d ,%d %[)]>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
!! Failed: scanf() returned 4
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
!! Failed: scanf() returned 4
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
== Passed: centre(19,43) size(21,37)
Format:    <<centre (%d,%d) size (%d,%d%[)]>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
!! Failed: scanf() returned 2
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
!! Failed: scanf() returned 4
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
!! Failed: scanf() returned 4
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
!! Failed: scanf() returned 1

Format 4
Format:    <<centre (%d ,%d ) size (%d ,%d )>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
== Passed: centre(19,43) size(21,37)
Format:    <<centre (%d,%d) size (%d,%d)>>
   Data:   <<centre ( 19, 43 ) size ( 21, 37 )>>
!! Failed: scanf() returned 2
   Data:   <<centre (19, 43) size (21, 37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre (19, 43) size (21, 37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37)>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre(19,43) size(21,37>>
== Passed: centre(19,43) size(21,37)
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )>>
!! Failed: scanf() returned 1

请注意,当缺少第二个右括号时,“格式 4”下的格式字符串如何接受数据。即使缺少字符,也满足 4 个转换规范。 “格式 5”格式拒绝这些数据行。

示例代码和数据没有演示它,但代码也很乐意读取多个右括号(因为它使用%[)])。这可以通过使用%1[)] 来规定最后只有一个右括号来避免。您还可以使用%n 转换规范和第六个参数(另一个int *)来获取处理的字符数。这将允许您检测扫描停止的位置,从而在所需的输入之后是否有未处理的字符。请注意,%n 转换规范不计入来自scanf() 等的返回值中。这个片段可以粘贴在代码中main()函数的末尾:

printf("\nFormat 6\n");
int len, rc;
const char data6[] = "centre ( 19 , 43 ) size ( 21 , 37 )))";
const char format6[] = "centre (%d ,%d ) size (%d ,%d %1[)]%n";
printf("Format:    <<%s>>\n", format6);
printf("   Data:   <<%s>>\n", data[5]);
if (sscanf(data6, format6, &x1, &y1, &x2, &y2, str, &len) != 5)
    printf("!! Failed: scanf() returned %d\n", rc);
else
    printf("== Passed: centre(%d,%d) size(%d,%d) len=%d <<%s>>\n",
           x1, y1, x2, y2, len, &data6[len]);

它生成输出:

Format 6
Format:    <<centre (%d ,%d ) size (%d ,%d %1[)]%n>>
   Data:   <<centre ( 19 , 43 ) size ( 21 , 37 )))>>
== Passed: centre(19,43) size(21,37) len=35 <<))>>

总结

如果你理解了为什么会得到每一个结果,那么你对scanf()的理解就不错了。如果您不确定原因,请尝试并阅读规范(例如 POSIX sscanf()),直到您确定自己理解为止。

【讨论】:

    【解决方案4】:

    在你的情况下

    char y[] = "a";
    scanf("Letter: %s", y);
    printf("%s\n", y);
    

    你应该这样输入。

    字母:abcd

    它会正常工作

    例如,如果 scanf 是这样写的

    int y;
    scanf("y=%d", &y);
    

    那么你应该像这样给出输入

    y=10

    不是 10

    我想你得到了你想要的...... :) 现在享受

    【讨论】:

      猜你喜欢
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      • 2019-05-26
      • 2021-02-13
      • 1970-01-01
      • 2018-01-21
      • 2017-01-24
      • 1970-01-01
      相关资源
      最近更新 更多