在 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型的 这样不就只能返回一个字符了吗