如何将scanf中用空格输入的3个字符放入字符数组中?

如何将scanf中用空格输入的3个字符放入字符数组中?,c,scanf,C,Scanf,我以前是一名java程序员,但现在正在大学计算机科学专业学习C课程 我需要用户能够输入3个字符,前2个是数字,最后1个是“v”或“h”。 例如12伏 我需要用户能够在每个字符之间输入空格 这是我当前的代码: } 但是,如果我运行它,当我输入字符时,它可以正常工作,但如果我输入12v,它将打印出1,调用printBox,然后打印出2,然后再次打印出box,依此类推 如果有人能解释我在这里做错了什么,我将不胜感激。由于潜在的缓冲区溢出,通过scanf读取字符串通常是个坏主意。在中考虑使用FSCANF

我以前是一名java程序员,但现在正在大学计算机科学专业学习C课程


我需要用户能够输入3个字符,前2个是数字,最后1个是“v”或“h”。 例如12伏

我需要用户能够在每个字符之间输入空格

这是我当前的代码:

}

但是,如果我运行它,当我输入字符时,它可以正常工作,但如果我输入12v,它将打印出1,调用printBox,然后打印出2,然后再次打印出box,依此类推


如果有人能解释我在这里做错了什么,我将不胜感激。

由于潜在的缓冲区溢出,通过scanf读取字符串通常是个坏主意。在

中考虑使用FSCANF或更好的FFET 请注意“\0”的额外字节

此外,您还在这里将字符与字符串进行比较:input[i]!=\N它应该是输入[i]!='\而不是

顺便说一句,你可以用

int x, y;
char d;
scanf("%d%d%c", &x, &y, &d);
%s使用scanf读取以空格分隔的字符串,因此如果这不是您想要的,那么就不能使用它。%c读取单个字符,但不跳过空格,因此您可能还希望在格式中使用空格来跳过空格:

char input[3];

scanf(" %c %c %c", intput, input+1, input+2);

将读取3个非空白字符,并跳过它们之前或之间的任何空白。您还应该检查scanf的返回值,以确保它是3-如果不是,则在到达文件结尾之前,输入中的字符数少于3个。

这看起来像两个简单的错误

移动[]和输入[]需要使用单独的索引

    int i = 0;
    while(input[i] != 0){

            if(input[i] != ' ' && input[i] != "\n"){
                    move[i] = input[i];
            }
            i++;
    }
想象输入为12伏

输入[0]!=0,所以我们进入循环

它也不是“”或“\n”,因此我们将输入[0]复制到移动[0]

到目前为止还不错

您增加i,并发现输入[1]=''

但是你又一次增加了我

您发现您对输入[2]2感兴趣-因此您将其复制到移动[2],而不是移动[1]。哎呀

更糟糕的是,您从未将字符串结尾放在move[]的最后一个有效字符之后

如果有人能解释我做错了什么,我会很感激的

简短的故事是:您的代码不能满足您的需求。它根本不做你想让它做的事

你的要求是:

所有字段必须为一个字符。您的代码无法满足此要求。您的代码将错误地接受每个字段的多个字符。 必须有一个空间正好有一个空间?在田野之间。您的代码无法满足此要求。字段之间可能有多个空格,您的代码将错误地接受这一点。 事实上,您的代码通过访问移动数组来调用未定义的行为。考虑到上述情形之一,我可能会变得高于3。在这段代码中可能会发生什么:move[i]=input[i]

你的代码也太复杂了。您的所有功能都可以由scanf单独执行。这是一个非常强大的功能,当你知道如何正确使用它。。。我建议你在有机会的时候多读多理解。你会学到很多

我注意到您在所介绍的逻辑中忽略了一点:第一个字段可能也是“x”,它对应于一个退出用例。这是一个糟糕的设计;打电话的人没有机会清理。。。但我会带着它跑。您真的应该使用return并返回一个int值或其他与error/success相对应的值

让我们把最后一个段落撇在一边,因为我们可以简单地认为“X”是无效的输入和退出,因此我不想改变你的函数的合同;我把这个留给你。到目前为止描述的表达式似乎是int x=scanf%1[0123456789]%*1[]%1[0123456789]%*1[]%1[vh],a,b,c

请注意,a、b和c应有足够的空间来存储长度为一个字节的字符串。也就是说,它们的声明应该如下所示:chara[2],b[2],c[2]

确保检查了示例中的返回值x!如果x是3,可以安全地假设三个变量a、b和c可以安全使用。如果x是2,可以安全地假设a和b可以安全使用,依此类推。。。如果x为EOF或0,则它们都不能安全使用

通过检查返回值,可以拒绝与该精确模式不匹配的输入,即:

宽度不完全为一个字节的字段将被拒绝。 空间过多或过少将被拒绝。 出现了您忽略了提及的其他内容,它也出现在您的代码中:Chux提到您可能希望输入以“\n”换行符终止。这也可以使用scanf以多种方式实现:

扫描%1*[\n];将尝试读取并丢弃恰好一个“\n”字符,但有 没有办法确保这是成功的。getchar更适合于此目的;类似于if getchar!='\n'{exitEXIT_FAILURE;}可能是有意义的,如果您希望确保输入行的格式是完美的,并且在不正确的情况下爆炸出来。。。你要出去吗? scanf%*[^\n];scanf%*c;更有意义;如果您对每行阅读一项感兴趣,那么丢弃行中剩余的所有内容以及换行符本身是有意义的。请注意,当您的程序丢弃或截断输入时,它应该始终告诉用户。您也可以使用getchar来实现这一点。
那么是数字还是字符?这在Java中也应该有所不同。并限制scanf的输入长度,否则会遇到未定义的行为。char move[4]={0};扫描%c%c%c、&move[0]、&move[1]、&move[2];输入3个字符,前2个为数字,最后1个为“v”或“h”。例如12伏。这是错误的领导。1 2 v是5个字符,如果按enter键计数,则多1个字符。显然,代码需要读取3个非空白字符。当使用scanf和family以及“%s”格式说明符时,为了避免像用户一样的输入缓冲区溢出,在这种情况下,输入16个或更多字符时,始终包含一个比输入缓冲区长度小1的最大长度修饰符。并始终检查返回值而不是参数值以确保操作成功请注意“\0”的额外字节。fgets不需要。推荐fgetsinput、输入大小、标准输入;扫描%d%d%c,&x,&y,&d;无法在OP的12 v中正确扫描。不幸的是,建议不要使用scanf太常见了,因为它很容易被误用,即使它是工作的正确工具。根据这种逻辑,建议不要完全使用C是有道理的。这种逻辑不属于这个问题的答案。此外,建议不要假借scanf不如fscanf安全的幌子使用scanf是没有根据的;对此没有合乎逻辑的解释。x和y可能包含多个数字。如果我可以建议,从一个已经学会如何安全使用scanf的人那里,将x和y声明为未签名int,并使用%1u,这是一个1,而不是一个ell;%1d将导致UB的负值。这些指令都没有强制执行字段之间的空格要求;它们可能会丢弃多个空白字符“\n”、“t”等。。。并始终检查返回值!此外,如上所述,将输入[i]与\n进行比较是不正确的。应该是“\n”这是一条很好的信息,但它需要改进。。。似乎你只花了很小的努力就获得了最高的分数。正如您后来所说,需要检查scanf的返回值;你目前的例子是一个糟糕的例子。此外,这只回答了问题的一半,虽然这似乎是朝着正确方向迈出的一大步,但如果我们准确解释老年退休金计划的要求,那么第一个字段就不需要任何前导空格,其他每个字段都需要一个空格字符的分隔符,而不是换行符或制表符。@Freenode Newbostonesbivor:OP没有列出任何要求,只是两个示例输入,应该可以工作12v和12v。如果不是错误的话,要求字符之间只有一个空格是愚蠢的。尽管我理解这个问题,@chux,在前面添加空格将违反OP指定的要求。修改后一个小时左右我会ping你…@chux谢谢你的输入。。。你觉得怎么样?
char input[3];

scanf(" %c %c %c", intput, input+1, input+2);
    int i = 0;
    while(input[i] != 0){

            if(input[i] != ' ' && input[i] != "\n"){
                    move[i] = input[i];
            }
            i++;
    }
void manageInput(char box[][width]){
    for (;;) {
        char a[2], b[2], c[2];
        int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c);
        if (x != 3) {
            /* INVALID INPUT should cause an error value to be returned!
             * However, this function has no return value (which makes it
             * poorly designed)... Calling `exit` gives no opportunity for
             * calling code to clean up :(
             */
            exit(EXIT_FAILURE);
        }

        if (getchar() != '\n') {
#           ifdef BOMB_OUT
            exit(EXIT_FAILURE);
#           else
            scanf("%*[^\n]");
            getchar();
            puts("NOTE: Excess input has been discarded.");
#           endif
        }

        char move[4] = { a[0], b[0], c[0] };
        printf("%s\n", move);
        makeMove(box, move);
        printBox(box, height, width);
        // TODO
        if(move[0] == 'x'){
            exit(0);
        }
    }
}