【问题标题】:How exactly does space work with scanf?空间如何与 scanf 一起工作?
【发布时间】:2012-02-15 22:40:33
【问题描述】:

我是一名数学专业的学生,​​我正在学习 C 编程的基础知识。我需要一个程序来读取包含在数组中的输入,其中的组件必须具有某些必要条件;我希望程序向用户询问数组的组件。然后,用户必须输入这些组件,并用空格分隔它们。细节对于解决主要问题并不重要;我将选择一个比我正在处理的更简单的示例:假设我想要一个包含 6 个组件的数组不包含数字 4。所以我尝试了:

#include <stdio.h>

int main(void) {
    int a[6];
    printf("enter components: ");
    int i;
    for (i = 0; i < 6; i++) {
        scanf("%d", &a[i]);
        if (a[i] == 4) printf(" \n\n4 is not allowed, try again\n\n");
    }
    for (i = 0; i < 6; i++) {
        printf("%d ", a[i]);
    }
}

如果我编译并运行它,例如输入:

1 2 3 4 5 6

我会收到我的错误消息,但只有在按下回车之后,即在输入所有六个组件之后(不是在第四次按下空格之后)。所以这是我的问题(我正在寻找不使用字符串或指针的解决方案,除非没有它们是不可能的):

  1. 有没有办法让程序在输入后续空格后立即读取组件(并采取相应的行动)?我猜不是因为 scanf 只有在用户按下回车后才起作用,而不是空格,对吗?

  2. 如果没有,有没有办法让程序在最后按下回车后立即读取所有组件,但让用户从最后一个正确的组件中提取?例如,通过上述输入,我希望程序显示如下内容:

    4 is not allowed
    1 2 3 _
    

    以便用户可以更正他/她的输入(也可能更改前三位)。

对不起,如果这个问题太愚蠢了!谢谢你的帮助!!


编辑:嗯,谢谢你的好答案,你们都非常有帮助!可惜我只能接受一个。

【问题讨论】:

  • 抱歉,错误处理和检查输入是否有错误是不同的事情。已编辑。如果你不反对的话。
  • C 标准库中没有任何东西支持这一点;您将需要使用或多或少特定于平台的库,例如ncurses。你的目标是什么平台?
  • @Gangnus 没问题,感谢您的编辑。
  • @ruakh 我在 Windows 中使用代码块;我只用过标准库和数学库,其他的不知道。

标签: c arrays scanf space


【解决方案1】:

在for循环中,每次迭代后,计数器自动加一。如果你得到一个无效的输入,你应该防止计数器增加。为此,只需在您提供无效输入时将i--; 添加到您的代码中。

#include <stdio.h>

int main(void) {
    int a[6];
    printf("enter components: ");
    int i;
    for (i = 0; i < 6; i++) {
        scanf("%d", &a[i]);
        if (a[i] == 4){
           printf(" \n\n4 is not allowed, try again\n\n");
           i--;
        }
    }
    for (i = 0; i < 6; i++) {
        printf("%d ", a[i]);
    }
}

【讨论】:

  • Mir,这种方法会让他陷入无限循环……因为 a[i] 将一直为 4!
  • 感谢您的回答。这不会用后面的组件覆盖错误的组件吗?我尝试运行它,但没有得到改进。
  • 为什么?在循环的开头有一个scanf。 @mir-milad-hosseiny,您的代码是正确的,但您没有回答问题。埃米利奥,你是对的。这是对代码中另一个问题的更正。
【解决方案2】:

这与您的终端处于“熟”模式有关。在用户按下回车键之前,字符甚至不会发送到程序。

【讨论】:

  • 好的,谢谢,这就是我的想象。不过,选项 2. 仍然是可能的,不是吗?
  • 在熟模式下,用户无法编辑您打印的内容。如果您关闭熟食模式,一切皆有可能。例如,看看libreadline
  • 谢谢,我会调查的,但我怀疑我能否将其用于我的评估。最后一件事:我可以让程序在输入每个组件后立即检查它(如果用户在输入每个组件后按 Enter 键),但是如果用户输入用空格分隔的组件并在最后按 Enter 键,则没有办法(仅使用 stdio.h)让用户从第一个错误的开始重新输入它们。对吗?
  • @Emilio:好吧,如果您计算正确的数量,您可以让他们从那里重新输入。让他们编辑以前接受的更困难。
【解决方案3】:

改进 Mir Milad Hosseiny 的答案(我错误地将其识别为失控的无限循环……实际上正是我在评论中描述的无限循环)……

我会编写一个小函数,其中包含“白名单”(您想要的东西)或“黑名单”您不想要的东西,并检查每个值是否属于(取决于方法)到列表中。这样,您可以保留一个单独的位置来存储您愿意接受或不接受的值,因此您的主要功能不会因为“if”中的异常或包含而变得非常混乱

所以你的代码是

if(isAllowed(a[i]){
   myList[j] = a[i]; //j is your alternate counter
}

【讨论】:

  • 谢谢,这是有道理的。有没有办法让程序打印 myList 以便用户修改它?
  • 好的,Ben Voigt 刚刚回答了这个问题。
  • 对,我的意思是,大概您想实际使用这 6 个数字来做某事(而不是仅仅将它们打印回来)。因此,您将在某处得到一个 userInput[6],它是存储数字的数组。因此,我的建议是将 scanf 置于无限循环中(不基于任何 int)并留在其中,直到获得 6 个有效值。仅当您具有有效值并在 userInput 数组中使用该索引时才增加有效值索引。
【解决方案4】:

你可以这样做:

int i,a[6];
for (int i=0;i<6;i++) {
 scan: scanf("%d",&a[i]);
}
for (int i=0;i<6;i++) if (a[i]==4) {
 printf("4 is not allowed. re-enter the last %d numbers\n",6-i);
 goto scan;
}

请注意,在大多数情况下,最好避免使用goto,但在这种情况下,我认为这是很自然的。

如果您确实需要,可以打印第一个 i 数字(在 goto 之前),但让用户更改这些数字很复杂(并且取决于平台)。

【讨论】:

  • 好的,这仍然需要用户手动重新输入最后的 6-i 组件。
  • 我以为这就是你想要的。如果不是,则将第二个循环的主体更改为:printf("4 is not allowed. re-enter the %dth number\n",i+1); scanf("%d",&amp;a[i]); i--;i-- 是重新检查a[i]
  • 是的,对不起,这就是我想要的。我的意思是用户必须输入第一个 i 组件,但第二次认为这不是必需的,因为它们已经存储在 a[i]s 中。谢谢,没有让程序打印第一个 i 组件的可能性,而用户可以编辑它们,这似乎是最好的解决方案!
【解决方案5】:

请看下面的代码:

#include <stdio.h>

int main(void) {
    int a[6];
    int i;
    bool hasError = false;
    int errorIndex = 0;
    do{
        hasError = false;
        printf("enter components: ");
        for (i = 0; i < errorIndex; i++)
            printf("%d ", a[i]);

        for (i = errorIndex; i < 6; i++) {
            scanf("%d", &a[i]);
            if (a[i] == 4 && hasError == false){
                printf(" \n\n4 is not allowed, try again\n\n");
                hasError = true;
                errorIndex = i;
            }
        }
    }while(hasError == true);
    for (i = 0; i < 6; i++) {
        printf("%d ", a[i]);
    }
}

【讨论】:

  • 第 6 行的 bool 是什么意思?我的编译器不理解这个(未声明),我也不理解(对不起,我是一个真正的初学者)
  • boot 是布尔类型。你应该包括&lt;stdbool.h&gt; 来使用它。 (或者您可以将bool 更改为int,将false 更改为0
  • 太好了,这完美!我想我将不得不更改接受的答案。
  • 谢谢,希望对你有用。
猜你喜欢
  • 2019-07-20
  • 2018-11-13
  • 2014-06-11
  • 2023-02-02
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多