我目前正在学习C,我对char数组和字符串之间的差异以及它们的工作原理感到困惑。
问题1:
为什么源代码1和源代码2的结果有所不同?
源代码1:
#include <stdio.h>
#include <string.h>
int main(void)
{
char c[2]="Hi";
printf("%d\n", strlen(c)); //returns 3 (not 2!?)
return 0;
}
源代码2:
#include <stdio.h>
#include <string.h>
int main(void)
{
char c[3]="Hi";
printf("%d\n", strlen(c)); //returns 2 (not 3!?)
return 0;
}
问题2:
字符串变量与char数组有何不同?如何使用允许\ 0存储的最小所需索引号来声明它们(请阅读下面的代码)?
char name[index] = "Mick"; //should index be 4 or 5?
char name[index] = {'M', 'i', 'c', 'k'}; //should index be 4 or 5?
#define name "Mick" //what is the size? Is there a \0?
问题3:
终止NUL是否仅遵循字符串而不是字符数组?所以字符串“Hi”的实际值是[H] [i] [\ 0],字符数组“Hi”的实际值是[H] [i]?
问题4:
假设c [2]将存储“Hi”后跟一个\ 0(不确定如何完成,可能使用gets(c)
?)。那么\ 0存储在哪里?它是在c [2]之后“某处”存储为[H] [i] \ 0或将c [2]附加一个\ 0变为c [3],即[H] [i] [\ 0 ]
有点令人困惑的是,有时在字符串/ char数组后面有一个\ 0,当我用if (c1==c2)
比较两个变量时会导致麻烦,因为它很可能返回FALSE(0)。
详细的答案表示赞赏。但保持你的答案简短有助于我的理解:) 提前谢谢!
答案 0 :(得分:3)
答案1 :在代码1中,您有一个不是字符串的char数组;在代码2中,你有一个char数组,也是一个字符串。
答案2 :字符串是一个char数组,其中(至少)一个元素的值为0
;如果将大小部分留空,编译器将自动用尽可能小的值填充它。
char astring[] = "foobar"; /* compiler automagically uses 7 for size */
printf("%d\n", (int)sizeof astring);
回答3 :一个char数组,其中一个元素NUL
是一个字符串;一个char数组,其中没有元素NUL
不是字符串。
答案4 :定义为包含两个元素(char c[2];
)的数组不能容纳三个元素。如果它是一个字符串,它只能是空字符串或带有1个字符的字符串。
答案 1 :(得分:3)
问题1:
为什么源代码1和源代码的结果存在差异 代码2?
源代码1:
#include <stdio.h>
#include <string.h>
int main()
{
char c[2]="Hi";
printf("%d", strlen(c)); //returns 3 (not 2!?)
getchar();
}
源代码2:
#include <stdio.h>
#include <string.h>
int main()
{
char c[3]="Hi";
printf("%d", strlen(c)); //returns 2 (not 3!?)
getchar();
}
<强>答案强>:
因为在第一种情况下,c[]
仅持有“嗨”。 strlen最后会查找零,并且,具体取决于c[]
后面迟到的内容,或者崩溃。如果不确切知道c[]
数组后面的内存是什么,我们就不能说。
问题2:
字符串变量与char数组有何不同?如何申报 它们具有允许\ 0存储的最小所需索引号 如果有的话(请阅读下面的代码)?
char name[index] = "Mick"; //should index be 4 or 5?
char name[index] = {'M', 'i', 'c', 'k'}; //should index be 4 or 5?
<强>答案强> 真的取决于你想做什么。如果你想将内容实际用作字符串,可能就是5。但是没有什么可以说你不能将“Mick”存储在4个字符的数组中 - 你只是不能使用strlen来找出它有多长,因为strlen将继续5并且很可能(很多)进一步找到长度,如果下几个内存位置没有零,则可能导致崩溃,因为最终没有有效的内存地址可供读取。
#define name "Mick" //what is the size? Is there a \0?
这完全没有大小,直到你使用名称somwhere。 #defines不是编译器看到的内容 - 如果你在任何地方使用name
,预处理器将用"Mick"
替换name
- 并且希望,这是编译器可以理解的地方的。然后应用与之前的答案相同的规则 - 这取决于您希望如何使用字符数组。要使用strlen
,strpy
和几乎所有其他str...
函数进行正确操作,最后需要为零。
问题3:
终止null是仅遵循字符串而不是字符数组?所以 字符串“Hi”的实际值是[H] [i] [\ 0]和实际值 char数组“Hi”是[H] [i]?
是的,不,也许吧。这一切都取决于你如何使用"Hi"
字符串文字(这是“双引号内的东西”的技术名称)。如果编译器是“允许的”,它将在结尾处放置零。但是如果你将一个数组初始化到一个给定的大小,它会把字节填入那里,如果没有空间,那就是你的问题,而不是编译器的问题。
问题4:
假设c [2]将存储“Hi”,然后存储\ 0(不确定如何 这是完成的,使用gets(c)也许?)。那么\ 0存储在哪里?是吗 在c [2]之后存储“某处”变为[H] [i] \ 0或将c [2]存在 附加\ 0成为c [3],即[H] [i] [\ 0]?
在c [2]中,除了'H','i'之外,没有人知道存储了什么[技术上,它很可能是“地球的尽头” - 在计算机术语中,这是“可以记忆的”不会被阅读 - 在这种情况下strlen
就会崩溃你的程序,因为strlen读取超出地球的末端]。但是如果也可以是零,一个,字母'a',数字42,或任何其他8位[1]值。
安静令人困惑的是,有时会有一个\ 0跟随 string / char数组,当我比较两个变量时会导致麻烦 if(c1 == c2)因为它很可能返回FALSE(0)。
如果c1和c2是char数组,那么总是假的,因为c1和c2永远不会有相同的地址,并且在C中以这种方式使用数组时,它变成“第一个内存中的地址”数组中的元素“。所以无论c1和c2的内容是什么,它们的地址都不能相同[因为它们是两个不同的变量,而且两个变量在内存中不能有相同的位置 - 就像试图将两辆车停在停车位一样只有一辆车足够大 - 不,在我们的思想实验中不允许破碎任何一辆车]。
[1]不保证字符为8位。但是现在就让我们知道。
答案 2 :(得分:1)
strlen()
适用于\0
终止字符,C
所有字符串都应\0
终止。因此,当您为2个字符H
和i
仅提供2个空格时,\0
没有空间。因此,您在Undefined Behavior
中获得了strlen()
。
如果是char c[3] = "Hi";
,则第三位有\0
,而strlen()将计算实际长度。
How to declare them with the minimum required index numbers allowing \0 to be stored if any ?
如果您不确定char数组的大小,请执行以下操作:
char c1[] = "Mike"; // strlen = 4
char c2[] = "Omkant" // strlen = 6
注意:
编辑:在上述未明确提及尺寸的情况下,请勿与sizeof
混淆strlen()
。
strlen()
仅返回字符数
sizeof
给出的字符数加上一个(\0
个字符)。
因此sizeof总是比strlen()返回的数字多1个。
答案 3 :(得分:1)
运行源代码一是未定义的行为,因为strlen()
需要一个以NUL结尾的字符串,c[2] = "Hi"; /* = { 'H', 'i' } */
不是。{1}}。字符串与char数组的不同之处在于字符串是一个char数组,在数组中某处至少有一个NUL字节。
其余的答案应该很容易理解。
要在初始化时自动调整char数组以匹配字符串文字的大小,只需指定数组大小:
char c[] = "This will automatically size the c array (including the NUL).";
请注意,无法将char数组与==运算符进行比较。你必须使用
if (strcmp(c1, c2) == 0) {
/* Equal. */
} else {
/* Not equal. */
}