为什么在C语言中,数组的地址等于其值?

13 浏览
0 Comments

为什么在C语言中,数组的地址等于其值?

在下面的代码片段中,指针的值和地址如预期般不同。但是数组的值和地址却不同!这是怎么回事呢?

输出:

my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC

#include 
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;
}

0
0 Comments

在C语言中,当你在表达式中使用数组的名称(包括将其传递给函数)时,除非它是地址运算符(&)或sizeof运算符的操作数,否则它会退化为指向其第一个元素的指针。

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

在你的示例中,my_array的类型是char[100],当你将其传递给printf函数时,它退化为char*类型。

&my_array的类型是char (*)[100](指向100个char的数组的指针)。由于它是&的操作数,所以这是my_array不会立即退化为指向其第一个元素的指针的情况之一。

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

pointer_to_array的类型是char * - 初始化为指向数组的第一个元素,因为这是my_array在初始化表达式中退化后的结果 - 而&pointer_to_array的类型是char **(指向char指针的指针)。

其中:my_array(在退化为char*之后)、&my_arraypointer_to_array都直接指向数组或数组的第一个元素,因此具有相同的地址值。

在C语言中,数组的地址等于其值的原因是因为数组在表达式中会退化为指向其第一个元素的指针。如果你想要获取数组的地址而不是其第一个元素的地址,你可以使用&运算符。此外,当你对数组指针和元素指针进行指针运算时,需要注意它们的不同类型。

0
0 Comments

在C语言中,数组名与指向数组的指针是不同的。数组名是数组地址的别名,其地址定义为数组本身的地址。

指针是堆栈上的普通C变量。因此,您可以获取其地址并从内部获取与其所持有的地址不同的值。

我在这里写了关于这个主题的文章-请看一下。

&my_array不应该是一个无效的操作吗?因为my_array的值并不在堆栈上,只有my_array[0...length]在堆栈上。然后这一切都会有意义...

- 我其实不知道为什么允许这样做。

您可以获取任何变量的地址(如果没有标记为register),无论其存储持续时间是静态、动态还是自动的。

my_array本身在堆栈上,因为my_array就是整个数组。

- 数组肯定在堆栈上,但my_array产生的是第一个元素的内存地址。这个内存地址存储在哪里?如果它是一个指针(char *),它将存储在堆栈上,但是在my_array的情况下,内存地址存储在哪里?如果堆栈中有|000|001|002|...|099|,其中每个都是与数组元素的int值对应的内存槽,编译器是否保留另一个槽来指示第一个元素在内存中的确切位置?

当my_array不是&或sizeof运算符的主题时,它被计算为指向其第一个元素的指针(即&my_array[0])-但my_array本身不是该指针(my_array仍然是数组)。该指针只是一个短暂的右值(例如,给定int a;,它就像a + 1一样)-至少在概念上,它是"按需计算的"。my_array的真正"值"是整个数组的内容-只是在C中确定这个值就像试图将雾气装进罐子里一样困难。

my_array是数组的名称。它不是"数组地址的别名"。由于my_array表示一个数组,因此定义my_array的地址与定义int x;时的&x是一样的。数组是堆栈变量(在这种情况下-当然,您可以使它们静态等等),因此您可以以与获取int的地址相同的方式获取其地址。

感谢详细的博客文章。但是您遗漏了一件事:我可以想象出对数组指针的完全正常的用途。它是为了在类型系统中对数组的大小进行编码。我认为这主要是为了人类读者,但还有更多内容:如果您尝试传递不同大小的数组指针,编译器会警告您,如"expected ‘int (*)[5]’ but argument is of type ‘int (*)[4]’"。

0
0 Comments

在C语言中,数组的名称通常会被解析为数组的第一个元素的地址,因此array和&array具有相同的值(但是不同的类型,所以如果数组的长度大于1个元素,则array+1和&array+1将不相等)。

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

对于定义为T array[size]的数组,它将具有类型T *。当/如果你对它进行递增操作,你将进入数组的下一个元素。

&array会计算出相同的地址,但是给定相同的定义,它将创建一个类型为T(*)[size]的指针 - 也就是指向数组而不是单个元素的指针。如果你对这个指针进行递增操作,它会添加整个数组的大小,而不是单个元素的大小。例如,使用如下代码:

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

我们可以预期第二个指针比第一个指针大16(因为它是一个由16个char组成的数组)。由于%p通常将指针转换为十六进制,所以可能看起来像这样:

0x12341000    0x12341010

是的,对每个指针添加1会得到不同的结果。你知道每个指针属于哪种类型吗?

:&array是指向数组的第一个元素的指针,而array指的是整个数组。通过比较sizeof(array)和sizeof(&array),可以观察到根本的区别。然而需要注意的是,如果你将数组作为参数传递给函数,实际上只有&array被传递。除非数组被封装在struct内部,否则无法按值传递数组。

:如果将数组传递给函数,它会退化为指向其第一个元素的指针,因此实际上传递的是&array[0],而不是指向数组的指针。这可能是一个小问题,但我认为这一点很重要要明确;如果函数具有与传递的指针类型匹配的原型,编译器将发出警告。

Bailey:公平地说,这有点迂腐,因为数组的地址和数组的第一个元素的地址是相同的地址,即使语义上有所不同。

Coffin:例如int *p = &a,如果我想要int指针p的内存地址,我可以使用&p。因为&array转换为整个数组的地址(从第一个元素的地址开始)。那么我如何找到数组指针的内存地址(它存储数组第一个元素的地址)?它一定存在于内存中的某个地方对吗?

:不,没有必须在内存中存储指向数组的指针。如果你创建一个指针,然后可以取它的地址:int *p = array; int **pp = &p;。

谢谢。我在一本C语言书中读到过一句话。它说:“当你创建一个指针变量时,计算机会分配4或8字节的空间来存储它。但是如果你创建一个数组怎么办?计算机会分配空间来存储数组,但不会分配任何内存来存储数组变量。编译器只是将数组的起始地址插入其中。”

:这句话没有太多意义。你知道“它不会分配任何内存来存储数组变量”是什么意思吗?也许“变量”这个词在某种奇怪的方式上被使用了。

我认为这个答案没有在静态分配的数组的上下文中解释为什么只有在静态分配的数组中才会出现variable == &variable的情况。

:没有什么需要解释的 - 给定一个局部数组,variable和&variable将给出相同的地址。

FYI,当数组是C11的alignof运算符的操作数时,以及当它是用于初始化char数组的字符串字面量(char [])时,数组不会衰变为指针的两种情况下,它不会衰变为指针。(此外,在C++中,另一个例外是,据我所知,当数组通过引用传递时,但我们这里不讨论C++)。

为什么&(array+1)会导致错误“作为一元'&'操作数需要左值”。array+1不是一个字面值。对这种行为感到困惑。

第一个评论是错误的,为什么还保留它?我认为它可能会导致那些没有阅读下面回复的人产生误解。

0