我正在阅读一些说明
的文档第一个案例
char * p_var="Sack";
将创建一个常量字符串文字。
因此像
这样的代码 p_var[1]="u";
因为该属性而失败。
<击> 第二种情况
还提到的是,这仅适用于字符文字,而不适用于通过指针的其他数据类型。所以像
这样的代码float *p="3.14";
将失败,导致编译器错误。
但是,当我尝试它时,我没有得到编译器错误,访问它虽然给了我0.000000f
(在Ubuntu上使用gcc)。
<击> 撞击>
关于上述内容,我有三个问题:
为什么在 First Case 中创建字符串文字是只读的?
为什么只允许创建字符串文字,而不是像浮点指针那样的其他常量?
<击> 3。为什么第二种情况没有给我编译错误? 击>
更新
请丢弃第3个问题和第2个案例。我通过添加引号来测试它。
由于
答案 0 :(得分:5)
前提是错误的:指针不会创建任何字符串文字,既不是只读的也不是可写的。
创建只读字符串文字是文字本身:"foo"
是只读字符串文字。如果将其分配给指针,则该指针指向只读存储器位置。
有了这个,让我们转向你的问题:
为什么在First Case中创建字符串文字是只读的?
真正的问题是:为什么不呢?在大多数情况下,您不希望稍后更改字符串文字的值,因此默认假设是有意义的。此外,您可以通过其他方式在C中创建可写字符串。
为什么只允许创建字符串文字而不是其他常量,如float?
再次,错误的假设。你可以创建其他常量:
float f = 1.23f;
此处,1.23f
文字是只读的。您也可以将其分配给常量变量:
const float f = 1.23f;
为什么Second Case没有给我编译错误?
因为编译器无法检查指针是指向只读内存还是可写内存。考虑一下:
char* p = "Hello";
char str[] = "world"; // `str` is a writeable string!
p = &str[0];
p[1] = 'x';
在这里,p[1] = 'x'
完全合法 - 如果我们事先没有重新分配p
,那将是非法的。检查这一点通常不能在编译时完成。
答案 1 :(得分:1)
关于你的问题:
char *p_var="Sack";
好吧,p_var
被分配了分配给字符串"Sack"
的内存的起始地址。 p_var
内容不是只读的,因为您没有将const
关键字放在C结构中的任何位置。尽管像strcpy或strcat这样操作p_var
内容可能会导致未定义的行为。
引用C ISO 9899:
声明
char s[] = "abc", t[3] = "abc";
定义 plain char数组对象s
和t
,其元素用字符串文字初始化。
该声明与以下内容相同:
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
数组的内容是可修改的。另一方面,声明:
char *p = "abc";
使用类型指向char 的指针定义p
并将其初始化为指向类型 char 数组的对象,其长度为4,其元素使用字符串文字初始化。如果尝试使用p
修改数组的内容,则行为未定义。
根据您的平台和编译器解释为什么它是只读的:
通常字符串文字将被放入“只读数据”部分,该部分以只读方式映射到进程空间(这就是为什么你似乎不允许更改它)。
但是有些平台确实允许,数据段是可写的。
要创建浮动常量,应使用:
const float f=1.5f;
现在,当你做的时候:
float *p="3.14";
你基本上是将字符串文字的地址分配给浮点指针。
尝试使用-Wall -Werror -Wextra
进行编译。你会发现发生了什么。
它有效,因为在实践中,引擎盖下的char *
和float *
之间没有区别。
就好像你写的那样:
float *p=(float*) "3.14";
这是一个明确定义的行为,除非float和char的内存对齐要求不同,在这种情况下会导致未定义的行为(参考:C99,6.3.2.3 p7)。
答案 2 :(得分:0)
答案 3 :(得分:0)
float *p="3.14";
这也是字符串文字!
Why are string literals created in First Case read-only?
不,"sack"
和"3.14"
都是字符串文字,都是只读的。
为什么只允许创建字符串文字而不是其他常量,如float?
如果要创建浮点const,请执行:
const float p=3.14;
Why is Second Case not giving me compiler errors?
您正在使指针p
指向字符串文字。取消引用p
时,它希望读取浮点值。所以编译器可以看到没有错。