C指针:数组变量

时间:2012-08-09 13:53:12

标签: c arrays pointers

我在我的书(以及互联网上的许多来源)中读到了这一点:

  

数组变量指向到数组中的第一个元素。

如果是,则数组变量和第一个元素不同。正确?

这意味着通过以下代码,它将产生两种不同的结果:

int main(){
    char msg[] = "stack over flow";
    printf("the store string is store at :%p\n",&msg);
    printf("First element: %p\n",&msg[0]);
}

但是我收到了两个案例的相同结果。所以,通过这个例子,我认为应该说:数组变量第一个元素。 (因为它有相同的地址)

我不知道这是真还是错。请教我。

7 个答案:

答案 0 :(得分:8)

数组变量表示数组占用的整个内存块,而不仅仅是数组的第一个元素。因此array array[0]相同(参见sizeof array / sizeof array[0])。但是数组的第一个元素与数组本身位于相同的内存地址。

说数组指向第一个元素也是不正确的,在大多数情况下,数组表达式衰变为指向其第一个元素的指针,但它们是不同的东西(例如,再次参见sizeof)。 / p>

答案 1 :(得分:5)

他们指向相同的地址,即printf会显示相同的值,但它们的类型不同。

  • &msg的类型是char(*)[16],指向char
  • 的数组16的指针
  • &msg[0]的类型是char *,指向char的指针

测试这个的一种便宜的方法是做一些指针算术。尝试打印&msg + 1

C FAQ可能有用。

答案 2 :(得分:5)

数组变量 整个数组。它衰减成指向数组第一个元素的指针。

如果你看一下类型:

  • msg的类型为char [16]
  • &msg的类型为char (*)[16]
  • &msg[0]的类型为char *

因此,在msg可以衰减到数组的上下文中,例如作为参数传递时,其值将等于&msg[0]

让我画出这个:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|s|t|a|c|k| |o|v|e|r| |f|l|o|w|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+

想象一下这个数组的起点,'s'所在的地址是地址0x12345678

  • msg本身,指的是整个16字节的内存。就像你说int a;时一样,a指的是4个字节的内存。
  • msg[0]是该16个字节的第一个字节。
  • &msg是数组开始的地址:0x12345678
  • &msg[0]是数组的第一个元素的地址:0x12345678

这就是为什么&msg&msg[0]的值相同,但它们的类型不同。

现在问题是,msg本身并不是头等公民。例如,您无法分配数组。这就是为什么在大多数情况下,数组会衰减到它的指针。

如果你知道函数指针,这非常相似:

int array[10];
int function(int);
  • int *var = array中,array衰减到指针(&array
  • void *var = function中,function衰减到指针(&function

注意,在函数指针的情况下,我们喜欢保留类型,所以我们写:

int (*var)(int) = function;

同样,您可以使用数组:

int (*var)[10] = array;

答案 3 :(得分:2)

char myChar = 'A'
char msg[] = 'ABCDEFGH'

当您输入 myChar 时,您会获得价值。 但是使用 msg ,您将获得指向第一个字符的指针(对于必须使用msg [x]的值)

msg = &msg[0]

我认为这可以帮助你理解。

答案 4 :(得分:1)

这样看:

&msg = 0x0012
&msg[0] = 0x0012
&msg[1] = 0x0013

在这种情况下,&msg[1]指向msg+1。当您引用&msg&msg[0]时,您指的是相同的内存地址,因为这是指针开始的位置。增加数组变量会使指针增加+1,因为char变量的大小只有1个字节。

如果你用一个整数做同样的技巧,你会将指针增加+4个字节,因为整数是4个字节。

答案 5 :(得分:1)

使用数组表达式时,编译器会将其转换为指向第一个元素的指针。这是由1999 C标准在6.3.2.1中指定的显式转换3.这对您来说很方便,因此您不必编写&array[0]来获取指向第一个元素的指针。

转换发生在所有表达式中,除非数组表达式是sizeof或一元&的操作数,或者是用于初始化数组的字符串文字。

通过打印sizeof arraysizeof array[0],您可以看到数组及其第一个元素不同。

答案 6 :(得分:1)

在大多数情况下,数组类型的表达式(“T的N元素数组”)将被/转换为/“decay”替换为指针类型的表达式(“指向T”的指针),表达式的将是数组中第一个元素的地址。

所以,假设声明

int a[10];

表达式a的类型是“int”的10个元素数组,或int [10]。但是,在大多数情况下,表达式的类型将转换为“指向int”或int *的指针,表达式的值将等同于&a[0]

此规则的例外情况是数组表达式是sizeof或一元&运算符的操作数,或者是用于初始化声明中另一个数组的字符串文字。

因此,根据我们上面的声明,以下所有内容都是正确的:

  Expression   Type         Decays to     Value
  ----------   ----         ---------     -----
           a   int [10]     int *         address of the first element of a
          &a   int (*)[10]  n/a           address of the array, which is the
                                            same as the address of the first
                                            element
       &a[0]   int *        n/a           address of the first element of a
          *a   int          n/a           value of a[0]
    sizeof a   size_t       n/a           number of bytes in the array 
                                            (10 * sizeof (int))
   sizeof &a   size_t       n/a           number of bytes in a pointer to 
                                           an array of int
   sizeof *a   size_t       n/a           number of bytes in an int
sizeof &a[0]   size_t       n/a           number of bytes in a pointer to int

请注意,表达式a&a&a[0]都具有相同的a的第一个元素的地址) ,但类型不同。类型很重要。假设如下:

int a[10];
int *p = a;
int (*pa)[10] = &a;

ppa都指向a的第一个元素,我们假设它位于地址0x8000。执行行

p++;
pa++;

但是,p指向下一个整数0x8004,假设为4字节int s),而pa指向next 10个元素的整数数组;也就是说,a0x8028)的最后一个元素之后的第一个整数。