在C中初始化一个char指针。为什么认为危险?
可能重复:
C中的char s []和char * s有什么区别?
我初始化一个char
指针:
char *a="test";
我在某些地方读到这被认为是只读的 ,这很危险。
这是否意味着"test"
没有在堆中分配空间? 这是否意味着字符串“test”可以在程序中稍后写入?
—扩大我的问题—
如果我已经初始化a
如上所述,然后我做了一堆其他的初始化,如:
int b=20; char c[]="blahblahblah";
内存中的“测试”是否会被“20”或“blah”覆盖? 或者这种情况没有根据?
这很危险,因为字符串不可修改。 尝试这样做会导致未定义的行为 。
所以最好这样做:
const char *a = "test";
你是正确的,在这种情况下, "test"
没有在堆或堆栈*上分配,而是位于不可修改的静态内存中。
*标准对堆栈或堆没有任何说明,尽管它通常是如何实现的。
另一方面:
char a[] = "test";
可以安全修改,因为它只是简短forms:
char a[] = {'t','e','s','t','\0'};
这是一个普通的可修改数组。
C程序中的文字字符串被认为是只读的,并且编译器/链接器/加载器可以将该字符串的存储器安排在受到保护以防止写入的存储器中。
根据您的编译器和操作系统,以下内容可能会触发运行时错误:
char *a = "test"; a[0] = 'T';
当然,如果你实际上并没有尝试更改字符串数据,那么这样做本身并不危险 。 但是,让编译器通过声明指针const
来帮助您确保这一点很有用:
const char *a = "test";
使用此声明,尝试a[0] = 'T'
将是编译错误,因此将比运行时更快地检测到。
试图修改字符串文字的内容将调用未定义的行为(意味着从段错误到代码按预期工作); 最好总是假设字符串文字是不可写的。
因此,如上所述, a
不应该是尝试修改它所指向的字符串的任何函数的目标。
**编辑**
C语言定义没有提到有关堆栈或堆的任何内容; 它指定了对象的生命周期和可见性,并且由实现将其映射到特定的体系结构和内存模型。 必须分配字符串文字,以便它们在程序的生命周期内可用。 几种常见的体系结构将它们放在只读数据段中; 有些人把它们放在一个可写的数据段中。 有些允许您在编译时选择哪个。
所有字符串文字都是只读的,即使它们的类型可能不是这样。 字符串文字的类型是char[]
,(例如, "Hello"
的类型为char[6]
,一个额外的'\0'
字符)。 虽然它不是合格的,但标准在§6.4.5/ 6中说明如下:
…如果程序试图修改这样的数组,则行为未定义。
如果你想要一个可变版本,你必须制作一个字符串的副本,或者像这样声明它:
char a[] = "test";
究竟。
例如,在C中由
char s[] = "hello world"
定义的字符串和在“main”之外的int debug=1
类的C语句将存储在初始化的读写区域中。 并且像const char* string = "hello world"
这样的C语句使得字符串文字“hello world”存储在初始化的只读区域中,而字符指针变量字符串存储在初始化的读写区域中。 例如:static int i = 10
将存储在数据段中,global int i = 10
将存储在数据段中
我在某些地方读到这被认为是只读的,这很危险。
字符串文字确实是只读的。
这是否意味着“测试”没有在堆中分配空间?
是否分配了字符串的空间不是由标准指定的。 它通常在程序的静态部分,但标准甚至没有提到堆的东西。
这是否意味着字符串“test”可以在程序中稍后写入?
写字符串是未定义的行为。
像"test"
这样的字符串文字是只读的,因此无法修改它们。 因此,任何修改它们的尝试都将导致未定义的行为。
例如:
char *a = "test"; *a = 'b';
*a = 'b';
是一种未定义的行为。
因此,如果要修改它们,则需要使用数组
char a[]="test";
因此,您可以通过执行以下操作将“test”修改为“best”:
a[0] = 'b';