我是编程新手,几周前开始学习 C。我在一本书上读到字符数组应该以 \0
结尾,但是当我创建一个没有 \0
的数组时,它可以正常工作。怎么可能。?
#include<stdio.h>
#include<string.h>
int main()
{
char a[] = {'a','p','p','l','e'};
printf("%d\n",strlen(a));
printf("%s\n",a);
return 0;
}
上面的代码输出是
5 apple
我还读到 char 是整数数据类型的子集,但是当我使用 int 数据类型创建上述数组时,它无法正常工作。
#include<stdio.h>
#include<string.h>
int main()
{
int a[] = {'a','p','p','l','e'};
printf("%d\n",strlen(a));
printf("%s\n",a);
return 0;
}
上面的代码输出是
1 a
为什么它只考虑数组的第一个元素?
最佳答案
你的问题的前半部分相当于:
I'm new to life and started to learn about road traffic a few weeks back. I have read in a book that you should wait for the green light before entering the intersection, but when I enter the intersection without waiting, it works properly. How is it possible?
换句话说,你只是运气好而已。碰巧的是,即使您构造了一个没有正确 \0
的字符数组。终止符,内存中恰好在 e
之后有一个 0 字节在apple
,所以无论如何它都有效。但它根本不能保证有效,就像它不能保证你可以继续逆着红灯过马路而最终不会被撞到一样。
继续你的第二个问题,当你读到“char
是整数数据类型的子集”时,这并不意味着你通常会在任何地方使用 char
。 ,您还可以使用int
.
这是内存中的一些字符。它们每个的大小都是一字节:
char c1 = 'p', c1 = 'e', c3 = 'a', c4 = 'r';
+---+ +---+
c1: | p | c2: | e |
+---+ +---+
+---+ +---+
c3: | a | c4: | r |
+---+ +---+
这是内存中的一些整数。在现代机器上,每个字节的大小可能是四个字节:
int i1 = 'p', i1 = 'e', i3 = 'a', i4 = 'r';
+---+---+---+---+ +---+---+---+---+
i1: | p | i2: | e |
+---+---+---+---+ +---+---+---+---+
+---+---+---+---+ +---+---+---+---+
i3: | a | i4: | r |
+---+---+---+---+ +---+---+---+---+
这是一个 char
的数组,正确的空终止:
char ca[] = { 'p', 'e', 'a', 'r', '\0' };
+---+---+---+---+---+
ca: | p | e | a | r |\0 |
+---+---+---+---+---+
何时 printf
打印此字符串,或 strlen
计算它的长度,他们从开头开始,沿着字符串一次移动一个字节,直到找到 \0
.
但是这是一个 int
的数组:
int ia[] = { 'p', 'e', 'a', 'r', '\0' };
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
ia: | p | e | a | r | \0 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
但我画得有点错误,因为实际上,每个 int 中的三个额外字节并不是用空格填充的,而是用零字节填充的。 (就好像我们想用前导零来表示数字 1,即 0001。)所以更准确的图片如下所示;
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
ia: | p \0 \0 \0 | e \0 \0 \0 | a \0 \0 \0 | r \0 \0 \0 | \0 \0 \0 \0|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
所以当 printf
或strlen
从头开始并一次一个字节地处理数组,查找终止 \0
,他们立即找到一个,就在第一个字母之后。
这里需要考虑的重要一点是 printf
和strlen
被定义为对 char
的数组进行操作。由于 C 的工作方式,他们无法知道你是否作弊并传递了 int
数组。反而。他们确实采用了相同的内存并将其视为 char
的数组。 ,因此得到的结果与您的预期截然不同。
因为很容易犯这样的错误,所以如果你犯了这样的错误,好的编译器会警告你。对于您的代码,我的编译器给了我这些警告:
warning: incompatible pointer types passing 'int [5]' to parameter of type 'const char *'
warning: format specifies type 'char *' but the argument has type 'int *'
这些消息引用类型 char *
,它是指向 char
的指针,因为当您将数组传递给函数时,实际传递的是指向数组第一个元素的指针。 (但这是另一天的话题。但这与我所说的 printf
和 strlen
“实际上采用相同的内存并将其视为”它是一个字符数组有很大关系。)
关于无法创建整数数组来保存字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52235084/