我决定回到 SI 去读 K&R 的书,我又一次被指针这个话题绊倒了,逻辑上似乎一切都清楚了,但就是这样有char *
一些const char *
问题。
给个代码,说明个个我都不清楚!
示例 1:
char *pstr = "Hello, world";
*pstr = 'D'; /// При запуске приложения на этом месте вылетит сбой не понятно!
printf(pstr); /// Ну и конечно ничего не выведет, измененную строку я не получу, ой точнее массив из символов
示例 2:
const char *pstr = "Hello, world";
*pstr = 'D'; /// Сбоя не будет и программа вообще не скомпилируется т.к компилятор сообщит что мы не можем изменять наш константный объект
printf(pstr); /// До сюда дело не дойдет
示例 3:
char str[] = "Hello, world";
char *pstr = str;
*pstr = 'D'; /// Все ок мы успешно поменяем наш первый элемент массива
printf(pstr); /// Мы получим это: "Dello, world"
让我们划清所有这些示例:为什么我不能在第一个示例中分别更改每个文字?(我没有像第二个例子那样声明对象常量)
PS第三个例子是给大图看的,如果你输入一个额外的参数,一切正常
在第一种和第二种情况下,您直接使用字符串文字。
在 C 中,您无法控制字符串文字的类型 const 限定。此 const 限定由语言唯一定义。C 中字符串文字的类型是
char [N]
. 尽管字符串文字的类型在技术上不包含限定符const
,但字符串文字仍然是不可变(不可修改)的对象。尝试修改字符串文字,就像任何其他不可修改的对象一样,会导致未定义的行为。你如何声明你的指针
pstr
- 有const
或没有 - 对字符串文字的类型和属性没有影响。您的指针本身与字符串文字无关。您的指针只不过是对真实对象的访问路径。访问路径的恒定性只不过是自律的一个要素,通常与该路径所通向的对象的恒定性无关。C 语言为您提供了合法创建可修改对象的常量访问路径和不可修改对象的非常量访问路径的方法。最终,对象合法修改的可能性仅由对象本身的可修改性精确确定,而不以任何方式取决于访问路径的常量(因为后者很容易消除)。
鉴于文字是不可变对象,使用非常量指针(如第一个示例)指向字符串文字没有任何意义,即使语言正式允许也是如此。
在第三个选项中,您不直接使用字符串文字,而是创建自己的可修改数组,该数组仅使用字符串文字的值进行初始化。那些。您的数组包含字符串文字值的独立副本。这是您自己的数组,您可以随意修改它。
根据C语言标准(6.4.5 String literals)
也就是说,您不能更改字符串文字,即使它们具有非常量字符数组类型。C 字符串文字具有非常量数组类型的事实是为了 C 程序的向后兼容性。
因此,在本提案中
用作指针初始值设定项的字符串文字
pstr
被隐式转换为 类型的指针char *
,而不是指向const char *
文字第一个字符的类型的指针。在 C++ 中,字符串文字具有常量字符数组的类型,这避免了混淆。
在第三个例子中
指针
pstr
不再处理字符串文字,而是处理用户定义的字符数组。字符串文字仅用于用自己的字符初始化字符数组的元素。由于数组被声明为非常量,因此可以更改其元素。c的类型安全性不够,并且允许为非常量指针分配字符串文字的地址。左侧的指针不是常量这一事实并不意味着您可以更改它指向的内容。对指针的赋值不会在字符串下创建额外的对象,也不会将右侧复制到其中。
那。您的查看代码:
本质上等同于此(出于演示目的更明显):
在这种形式下,即使是gcc也会报告带有适当的警告:
c标准明确指出,尝试修改字符串文字会导致未定义的行为 (6.4.5/7):
根据定义,字符串文字是 const 。它一般可以放在“只读”存储器中。例如,第一个示例中的 VC++ 将跳过代码,不会出现故障 - 但在执行过程中该行不会更改。