3

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

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

如果这是真的,那么数组变量和第一个元素是不同的。对?

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

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

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

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

4

7 回答 7

8

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

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

于 2012-08-09T13:56:23.970 回答
5

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

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

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

这个C 常见问题解答可能很有用。

于 2012-08-09T13:55:44.303 回答
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'的位置是 address 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;
于 2012-08-09T13:57:10.433 回答
2
char myChar = 'A'
char msg[] = 'ABCDEFGH'

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

msg = &msg[0]

我想这可以帮助你理解。

于 2012-08-09T14:01:18.007 回答
1

这样看:

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

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

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

于 2012-08-09T14:02:13.813 回答
1

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

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

sizeof array通过打印和可以看到一个数组和它的第一个元素是不同的sizeof array[0]

于 2012-08-09T14:32:11.443 回答
1

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

所以,假设声明

int a[10];

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

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

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

  表达式类型衰减为值
  ---------- ---- --------- -----
           a int [10] int * a 的第一个元素的地址
          &a int (*)[10] n/a 数组的地址,即
                                            和第一个地址一样
                                            元素
       &a[0] int * n/a a 的第一个元素的地址
          *a int n/a [0] 的值
    sizeof a size_t n/数组中的字节数
                                            (10 * sizeof (int))
   sizeof &a size_t n/指针中的字节数
                                           一个整数数组
   sizeof *a size_t n/int 中的字节数
sizeof &a[0] size_t n/指向 int 的指针中的字节数

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

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

p和都pa指向 的第一个元素a,我们假设它位于 address 0x8000。执行行后

p++;
pa++;

但是,p指向下一个整数0x8004,假设 4 字节ints),而pa指向下一个10 元素整数数组;即a( 0x8028) 的最后一个元素之后的第一个整数。

于 2012-08-09T14:42:43.060 回答