关于字符串长度,终止NUL等

时间:2012-12-31 21:23:41

标签: c string arrays

我目前正在学习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)。

详细的答案表示赞赏。但保持你的答案简短有助于我的理解:) 提前谢谢!

4 个答案:

答案 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 - 并且希望,这是编译器可以理解的地方的。然后应用与之前的答案相同的规则 - 这取决于您希望如何使用字符数组。要使用strlenstrpy和几乎所有其他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个字符Hi仅提供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. */
}