没有任何地址规范的字符指针如何保存数据?

时间:2017-04-11 09:11:41

标签: c string pointers char string-literals

以下C程序不应该通过我对指针的理解而起作用,但确实如此。

#include<stdio.h>
main() {
    char *p;
    p = "abcdefghijk";
    printf("%s", p);
}

输出:

  

ABCDEFGHIJK

char指针变量p指向一些随机的东西,因为我没有为p = &i;分配任何地址,其中i是一些char数组。

这意味着如果我尝试将任何内容写入指针p所持有的内存地址,它应该给我分段错误,因为它是一些未被OS分配给我的程序的随机地址。

但程序编译并成功运行。发生了什么事?

5 个答案:

答案 0 :(得分:4)

在此表达式声明中

p="abcdefghijk";

指针p被赋予字符串文字"abcdefghijk"的第一个字符的地址,编译器将其存储为静态存储区中的以零结尾的字符数组。

因此,在本声明中,有两件事情发生。首先,编译器创建一个带有静态存储持续时间的未命名字符数组,以保存字符串文字。然后将数组的第一个字符的地址分配给指针。您可以通过以下方式想象它

char unnamed[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', '\0' };
p = unnamed;

p = &unnamed[0]; 

考虑到虽然C中的字符串文字具有与C ++相反的非常量字符数组类型,但它们具有常量字符数组的类型,但您可能不会更改字符串文字。任何更改字符串文字的尝试都会导致未定义的行为。

因此,此代码段无效

char *p = "abcdefghijk";
p[0] = 'A';

但是您可以创建自己的字符数组,使用字符串文字初始化它,在这种情况下,您可以更改数组。例如

char s[] = "abcdefghijk";
char *p = s;
p[0] = 'A';

来自C标准(6.4.5字符串文字)

  

7没有特别说明这些阵列是否与它们不同   元素具有适当的值。如果程序试图   修改这样的数组,行为是未定义的。

注意报价的这一部分

  

没有特别说明这些阵列是否与它们不同   元素具有适当的值。

这意味着,例如,如果你要写

char *p = "abcdefghijk";
char *q = "abcdefghijk";

然后该表达式不必产生true(整数值1)

p == q

,结果取决于编译器选项,无论相同的字符串文字是作为一个数组存储还是作为不同的数组存储。

答案 1 :(得分:2)

在C中,像"abcdefghijk"这样的字符串文字实际上存储为(只读)字符数组。赋值使p指向该数组的第一个字符。

我注意到你提到p = &i其中i是一个数组。在大多数情况下,这是错误的。数组自然地衰减指向它们的第一个元素。即执行p = i将等于p = &i[0]

虽然&i&i[0]都会产生相同的地址,但它在语义上却非常不同。让我们举一个例子:

char array[10];

如上所述,上面的定义是&array[0](或只是普通的array,如上所述),您会得到指向char的指针,即char *。在执行&array时,您会得到一个指向十个字符数组的指针,即char (*)[10]。这两种类型非常不同。

答案 2 :(得分:0)

p="abcdefghijk";

您正在代码段中创建一个字符串文字并将该文字的第一个字符的地址分配给指针,并且由于指针不是常量,您可以使用不同的地址再次分配它。

答案 3 :(得分:0)

字符串文字"abcdefghijk"是通过将字符放在程序的数据文本段中的块中来编译的。然后,将它分配给指针会将其在数据段中的位置地址分配给指针。

答案 4 :(得分:0)

"abcdefghijk"是一个字符串常量,p="abcdefghijk";将为此字符串的p地址提供。 所以printf("%s",p);显示此字符串没有错误是正常的。