哪个是使用字符串文字初始化字符数组的更好方法?

我是C语言的新手。 我试图理解C中的数组概念。我对数组初始化有困惑。

哪个是使用字符串文字初始化字符数组的更好方法?

 char arr[3] = "xyz"; 

要么

 char arr[] = "xyz"; 

提前致谢。

除非在特殊情况下,总是更喜欢第二种方式,即不明确键入数组的大小。 这样可以避免在您的示例中看似无意识地创建的错误。

要理解这一点,首先应该了解字符串究竟是什么。 空字符用'\0' 。 字符串是一系列零个或多个非空char由单个空字符终止 。 最后一点非常重要。 看下面的代码:

 const char* my_string = "xyz"; size_t string_len = strlen( my_string ); // string_Len == 3 

指针只是一个内存地址。 它本身不包含任何类型的大小或长度信息。 然后, strlen()如何测量my_string的长度? 当然,这是通过测量字符串开头到终止空字符之前的非空字符数量。 您现在可能已经注意到,终止空字符隐含在字符串文字中。 上面的字符串文字在内存中创建一个如下所示的数组:

  _______ _______ _______ _______ | | | | | | 'x' | 'y' | 'z' | '\0' | |_______|_______|_______|_______| ^ | `my_string` is a pointer to this cell 

数组本身没有命名,但编译器设法将其第一个元素的地址作为my_string的值。 那么,你的第一个例子会发生什么?

 char my_string[ 3 ] = "abc"; 

根据标准的定义,字符串文字的类型为char[ N ] ,其中N是字符串的长度加上一个要计算的空字符(请注意,由于历史原因字符串文字未声明为const ,但仍然是未定义的行为以修改它们)。 因此,上面的表达式"abc"具有char[ 4 ]类型。 另一方面, my_string (现在是一个数组,而不是指针,BTW)的类型为char[ 3 ] 。 也就是说,您将较小的数组设置为较大的数组,因为4 > 3 。 标准规定,在这种精确的情况下,字符串文字的空字符不适合数组,它应该被截断。 因此, my_string在内存中看起来像这样:

  _______ _______ _______ | | | | | 'a' | 'b' | 'c' | |_______|_______|_______| 

看起来不错,但……等等。 终止空字符在哪里? 你通过明确声明arrays的大小来切断它! 现在, strlen()应该如何确定字符串的长度? 它将继续读取字符串之后的字符,直到通过巧合找到空字符。 这是未定义的行为。 另一方面,通过这样做:

 const char[] my_string = "abc"; 

你不会冒这样做的风险。 my_string的类型将自动推导为const char[ 4 ] ,并保留null字符。

tl; dr不要忘记终止空字符!

每当使用字符串文字初始化一个字符数组时,不要指定用字符串文字初始化的字符串的边界,因为编译器将自动为整个字符串文字分配足够的空间,包括终止空字符。

C标准(c11 – 6.7.8:第14段)说:

字符类型数组可以由字符串文字或UTF-8字符串文字初始化,可选地用大括号括起来。 字符串文字的连续字节(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素。

 char arr[3] = "xyz"; 

在此示例中, arr大小为3 ,但字符串文字的大小为4 。 string定义了一个比数组更能容纳的字符(终止’\ 0’)。

 char arr[] = "xyz"; 

在此示例中,未指定数组初始化中字符数组的边界。 如果省略数组绑定,则编译器会分配足够的大小来存储整个字符串文字,包括空字符。

你使用第二个,因为在第二个中你想要初始化另一个超过3个字符的string ,所以它会自动处理。

示例代码

 int main() { int i; char arr[] = "xyz Hello World"; for(i=0;i 

如果您使用第一个,那么当您想存储超过3个字符串时,它将在编译时显示warning

警告

  warning: initializer-string for array of chars is too long [enabled by default] char arr[3] = "xyz Hello World"; 

所以你应该使用第二个帽子是使用string初始化character数组的更好方法。

考虑也使用

 const char* arr = "xyz"; 

它是相同的(除了’const’关键字使得它不会意外地更改数组),但数据不会被复制到堆栈上,您在可执行文件的数据段中使用静态副本。 特别是对于大弦,这可能很重要。