简体   繁体   English

如何获取在scanf中用空格输入的3个字符到一个char数组中?

[英]How to get 3 chars entered with spaces in scanf into a char array?

I am previously a java programmer, but I'm now doing a C course at university (computer science major). 我以前是Java程序员,但现在正在大学(计算机科学专业)学习C课程。

I need the user to be able to enter 3 chars,the first 2 being numbers, and the last 1 being either 'v' or 'h'. 我需要用户能够输入3个字符,前2个是数字,后1个是“ v”或“ h”。 For example "1 2 v". 例如“ 1 2 v”。

I need the user to be able to enter it with the spaces in between each character. 我需要用户能够输入每个字符之间的空格。

This is my current code: 这是我当前的代码:

void manageInput(char box[][width]){
    char move[4];
    char input[16]; 
    while(1){

            scanf("%s", input);
            int i = 0;
            while(input[i] != 0){

                    if(input[i] != ' ' && input[i] != "\n"){
                            move[i] = input[i];
                    }
                    i++;
            }
            printf("%s\n", move);

            makeMove(box, move);
            printBox(box, height, width);
            // TODO
            if(move[0] == 'x'){
                    exit(0);
            }
    }

} }

However if I run it, it works fine when I enter the chars with out spaces like "12v", but If I enter "1 2 v", it will print out "1", call printBox, then print out "2", then print out box again, and so on. 但是,如果我运行它,当我输入带有“ 12v”之类的空格的字符时,它可以正常工作,但是如果我输入“ 1 2 v”,它将打印出“ 1”,调用printBox,然后打印出“ 2”,然后再次打印输出框,依此类推。

If someone could explain what I'm doing wrong here, I would appreciate it. 如果有人可以在这里解释我在做什么错,我将不胜感激。

If someone could explain what I'm doing wrong here, I would appreciate it. 如果有人可以在这里解释我在做什么错,我将不胜感激。

The short story is: Your code doesn't fulfill your requirements. 简短的故事是:您的代码无法满足您的要求。 It simply doesn't do what you want it to do. 它根本不执行您想要的操作。

Your requirements are: 您的要求是:

  • All fields must be one character. 所有字段必须是一个字符。 This requirement isn't fulfilled by your code. 您的代码无法满足此要求。 Your code will mistakenly accept multiple characters per field. 您的代码将错误地在每个字段中接受多个字符。
  • There must be one space (exactly one space?) between the fields. 字段之间必须有一个空格(恰好是一个空格?)。 This requirement isn't fulfilled by your code. 您的代码无法满足此要求。 There might be multiple spaces between the fields, and your code will mistakenly accept that. 字段之间可能有多个空格,并且您的代码将错误地接受该空格。

In fact, your code invokes undefined behaviour by accessing the move array out of bounds. 实际上,您的代码通过超出范围访问move数组来调用未定义的行为。 Consider that as a consequence of one of the above scenarios i might become some value higher than 3. What might happen in this code: move[i] = input[i]; 考虑到上述情况之一, i可能会变得比3高一些。此代码中可能发生什么: move[i] = input[i]; ?

Your code is also way too complex. 您的代码也太复杂了。 All of your functionality can be performed by scanf alone. 您的所有功能都可以由scanf单独执行。 It's a very powerful function, when you know how to use it correctly... I suggest reading and understanding the manual multiple times, when you have an opportunity. 当您知道如何正确使用它时,它是一项非常强大的功能。如果有机会,我建议您多次阅读和理解本手册 You'll learn a lot ! 您将学到很多东西

I notice something you neglected to mention from within the logic you have presented: It's expected that the first field might also be 'x' , which corresponds to an exit usecase. 我注意到您在所提供的逻辑中忽略了要提及的内容:预计第一个字段也可能是'x' ,它对应于退出用例。 This is a bad design; 这是一个糟糕的设计; the caller has no opportunity to clean up... but I'll run with it. 呼叫者没有机会清理...但是我会继续处理。 You really should use return (and return an int value or something, corresponding to error/success) instead. 您实际上应该使用return (并返回一个int值或某个值,对应于错误/成功)。

Let us caste that last paragraph aside, because we can simply consider 'x' to be invalid input (and exit as a result), and I don't want to change the contracts of your functions; 让我们将最后一段抛开,因为我们可以简单地将'x'视为无效输入(并因此退出),并且我不想更改函数的协定。 I'll leave that to you. 我留给你。 The expression described so far appears to be int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c); 到目前为止描述的表达式似乎是int x = scanf("%1[0123456789]%*1[ ]%1[0123456789]%*1[ ]%1[vh]", a, b, c); .

Note that it is expected that a , b and c will have enough space to store a string of one byte in length. 请注意,预期abc将有足够的空间来存储长度为一个字节的字符串。 That is, their declaration should look like: char a[2], b[2], c[2]; 也就是说,它们的声明应类似于: char a[2], b[2], c[2]; .

Make sure you check the return value ( x , in the example)! 确保检查返回值(在示例中为x )! If x is 3, it's safe to assume that the three variables a , b and c are safe to use. 如果x为3,则可以安全地假定三个变量abc可以安全使用。 If x is 2, it's safe to assume that a and b are safe to use, and so on... If x is EOF or 0 , none of them are safe to use. 如果x为2,则可以安全地假定ab是可以安全使用的,依此类推...如果xEOF0 ,则都不可以安全使用。

By checking the return value, you can reject input that doesn't match that precise pattern, that is: 通过检查返回值,您可以拒绝与该精确模式不匹配的输入,即:

  • Fields that aren't exactly one byte in width will be rejected. 宽度不完全是一个字节的字段将被拒绝。
  • Too many or too few spaces will be rejected. 太多或太少的空格将被拒绝。

Something else popped up that you have neglected to mention, and it's also present within your code: Chux mentioned that you'll likely be expecting the input to be terminated with a '\\n' (newline) character. 弹出的其他内容您没有提到,它也存在于代码中:Chux提到您可能期望输入以'\\n' (换行符)终止。 This can also be implemented in a number of ways using scanf : 这也可以使用scanf以多种方式实现:

  • scanf("%1*[\\n]"); will attempt to read and discard precisely one '\\n' character, but there's no way to ensure that was successful. 会尝试读取并精确丢弃一个'\\n'字符,但是无法确保成功。 getchar would be more appropriate for that purpose; getchar将更适合getchar目的; something along the lines of if (getchar() != '\\n') { exit(EXIT_FAILURE); } 类似于if (getchar() != '\\n') { exit(EXIT_FAILURE); } if (getchar() != '\\n') { exit(EXIT_FAILURE); } might make sense, if you wish to ensure that the lines of input are perfectly formed and bomb out when they aren't... #define BOMB_OUT ? if (getchar() != '\\n') { exit(EXIT_FAILURE); }可能是有意义的,如果你希望确保输入的线是完全形成,并轰炸时,他们都没有...... #define BOMB_OUT
  • scanf("%*[^\\n]"); scanf("%*c"); makes more sense; 更有意义; If you're interested in reading one item per line , then it makes sense to discard everything remaining on the line, and then the newline character itself. 如果您有兴趣阅读每行中的一项 ,则有必要丢弃该行中剩余的所有内容,然后丢弃换行符本身。 Note that your program should always tell the user when it's discarding or truncating input. 请注意,您的程序应始终告诉用户何时丢弃或截断输入。 You could also use getchar for this. 您也可以为此使用getchar

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);
        }
    }
}

%s reads a whitespace-delimited string with scanf, so if that's not what you want, it's not the thing to use. %s使用scanf读取由空格分隔的字符串,因此,如果这不是您想要的内容,那不是要使用的东西。 %c reads a single character, but does not skip whitespce, so you probably also want a %c读取一个字符,但不跳过白杠,因此您可能还需要一个 (space) in your format to skip whitespace: (空格)以您的格式跳过空格:

char input[3];

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

will read 3 non-whitespace characters and skip any whitespace before or between them. 将读取3个非空白字符,并跳过它们之前或之间的所有空白。 You should also check the return value of scanf to make sure that it is 3 -- if not, there was less than 3 characters in your input before an end-of-file was reached. 您还应该检查scanf的返回值,以确保它是3 -如果不是,则在到达文件结尾之前,输入的字符数少于3个。

It's usuall a bad idea to read string via scanf because of potential buffer overflow. 由于潜在的缓冲区溢出,通过scanf读取字符串通常是一个坏主意。 Consider using fscanf or better fgets as in 考虑使用fscanf或更好的fgets

fgets(input, 15, stdin);

Note the extra byte for '\\0'. 注意“ \\ 0”的额外字节。


Also, you're comparing char to string here: input[i] != "\\n" . 另外,您在这里将char与string进行比较: input[i] != "\\n" It should be input[i] != '\\n' instead. 应该改为input[i] != '\\n'


And btw you can just use something like 顺便说一句,您可以使用类似

int x, y;
char d;
scanf("%d%d%c", &x, &y, &d);

This looks like two simple bugs. 这看起来像两个简单的错误。

You need to use separate indexes for move[] and input[] 您需要为move []和input []使用单独的索引

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

            if(input[i] != ' ' && input[i] != "\n"){
                    move[i] = input[i];
            }
            i++;
    }

Imagine input of 1 2 v 想象一下1 2 v的输入

input[0] != 0, so we enter the loop input [0]!= 0,所以我们进入循环

it's not ' ' or '\\n' either, so we copy input[0] to move[0] 它也不是''或'\\ n',所以我们将输入[0]复制到move [0]

so far so good 到现在为止还挺好

You increment i, and discover that input[1] == ' ' 您增加i,然后发现input [1] ==''

But then you increment i again 但是你又增加了我

You discover that you are interested in input[2] (2) - so you copy it to move[2], rather than move[1]. 您发现您对输入[2](2)感兴趣-因此您将其复制到move [2],而不是move [1]。 Oops! 哎呀!

Then to make things worse, you never put an end-of-string character after the last valid character of move[]. 然后,更糟糕的是,您永远不要在move []的最后一个有效字符之后放置字符串结尾字符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM