一个数组的地址是如何等于它在C中的值?

在下面的代码中,指针值和指针地址与预期不同。

但数组值和地址不!

这怎么可能?

产量

my_array = 0022FF00 &my_array = 0022FF00 pointer_to_array = 0022FF00 &pointer_to_array = 0022FEFC 
 #include <stdio.h> int main() { char my_array[100] = "some cool string"; printf("my_array = %p\n", my_array); printf("&my_array = %p\n", &my_array); char *pointer_to_array = my_array; printf("pointer_to_array = %p\n", pointer_to_array); printf("&pointer_to_array = %p\n", &pointer_to_array); printf("Press ENTER to continue...\n"); getchar(); return 0; } 

数组的名称通常是数组的第一个元素的地址,所以array&array的值是相同的(但是不同的types,所以如果数组大于1, array+1&array+1相等)元素长)。

有两个例外:当数组名称是sizeof或一元& (地址 – )的操作数时,名称引用数组对象本身。 因此sizeof array给你的是整个数组的字节大小,而不是指针的大小。

对于定义为T array[size] ,它将具有typesT * 。 当/如果你增加它,你到达数组中的下一个元素。

&array求值到相同的地址,但给定相同的定义,它会创build一个types为T(*)[size]的指针,即它是一个指向数组的指针,而不是单个元素。 如果你增加这个指针,它将增加整个数组的大小,而不是单个元素的大小。 例如,用这样的代码:

 char array[16]; printf("%p\t%p", (void*)&array, (void*)(&array+1)); 

我们可以期望第二个指针比第一个大16(因为它是16个char的数组)。 由于%p通常以hex转换指针,因此可能如下所示:

 0x12341000 0x12341010 

这是因为数组名my_array )不同于指向数组的指针。 它是数组地址的别名,其地址被定义为数组本身的地址。

然而,指针是堆栈上的一个普通的Cvariables。 因此,你可以把它的地址从它所保存的地址中得到一个不同的值。

我在这里写了这个话题 – 请看看。

在C中,当你在一个expression式中使用一个数组的名称(包括将它传递给一个函数),除非它是( & )的运算符或sizeof运算符的操作数,它会衰减到一个指向它的第一个元件。

也就是说,在大多数情况下, array在数据types和数值上都等同于&array[0]

在你的例子中, my_arraytypes为char[100] ,当你将它传递给printf的时候它会衰减到char*

&my_arraytypes是char (*)[100] (指向100个char数组)。 因为它是&的操作数,所以这是my_array不会立即衰减到第一个元素的指针的情况之一。

指向数组的指针与指向数组第一个元素的指针具有相同的地址值,因为数组对象只是其元素的连续序列,但指向数组的指针的types与指向元素的指针的types不同那个数组。 对两种types的指针进行指针运算时,这一点很重要。

pointer_to_arraytypes为char * – 初始化为指向数组的第一个元素,因为my_array会在初始化expression式中衰减 – 而&pointer_to_arraytypes为char ** (指向char **的指针)。

其中: my_array (衰减到char* ), &my_arraypointer_to_array都直接指向数组或数组的第一个元素,因此具有相同的地址值。

从comp.lang.c FAQ:

  • 那么C中“指针和数组的等价性”是什么意思呢?
  • 由于数组引用衰减为指针,如果arr是一个数组,arr和&arr之间有什么区别?

或者阅读整个数组和指针部分。

当您查看数组的内存布局时,可以很容易地理解为什么my_array&my_array导致相同的地址。

假设您有10个字符的数组(而不是您的代码中的100个)。

 char my_array[10]; 

my_array内存看起来像这样:

 +---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+ ^ | Address of my_array. 

在C / C ++中,数组会衰减到指针,如expression式中的第一个元素

 printf("my_array = %p\n", my_array); 

如果您检查数组的第一个元素的位置,您将看到它的地址与数组的地址相同:

 my_array[0] | v +---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+ ^ | Address of my_array[0]. 

在C语言的前身B语言中,指针和整数是可以自由互换的。 该系统的行为就像所有的内存都是一个巨大的arrays。 每个variables名都有一个全局或相对地址的地址,每个variables名只有编译器必须跟踪的东西是全局variables还是局部variables,以及它的地址是相对于第一个全局variables还是本地variablesvariables。

鉴于像i;这样的全球性声明i; [无需指定types,因为所有东西都是整数/指针]将被编译器处理为: address_of_i = next_global++; memory[address_of_i] = 0; address_of_i = next_global++; memory[address_of_i] = 0;i++这样的语句会被处理为: memory[address_of_i] = memory[address_of_i]+1;

arr[10];这样的声明arr[10]; 将被处理为address_of_arr = next_global; memory[next_global] = next_global; next_global += 10; address_of_arr = next_global; memory[next_global] = next_global; next_global += 10; 。 请注意,一旦声明被处理, 编译器可以立即忘记arr是一个数组 。 像arr[i]=6; 将作为memory[memory[address_of_a] + memory[address_of_i]] = 6;处理memory[memory[address_of_a] + memory[address_of_i]] = 6; 。 编译器不会在乎arr表示一个数组,而i是一个整数,反之亦然。 实际上,它不会在意它们是数组还是两个整数; 它会非常愉快地生成所描述的代码,而不考虑是否可能有用的结果行为。

C程序devise语言的目标之一是在很大程度上与B兼容。在B中,一个数组的名称(在B术语中称为“向量”)标识了一个variables,该variables保存了一个指针,该指针最初被指定指向到给定大小的分配的第一个元素,所以如果这个名字出现在函数的参数列表中,函数将接收到一个指向该向量的指针。 即使C添加了“真实”的数组types,其名称与分配的地址严格相关,而不是最初指向分配的指针variables,将数组分解为指针,使声明Ctypes数组的代码具有相同的行为B代码声明一个向量,然后从来没有修改variables保持其地址。

其实&myarraymyarray都是基地址。

如果你想看到的差异,而不是使用

 printf("my_array = %p\n", my_array); printf("my_array = %p\n", &my_array); 

使用

 printf("my_array = %s\n", my_array); printf("my_array = %p\n", my_array);