不能修改的C字符串 [英] Cannot modify C string
问题描述
考虑以下code。
int main(void) {
char * test = "abcdefghijklmnopqrstuvwxyz";
test[5] = 'x';
printf("%s\n", test);
return EXIT_SUCCESS;
}
在我看来,这应该打印abcdexghij。然而,它只是终止,但不会打印任何东西。
In my opinion, this should print abcdexghij. However, it just terminates without printing anything.
int main(void) {
char * test = "abcdefghijklmnopqrstuvwxyz";
printf("%s\n", test);
return EXIT_SUCCESS;
}
然而,这工作得很好,所以我误解操纵C字符串什么概念?在情况下,它是很重要的,我在运行Mac OS X 10.6,这是一个32位二进制我编译。
This however, works just fine, so did I misunderstand the concept of manipulating C strings or something? In case it is important, I'm running Mac OS X 10.6 and it is a 32-bit binary I'm compiling.
推荐答案
借助接受的答案是好的,但不是很完整的。
The accepted answer is good, but not quite complete.
char * test = "abcdefghijklmnopqrstuvwxyz";
一个的字符串的引用类型的匿名数组对象的char [N]
与静态存储时间(这意味着它存在的整个执行该计划),其中 N
是字符串的长度加上一个用于终止'\\ 0'
。这个对象不是常量
,但任何试图修改它不确定的行为。 (一个实现的可以的让字符串字面写的,如果它选择,但多数现代的编译器不知道。)
A string literal refers to an anonymous array object of type char[N]
with static storage duration (meaning it exists for the entire execution of the program), where N
is the length of the string plus one for the terminating '\0'
. This object is not const
, but any attempt to modify it has undefined behavior. (An implementation can make string literals writable if it chooses, but most modern compilers do not.)
该声明之上创建一个类型的char [27]
这样一个匿名对象,并使用该对象的第一个元素的地址来初始化测试
。因此,像的转让测试[5] ='X'
试图修改数组,并已不确定的行为;通常它会程序崩溃。 (初始化使用的地址,因为文字是数组类型,这是隐式转换在大多数情况下的指针数组的第一个元素的前pression。)
The declaration above creates such an anonymous object of type char[27]
, and uses the address of that object's first element to initialize test
. Thus an assignment like test[5] = 'x'
attempts to modify the array, and has undefined behavior; typically it will crash your program. (The initialization uses the address because the literal is an expression of array type, which is implicitly converted in most contexts to a pointer to the array's first element.)
请注意,在C ++中,字符串文字实际上是常量
,和上面的声明是非法的。在C或C ++,最好声明测试
为指针的常量的字符
Note that in C++, string literals are actually const
, and the above declaration would be illegal. In either C or C++, it's best to declare test
as a pointer to const char
:
const char *test = "abcdefghijklmnopqrstuvwxyz";
所以编译器会警告你,如果你尝试通过修改数组测试
。
(C字符串不是常量
由于历史原因,1989年的ANSI C标准之前,常量
关键字不存在。要求它在声明中使用像你会作出更安全的code,但它会要求现有的code被修改,一些ANSI委员会试图避免的。你应该的 pretend 的该字符串字面量常量
,即使他们不是如果你碰巧使用gcc,在 - Wwrite弦
选项将导致编译器把字符串为常量
- 这使得GCC不合格)
(C string literals are not const
for historical reasons. Before the 1989 ANSI C standard, the const
keyword did not exist. Requiring it to be used in declarations like yours would have made for safer code, but it would have required existing code to be modified, something the ANSI committee tried to avoid. You should pretend that string literals are const
, even though they aren't. If you happen to be using gcc, the -Wwrite-strings
option will cause the compiler to treat string literals as const
-- which makes gcc non-conforming.)
如果您希望能够修改测试
指的是字符串,您可以将其定义是这样的:
If you want to be able to modify the string that test
refers to, you can define it like this:
char test[] = "abcdefghijklmnopqrstuvwxyz";
编译器着眼于初始化,以确定有多大测试
必须。在这种情况下,测试
将类型的char [27]
。该字符串仍引用匿名大多只读的数组对象,但其价值的复制的成测试
。 (以用于初始化数组对象的初始化字符串文字是其中一个数组不腐烂的指针上下文之一;其他是当它是一元&放大器的操作;
或的sizeof
)。由于有匿名数组没有进一步的引用,编译器可以优化它了。
The compiler looks at the initializer to determine how big test
needs to be. In this case, test
will be of type char[27]
. The string literal still refers to an anonymous mostly-read-only array object, but its value is copied into test
. (A string literal in an initializer used to initialize an array object is one of the contexts in which an array does not "decay" to a pointer; the others are when it's the operand of unary &
or sizeof
.) Since there are no further references to the anonymous array, the compiler may optimize it away.
在这种情况下,测试
本身是包含您所指定的26个字符数组,加上'\\ 0'
终止。该阵列的寿命取决于其中测试
声明,这可能会或可能并不重要。例如,如果你这样做:
In this case, test
itself is an array containing the 26 characters you specified, plus the '\0'
terminator. That array's lifetime depends on where test
is declared, which may or may not matter. For example, if you do this:
char *func(void) {
char test[] = "abcdefghijklmnopqrstuvwxyz";
return test; /* BAD IDEA */
}
来电者将获得一个指针的东西,不再存在。如果需要引用数组,其中测试定义
的范围之内,就可以将其定义为静态
,或者您可以使用分配它的malloc
:
the caller will receive a pointer to something that no longer exists. If you need to refer to the array outside the scope in which test
is defined, you can define it as static
, or you can allocate it using malloc
:
char *test = malloc(27);
if (test == NULL) {
/* error handling */
}
strcpy(test, "abcdefghijklmnopqrstuvwxyz";
这样的阵列将继续存在,直到你调用免费()
。非标准的strdup()
函数做这个(它是由POSIX定义,但不是由ISO C)。
so the array will continue to exist until you call free()
. The non-standard strdup()
function does this (it's defined by POSIX but not by ISO C).
请注意仔细的测试
可以是指针或取决于你如何将它声明为数组。如果你通过测试
来一个字符串函数,或者说需要一个的char *
的任何功能,也没关系,但类似 sizeof的测试
将表现得非常不同,这取决于是否测试
是一个指针或数组。
Note carefully that test
may be either a pointer or an array depending on how you declare it. If you pass test
to a string function, or to any function that takes a char*
, that doesn't matter, but something like sizeof test
will behave very differently depending on whether test
is a pointer or an array.
借助 comp.lang.c常见问题是优秀的。第8节涵盖字符和字符串,并质疑8.5分质疑1.32,既解决您的具体问题。第6节涵盖了数组和指针之间的经常混淆的关系。
The comp.lang.c FAQ is excellent. Section 8 covers characters and strings, and question 8.5 points to question 1.32, which addresses your specific question. Section 6 covers the often confusing relationship between arrays and pointers.
这篇关于不能修改的C字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!