13

考虑以下代码。

诠释主要(无效){
    char * test = "abcdefghijklmnopqrstuvwxyz";
    测试[5] = 'x';
    printf("%s\n", test);
    返回 EXIT_SUCCESS;
}

在我看来,这应该打印 abcdexghij。但是,它只是终止而不打印任何内容。

诠释主要(无效){
    char * test = "abcdefghijklmnopqrstuvwxyz";
    printf("%s\n", test);
    返回 EXIT_SUCCESS;
}

然而,这工作得很好,所以我误解了操纵 C 字符串的概念吗?如果它很重要,我正在运行 Mac OS X 10.6,它是我正在编译的 32 位二进制文​​件。

4

5 回答 5

32

用初始化值定义的字符指针进入只读段。要使它们可修改,您要么需要在堆上创建它们(例如使用 new/malloc),要么将它们定义为数组。

不可修改:

char * foo = "abc";

可修改:

char foo[] = "abc";
于 2009-09-21T18:16:01.353 回答
16

这个答案很好,但并不完整。

char * test = "abcdefghijklmnopqrstuvwxyz";

字符串字面量是指char[N]具有静态存储持续时间的匿名数组对象(意味着它在程序的整个执行过程中都存在),其中N是字符串的长度加上终止符的长度'\0'。此对象不是const,但任何修改它的尝试都有未定义的行为。(如果选择,实现可以使字符串文字可写,但大多数现代编译器不这样做。)

上面的声明创建了一个类型为 的匿名对象char[27],并使用该对象的第一个元素的地址来初始化test。因此,类似于test[5] = 'x'尝试修改数组的赋值,并且具有未定义的行为;通常它会使你的程序崩溃。(初始化使用地址,因为字面量是数组类型的表达式,在大多数上下文中它被隐式转换为指向数组第一个元素的指针。)

请注意,在 C++ 中,字符串文字实际上是const,上面的声明是非法的。在 C 或 C++ 中,最好声明test为指向const char的指针:

const char *test = "abcdefghijklmnopqrstuvwxyz";

因此,如果您尝试通过test.

(C 字符串文字不是const出于历史原因。在 1989 年 ANSI C 标准之前,该const关键字不存在。要求在像您这样的声明中使用它会使代码更安全,但它需要修改现有代码, ANSI 委员会试图避免的事情。您应该假装字符串文字是const,即使它们不是。如果您碰巧使用 gcc,该-Wwrite-strings选项将导致编译器将字符串文字视为const-- 这使得 gcc 不合格.)

如果您希望能够修改test引用的字符串,可以这样定义:

char test[] = "abcdefghijklmnopqrstuvwxyz";

编译器查看初始化程序以确定需要多大test。在这种情况下,test将是类型char[27]。字符串字面量仍然引用匿名的大部分只读数组对象,但它的值被复制test. (用于初始化数组对象的初始化程序中的字符串文字是数组不会“衰减”为指针的上下文之一;其他情况是当它是一元&或的操作数时sizeof。)因为没有进一步引用匿名数组,编译器可能会将其优化掉。

在这种情况下,它本身是一个包含您指定的 26 个字符以及终止符test的数组。'\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给一个字符串函数,或者传递给任何接受 a 的函数char*,那没关系,但是sizeof test根据test是指针还是数组,类似的东西会表现得非常不同。

comp.lang.c 常见问题解答非常好。第 8 节涵盖字符和字符串,问题 8.5 指向问题 1.32,该问题解决了您的具体问题。第 6 节介绍了数组和指针之间经常令人困惑的关系。

于 2013-09-28T20:50:45.313 回答
4

您应该养成将变量类型与初始化程序类型匹配的习惯。在这种情况下:

const char* test = "abcdefghijklmnopqrstuvwxyz";

这样你会得到一个编译器错误而不是运行时错误。将编译器警告级别提高到最高也可能有助于避免此类陷阱。为什么这不是 C 语言中的错误可能是历史原因;当语言标准化时,早期的编译器允许它并且不允许它可能破坏了太多现有代码。但是现在操作系统不允许这样做,所以它是学术性的。

于 2009-09-21T18:29:33.017 回答
4

字符串文字可能不可修改;最好假设他们不是。有关更多详细信息,请参见此处

于 2009-09-21T18:38:46.150 回答
0

做:

 char * bar = strdup(foo);
 bar[5] = 'x';

strdup制作可修改的副本。

是的,你真的应该测试strdup没有返回 NULL。

于 2010-02-07T01:13:00.380 回答