指针创建常量字符串文字,为什么?

时间:2012-11-18 14:37:12

标签: c pointers constants

我正在阅读一些说明

的文档

第一个案例

char * p_var="Sack";     

将创建一个常量字符串文字。

因此像

这样的代码
  p_var[1]="u";             

因为该属性而失败。

<击> 第二种情况

还提到的是,这仅适用于字符文字,而不适用于通过指针的其他数据类型。所以像

这样的代码
float *p="3.14"; 

将失败,导致编译器错误。

但是,当我尝试它时,我没有得到编译器错误,访问它虽然给了我0.000000f(在Ubuntu上使用gcc)。

<击>

关于上述内容,我有三个问题:

  1. 为什么在 First Case 中创建字符串文字是只读的?

  2. 为什么只允许创建字符串文字,而不是像浮点指针那样的其他常量?

  3. <击> 3。为什么第二种情况没有给我编译错误?

    更新

    请丢弃第3个问题和第2个案例。我通过添加引号来测试它。

    由于

4 个答案:

答案 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)

关于你的问题:

  • 为什么在 First Case 中创建字符串文字是只读的?

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数组对象st,其元素用字符串文字初始化。
该声明与以下内容相同:
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
数组的内容是可修改的。另一方面,声明:
char *p = "abc";
使用类型指向char 的指针定义p并将其初始化为指向类型 char 数组的对象,其长度为4,其元素使用字符串文字初始化。如果尝试使用p修改数组的内容,则行为未定义。

根据您的平台和编译器解释为什么它是只读的:

通常字符串文字将被放入“只读数据”部分,该部分以只读方式映射到进程空间(这就是为什么你似乎不允许更改它)。

但是有些平台确实允许,数据段是可写的。

  • 为什么只允许创建字符串文字而不是像float这样的其他常量?和第三个问题。

要创建浮动常量,使用: 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)

  1. 效率
  2. 他们是
  3. 这是一个字符串注意引号

答案 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时,它希望读取浮点值。所以编译器可以看到没有错。