C:分配给指针时数组的行为

C: Behaviour of arrays when assigned to pointers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

main()
{
  char * ptr;

  ptr ="hello";


  printf("%p %s" ,"hello",ptr );

  getchar();

}

嗨,我正在努力清楚地理解数组如何分配给指针。我注意到当你把一个字符数组赋给一个chars-ptr="hello";的指针时,数组就衰减到指针上,但在这种情况下,我要给数组赋一个字符,它不在一个变量内,也不在一个包含变量的变量内",这种分配方式是不是专门为"Hello"取一个内存地址(显然发生了什么),它是不是可以修改"hello"中每个元素的值,它包含在存储该数组的内存地址中。作为比较,我是否可以为一个指针分配一个数组,例如ints,比如thisint_ptr = 5,3,4,3;,值5、3、4、3和"hello"一样位于内存地址中。如果不是,为什么只有字符串才有可能?提前谢谢。


"hello"是字符串文字。它是char [6]类型的无名称不可修改对象。它是一个数组,其行为与其他数组相同。它是无名的事实并没有真正改变任何事情。您可以将它与[]运算符一起使用,例如在"hello"[3]等中。就像其他数组一样,它可以并且将在大多数上下文中衰减到指针。

不能修改字符串文字的内容,因为它在定义中是不可修改的。它可以物理存储在只读存储器中。如果其他字符串文本包含常见的子字符序列,则它可以重叠。

通过复合文字语法,其他数组类型也有类似的功能。

1
int *p = (int []) { 1, 2, 3, 4, 5 };

在这种情况下,右侧是一个类型为int [5]的无名对象,它衰减到int *指针。不过,复合文字是可以修改的,这意味着您可以执行p[3] = 8,从而用8替换4

还可以对char数组和do使用复合文字语法

1
char *p = (char []) {"hello" };

在这种情况下,右侧是一个类型为char [6]的可修改的无名称对象。


首先,您应该阅读comp.lang.c常见问题解答的第6节。

字符串文字"hello"char[6]类型的表达式(5个字符表示"hello",另一个字符表示终止'\0')。它是一个具有静态存储持续时间的匿名数组对象,在程序启动时初始化为包含这6个字符的值。

在大多数上下文中,数组类型的表达式被隐式转换为指向数组第一个元素的指针;例外情况如下:

  • 当它是sizeof的参数时(sizeof"hello"产生6,而不是指针的大小);
  • 当它是EDOCX1(c11的一个新特性)的论点时;
  • 当它是一元&的参数时(&arr产生整个数组的地址,而不是第一个元素的地址;相同的内存位置,不同的类型);以及
  • 当它是初始化数组对象的初始值设定项中的字符串文字时(char s[6] ="hello";复制整个数组,而不仅仅是指针)。

这些例外都不适用于您的代码:

1
2
char *ptr;
ptr ="hello";

所以表达式"hello"被转换为("decays"to)指向上述匿名数组对象的第一个元素('h')的指针。

所以*ptr == 'h',你可以通过内存推进ptr来访问其它字符:'e''l''l''o''\0'。这就是当你给它一个"%s"格式时printf()所做的。

与字符串文字相关联的匿名数组对象是只读的,但不是const。这意味着,任何试图修改该数组或其任何元素的尝试都有未定义的行为(因为标准明确地这么说),但编译器不一定会警告您。(C++使字符串文本EDOCX1为20);在C中做同样的事情会破坏在EDOCX1之前添加的现有代码(20加法被添加到语言中)。因此,不,你不能修改EDOCX1×0的元素——或者至少你不应该尝试。为了使编译器在您尝试时发出警告,您应该将指针声明为const

1
2
const char *ptr; /* pointer to const char, not const pointer to char */
ptr ="hello";

(GCC有一个选项,-Wwrite-strings,使其将字符串文本视为const。这将导致它警告某些C代码在标准方面是合法的,但这些代码可能应该修改为使用const


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

main()
{
   char * ptr;

   ptr ="hello";

  //instead of above tow lines you can write char *ptr ="hello"

   printf("%p %s" ,"hello",ptr );

   getchar();

}

这里您已经将字符串文字"hello"分配给ptr,这意味着字符串文字存储在只读内存中,因此您不能修改它。如果声明char ptr[] ="hello";,则可以修改数组。


说什么?

您的代码分配了6个字节的内存,并用值"h"、"e"、"l"、"l"、"o"和"0"对其进行初始化。

然后它分配一个指针(指针的字节数取决于实现),并将指针的值设置为前面提到的5个字节的开头。

可以使用诸如ptr[1] = 'a'之类的语法修改数组的值。

在语法上,字符串是一种特殊情况。因为C没有特定的字符串类型,所以它提供了一些快捷方式来声明它们等等。但您可以轻松地创建与使用int的字符串相同类型的结构,即使语法必须稍有不同。