在 C 中初始化一个 char 指针。为啥被认为是危险的? [复制]

Posted

技术标签:

【中文标题】在 C 中初始化一个 char 指针。为啥被认为是危险的? [复制]【英文标题】:Initializing a char pointer in C. Why considered dangerous? [duplicate]在 C 中初始化一个 char 指针。为什么被认为是危险的? [复制] 【发布时间】:2012-02-06 09:50:45 【问题描述】:

可能重复:What is the difference between char s[] and char *s in C?

我初始化了一个char指针:

char *a="test";

我在某些地方读到这被认为是只读,而且很危险。

这是否意味着"test" 没有在堆中分配空间?这是否意味着字符串“test”可以稍后在程序中被覆盖?

---扩展我的问题---

如果我像上面那样初始化了a,然后我做了一堆其他的初始化,比如:

int b=20;
char c[]="blahblahblah";

内存中的“test”可以被“20”或“blah”覆盖吗?还是这种情况没有根据?

【问题讨论】:

想象一下,如果你能做到int *i=&1;。现在,如果您执行*i=2;,您正在尝试更改一个常量。哎哟。 【参考方案1】:

这是危险的,因为字符串是不可修改的。尝试这样做会导致未定义的行为

所以最好这样做:

const char *a = "test";

您是正确的,在这种情况下"test" 没有分配在堆或堆栈上*,而是位于不可修改的静态内存中。

*标准没有提到堆栈或堆,尽管它通常是这样实现的。

另一方面:

char a[] = "test";

修改是安全的,因为它只是以下的缩写:

char a[] = 't','e','s','t','\0';

这是一个普通的可修改数组。

【讨论】:

还有char *a="hello"; char *b="hello";在某些平台上,a==b,在某些a!=b上。所以改变一个,如果成功,可能会也可能不会改变另一个。允许但不要求实现合并相同的字符串常量。 @DavidSchwartz 这很好。我从来没有想过字符串池会发生什么。 旧的 Fortran 实现让您意外更改 文字常量 的值,例如 5 但是如果设置了大小就可以了? char a[5] = "test"; ? 我们可以将单个字符连接成字符串数组中的字符串吗?还是它仍然不可修改?【参考方案2】:

C 程序中的文字字符串被认为是只读的,编译器/链接器/加载器可能会将该字符串的内存安排在防止写入的内存中。

根据您的编译器和操作系统,以下可能会触发运行时错误:

char *a = "test";
a[0] = 'T';

当然,如果您实际上并没有尝试更改字符串数据,那么这样做本身并不危险。但是,让编译器通过声明指针 const 来帮助您确保这一点很有用:

const char *a = "test";

使用此声明,尝试a[0] = 'T' 将是一个编译错误,因此会比运行时更快地检测到。

【讨论】:

【参考方案3】:

"test" 这样的字符串文字是只读的,因此不能修改。因此,任何修改它们的尝试都会导致未定义的行为。

例如:

char *a = "test";
*a = 'b';

*a = 'b'; 是未定义的行为。

所以如果你想修改它们那么你需要使用一个数组

char a[]="test";

因此您可以通过执行以下操作将“测试”修改为“最佳”:

a[0] = 'b';

【讨论】:

【参考方案4】:

尝试修改字符串文字的内容将调用未定义的行为(意味着从段错误到代码按预期工作的任何事情);最好始终假设字符串文字是不可写的。

因此,正如所写,a 不应成为任何试图修改其指向的字符串的函数的目标。

** 编辑 **

C 语言的定义没有提到堆栈或堆。它指定对象的生命周期和可见性,并由实现将其映射到特定的体系结构和内存模型。必须分配字符串文字,以便它们在程序的生命周期内可用。几种常见的架构将它们放在只读数据段中;有些人将它们放在可写的数据段中。有些允许您在编译时选择哪个。

【讨论】:

【参考方案5】:

所有字符串文字都是只读的,即使它们的类型可能没有这样说。字符串文字的类型是 char[],(例如,"Hello" 的类型是 char[6]'\0' 字符的类型是额外的)。虽然它不是const-qualified,但该标准在 §6.4.5/6 中说明了以下内容:

…如果程序试图修改这样的数组,行为是 未定义。

如果你想要一个可变版本,你必须复制一个字符串,或者像这样声明它:

char a[] = "test";

【讨论】:

【参考方案6】:

Exactly.

例如,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 将存储在数据段中

【讨论】:

【参考方案7】:

我在某些地方读到这被认为是只读的并且很危险。

字符串字面量确实是只读的。

这是否意味着“测试”没有在堆中分配空间?

标准没有规定是否为字符串分配空间。它通常在程序的静态部分,但标准甚至没有提到堆。

这是否意味着字符串“test”可以稍后在程序中被覆盖?

重写字符串是未定义的行为。

【讨论】:

以上是关于在 C 中初始化一个 char 指针。为啥被认为是危险的? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C语言指针初学者 请帮我看看下面的提 为啥调用函数返回值是char型的 这样不就只能返回一个字符了吗

为啥使用三元运算符进行数组初始化是非法的?

为啥 argv[argc] 是指向 NULL 的指针?

c语言char和int可以互相赋值,但指针不能赋值,char *和int *不能直接赋值,为啥呢?谢谢

C语言指针赋值?

数组名相当于一个指针,哪数组指针char *p[],不就变成一个二级指针?