字符串在C中是如何工作的?

字符串在C中是如何工作的?,c,string,c99,ansi-c,C,String,C99,Ansi C,在C编程语言中,字符串被称为常量 因此,当我给出一个类似于char*s=“Hello”的语句时,我了解到s指向一个H的内存位置,因为“Hello”存储在程序的一些静态内存中,而且“Hello”是不可变的 这是否意味着变量s现在是指向常量数据的指针类型的变量,例如const int a=3;常数int*i=&a。这似乎是因为我不能操纵数据(当我这样做时,它会导致分段错误) 但,若确实如此,编译器不应该能够检测并说我已经将合格数据分配给了不合格变量吗。 类似于char*pp是指向非限定字符的指针,当

C编程语言中,字符串被称为常量

因此,当我给出一个类似于
char*s=“Hello”
的语句时,我了解到
s
指向一个H的内存位置,因为“Hello”存储在程序的一些静态内存中,而且
“Hello”
是不可变的

这是否意味着变量
s
现在是指向常量数据的指针类型的变量,例如
const int a=3;常数int*i=&a。这似乎是因为我不能操纵数据(当我这样做时,它会导致分段错误)

但,若确实如此,编译器不应该能够检测并说我已经将合格数据分配给了不合格变量吗。 类似于
char*p
p是指向非限定字符的指针,当我说
char*p=“Hello”
p时,指向非限定字符的指针不能指向常量字符类型

我错过了什么

如果不是上述情况,那么如何使常量字符数组不可变?

语法
char*s=“Hello”const
关键字不是C规范的一部分时,代码>就出现了。后来,它保留了反向兼容性。写入此类
s[i]
将导致未定义的行为。(在您的案例中观察到的Seg故障持续了几次)

此行为(从字符串文字或代码> const char []/COD>到非常量 char */COD>)在C++中被简单地支持直到C++ 11,然后被弃用。 C中的类型安全性是有限的。

首先,C中的字符串不是不可变的。C甚至不知道字符串的类型——字符串只是定义为以
'\0'
结尾的
字符序列

您所说的是字符串文本,它们可以是不可变的。C标准定义试图修改字符串文字是未定义的行为,但其类型仍然是
char*
。因此,如果您确信在C的实现中,字符串文本是可写的,那么您可以这样做!*)

但是,您的代码将不再是定义良好的C语言,并且无法在具有只读字符串文本的其他平台上工作。它将被编译,因为通过
char*
进行编写是非常好的,但在运行时会以不可预知的方式失败(比如,可能会发生崩溃)

因此,对于可移植代码来说,最好只将字符串文本分配给
const char*
指针,如果需要可变字符串,则将字符串文本用作
char[]
的初始值设定项



*)请注意,这是非常不常见的,现在只有针对嵌入式或非常旧的平台的专门编译器才能发现这一点。现代平台将字符串文本置于只读数据段或类似数据段中。

您看过标准文档吗?您真的应该下载然后阅读该规范。顺便说一句,ansi-c(甚至C99)是过时的标准。
变量s
不是常量(除非另有说明),您仍然可以使用它指向其他位置<代码>“Hello”
存储在程序的
数据部分
中,这就是为什么它是不可变的。“在C++11之前是短暂的”?那将是22年左右。你认为长时间是什么?)即使您确信字符串文本在实现中是可变的,但对其进行变异仍然是未定义的行为,所以您不能这样做。类似地,您可以确定您的实现不会捕获算术溢出——事实上,GCC被记录为不捕获——但编译器仍然可以产生令人惊讶的结果。看看您是否相信这是一个“UB技巧”,事实是编译器可能会将布尔值
x
常数折叠到
1
,即使它会对
x
的特定值求值为
0
,因为在UB的情况下它只会求值为
0
。类似地,如果编译器知道
char*p
的值是指向字符串文本的指针,那么它可以选择不编译
*p='a'它甚至可以选择不在该基本块中编译以下代码,前提是程序员必须已经做了一些事情来保证UB不会发生。您有参考您所指的现实吗?也就是说,一个使字符串文本可变的编译器?如果不是,那都是理论上的,不是吗?如果是这样,你怎么知道编译器永远不会获得我所说的那种优化?当GCC获得这些优化时,Linux作者和其他人当然感到惊讶,他们有理由相信他们的平台不会捕获整数溢出。不管怎么说,我就是这么想的。@rici例如,使用命令行选项
--可写字符串
就可以保证这一点。我仍然编辑了答案,以使依赖这些东西的警告更加明确。但实际上,UB并不意味着“你不能那样做”,它只是意味着“你的代码不是定义良好的C,所以很容易被破坏”。