[英]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: 您的要求是:
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. 请注意,预期
a
, b
和c
将有足够的空间来存储长度为一个字节的字符串。 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,则可以安全地假定三个变量a
, b
和c
可以安全使用。 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,则可以安全地假定a
和b
是可以安全使用的,依此类推...如果x
为EOF
或0
,则都不可以安全使用。
By checking the return value, you can reject input that doesn't match that precise pattern, that is: 通过检查返回值,您可以拒绝与该精确模式不匹配的输入,即:
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; 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.