我试图创建一个C
代码,该代码从用户获取最大长度10的输入字符串,并将每个字母分配到大小为10的数组的不同元素中。然而,我不能理解我的结果。我的代码:
char word1[9];
int i;
printf("Enter your first word: n");
scanf("%s", &word1);
printf("your word is %s n",word1);
for(i = 0; i < 10; i++)
printf("%d ", word1[i]);
system("pause");
当我输入单词"hello"时,for
循环向我显示,数组word1
的前6个元素中的每一个都被分配了相当于字母h,e,l,l,o的ASCII
数字。理想情况下,最后4个元素应该是0,但事实并非如此。输出为[104 101 108 108 111 0 0 01 0]。这个1是怎么来的?同样,如果我输入"hi"输出结果为[104 105 0 24 -3 127 0 0 10]。104和105后面的这些随机数是什么?为什么它们不是0?
对于上下文,我试图建立一个简单的代码,将检查如果两个输入词是字谜。我的想法过程是,将产生2个ASCII等效数组,然后我可以按升序排序,以便我可以比较每个相应的元素。
附加问题:为什么当我在for循环中从I <10增加10时,输出显示超过10个值?因为数组有10个元素,它不应该总是只显示10个输出吗?
对不起,如果这是微不足道的,我是非常新的C
。
您将获得ASCII数字,因为这一行:
printf("%d ", word1[i]);
你需要用%c
替换%d
-所以问题解决了。不过,还是有一个问题。当请求用户输入时,必须使用scanf()
来接受有限数量的字符:
char word[11]; // to get 10 chars + ' ' (null-terminator)
scanf("%10s", word);
您不需要在scanf()
中引入&符号,并且在%
和s
之间显式地使用(max length - 1)。
最后,迭代到数组的整个长度是一个非常糟糕的主意。考虑迭代直到检测到零终止符。总之,替换为:
for(i = 0; i < 10; i++)
while (word[i] != ' ')
你最大的问题是:
- 错误地使用
scanf()
在word1
调用未定义行为之前添加&
。由于数组/指针转换,word1
已经是一个指针。参见:C11标准- 6.3.2.1其他操作数-左值、数组和函数指示符(p3) - 您没有使用字段宽度修饰符来保护您的数组边界,允许用户通过输入超过您的数组所能容纳的字符来利用您的代码。使用
scanf()
和"%s"
转换说明符,不带字段宽度修饰符,将输入限制为数组可以容纳的字符数,这并不比使用gets()
更安全。看看:为什么gets()如此危险,它永远不应该被使用! - 如果数组包含少于
9
字符(应该是11
以保存10
字符串),则使用for
循环超出数组的末尾。word1
(如果正确读取)是一个以空结束的字符串。您只需循环,直到找到字符串的结束(例如,' '
字符,其ASCII值只是普通的0
)。你不能循环数组可以容纳的最大字符数——它们可能包含未设置的值。
要纠正上述问题,您可以这样做:
#include <stdio.h>
#define MAXCHR 10 /* if you need a constant, #define one (or more) */
int main (void) {
char word1[MAXCHR + 1]; /* to treat chars as a string, you need +1 for */
int i;
fputs ("Enter your first word: ", stdout); /* no conversion, printf not needed */
if (scanf ("%10s", word1) != 1) { /* validate EVERY input, protect */
puts ("EOF encountered on read of word1"); /* array bounds with field-width */
return 0;
}
printf ("your word is: %sn", word1); /* output word1 */
for (i = 0; word1[i]; i++) /* word1 is a string, loop to end */
printf ("%c ", word1[i]);
putchar ('n'); /* tidy up with newline */
#if defined (_WIN32) || defined (_WIN64)
system("pause"); /* non-portable, only for windows */
#endif
}
(注意:只有当输出字符串包含转换时才需要printf()
,否则,puts()
或fputs()
(如果需要行尾控制,则可以)
使用/输出示例
字符数以内的基本输入:
$ ./bin/word1
Enter your first word: bananas
your word is: bananas
b a n a n a s
输入的恰好是允许的字符数:
$ ./bin/word1
Enter your first word: 1234567890
your word is: 1234567890
1 2 3 4 5 6 7 8 9 0
输入的字符数是数组所能容纳的字符串的两倍:
$ ./bin/word1
Enter your first word: 12345678901234567890
your word is: 1234567890
1 2 3 4 5 6 7 8 9 0
(注意:无论您尝试输入多少字符,都只会存储10
加上终止null的字符。请注意,任何未读的字符都保留在stdin
中未读—只是等待在下一次输入时咬您。这就是为什么应该使用fgets()
或POSIXgetline()
来获取输入,以便消耗整行输入。无论使用哪个输入函数,除非检查返回值,否则无法正确使用它。用于确定输入是否成功。)
请过目一遍,如果还有问题请告诉我。
原因是,数组在C中不是由默认值(如0)初始化的,因此当您输入一个不覆盖整个数组的字符串时,其余元素没有任何默认值,并且它们从内存中获得一些垃圾值。您可以像这样初始化单词数组:
for(i = 0; i < 10; i++)
word1[i] = 0;
PS:char word1[9];
创建9个单元格而不是10个。还要注意,您应该考虑为