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

时间:2017-02-05 05:56:53

标签: c arrays

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

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

char arr[3] = "xyz";

char arr[] = "xyz";

提前致谢。

4 个答案:

答案 0 :(得分:8)

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

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

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'  |
|_______|_______|_______|

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

const char[] my_string = "abc";

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

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

答案 1 :(得分:4)

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

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

  

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

char arr[3] = "xyz";

在此示例中,arr的大小为3,但字符串文字的大小为4。字符串定义了一个字符(终止' \ 0'),而不是数组可以容纳的字符。

char arr[] = "xyz";

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

答案 2 :(得分:2)

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

示例代码

int main()
{
    int i;
    char arr[] = "xyz Hello World";
    for(i=0;i<sizeof(arr)-1;i++){
        printf("%c",arr[i]);
    }
    printf("\n");
    return 0;
}

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

警告

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

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

答案 3 :(得分:0)

还考虑使用

const char* arr = "xyz";

它是一样的(除了使用它之后的常量关键字,所以你不会意外地更改数组),但数据不会被复制在堆栈中,您可以在可执行文件的数据段中使用静态副本。特别是对于大弦乐,这很重要。