该accepted answer是好的,但不完整。
char * test = "abcdefghijklmnopqrstuvwxyz";
甲字符串文字是指具有静态存储持续时间类型char[N]
的一个匿名数组对象(即它存在该程序的整个执行),其中N
是串的长度加上一个用于终止'\0'
。此对象不是const
,但任何修改它的尝试都有未定义的行为。 (一个实现可以使字符串文字写的,如果它选择,但最现代的编译器不知道。)
声明上面创建char[27]
类型,例如一个匿名对象,并使用该对象的第一个元素的地址来初始化test
。因此像test[5] = 'x'
这样的分配尝试修改数组,并且具有未定义的行为;通常会导致程序崩溃。 (初始化使用地址,因为文字是数组类型的表达式,它在大多数上下文中被隐式转换为指向数组第一个元素的指针。)
注意,在C++中,字符串实际上是const
,和上面的声明是非法的。在C或C++,最好声明test
为指针,以常量char
:
const char *test = "abcdefghijklmnopqrstuvwxyz";
所以编译器会警告你,如果你尝试通过test
修改数组。
(由于历史原因,C字符串文字不是const
在1989 ANSI C标准之前const
关键字不存在要求它被用于像你这样的声明中会使用更安全的代码但它会要求现有的代码进行修改,一些ANSI委员会试图避免的。你应该假装该字符串字面量const
,尽管事实并非如此。如果你碰巧使用gcc,该-Wwrite-strings
选项将导致编译器把字符串文字为const
- 这使得GCC不符合)
如果你希望能够修改字符串。指的是,你可以将其定义是这样的:
char test[] = "abcdefghijklmnopqrstuvwxyz";
编译器着眼于初始确定test
需要有多大是。在这种情况下,test
将是char[27]
类型。字符串文字仍然指的是一个匿名的大部分只读数组对象,但它的值是将复制到test
中。 (在用于初始化一个数组对象的初始化字符串文字是其中的阵列不“衰减”的指针的上下文中的一个;所述其它的是当它的一元&
或sizeof
操作数。)由于不存在进一步的对匿名数组的引用,编译器可以优化它。
在这种情况下,test
本身是一个包含您指定的26个字符的数组,加上终止符'\0'
。该阵列的生命周期取决于test
的声明位置,这可能并不重要。例如,如果您这样做:
char *func(void) {
char test[] = "abcdefghijklmnopqrstuvwxyz";
return test; /* BAD IDEA */
}
调用者将收到一个指向不再存在的指针。如果需要参考范围之外的阵列,其中test
被定义,则可以将其定义为static
,也可以使用malloc
分配它:
char *test = malloc(27);
if (test == NULL) {
/* error handling */
}
strcpy(test, "abcdefghijklmnopqrstuvwxyz";
所以该阵列将继续存在,直到调用free()
。非标准的strdup()
函数执行此操作(它由POSIX定义,但不由ISO C定义)。
仔细注意test
可以是指针或取决于你如何声明一个数组。如果您将test
传递给字符串函数,或传递给任何采用char*
的函数,则无关紧要,但类似sizeof test
的行为会有很大差异,具体取决于test
是否为指针或数组。
的comp.lang.c FAQ非常出色。第8部分涵盖字符和字符串,第8.5部分问题涉及问题1.32,它解决了您的具体问题。第6节介绍了数组和指针之间经常令人困惑的关系。
我讨厌这么说,但这确实应该在某个C语言常见问题解答中......在Stack Overflow中已经有数十次或数百次的问题了。 – ephemient 2009-09-21 19:44:44
如果之前已询问过此问题,我很抱歉,但无法找到答案。我确实首先阅读了函数参考和所有内容,但是我确实没有看到我做错了什么。你能指点我这样一个C FAQ吗? – fresskoma 2009-09-21 20:58:06
@ x3ro:4年内没有人回答您有关C FAQ的问题? [comp.lang.c FAQ](http://www.c-faq.com/)非常好。第8部分涵盖字符和字符串,第8.5部分问题涉及问题1.32,它解决了您的具体问题。 – 2013-09-28 20:24:57