不能修改的C字符串 [英] Cannot modify C string

查看:133
本文介绍了不能修改的C字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆