C++ 指向数组第一个元素的指针的地址?

C++ 指向数组第一个元素的指针的地址?,c++,c,arrays,pointers,C++,C,Arrays,Pointers,我对指向数组开头的指针在内存中的位置有点困惑。据我所知,数组和指针可以使用相同的函数,如*、&和[]。因此,如果我创建一个字符数组,我理解为:buffer==&buffer[0] 所以不带括号的arrayname就像一个指针,它包含数组第一个条目的地址,对吗 但是,当我试图找出指针的地址(存储&buffer[0]的地址)时,它会给我与指针(&arrayname[0])中存储的值相同的值。这怎么可能?虚拟ram中的同一地址如何包含地址和缓冲区[0]的值(其在下面的代码中等于'H') #包括 #包括

我对指向数组开头的指针在内存中的位置有点困惑。据我所知,数组和指针可以使用相同的函数,如*、&和[]。因此,如果我创建一个字符数组,我理解为:buffer==&buffer[0]

所以不带括号的arrayname就像一个指针,它包含数组第一个条目的地址,对吗

但是,当我试图找出指针的地址(存储&buffer[0]的地址)时,它会给我与指针(&arrayname[0])中存储的值相同的值。这怎么可能?虚拟ram中的同一地址如何包含地址和缓冲区[0]的值(其在下面的代码中等于'H')

#包括
#包括
void main(){
字符缓冲区[]=“你好”;
printf(“地址缓冲区:%d\n”,&buffer);
printf(“值缓冲区:%d\n”,缓冲区);
printf(“地址缓冲区[0]:%d\n”,&buffer[0]);
printf(“值缓冲区[0]:%c\n”,缓冲区[0]);
printf(“地址缓冲区[1]:%d\n”,&buffer[1]);
系统(“暂停”);
}
所以基本上我被第一个输出搞糊涂了。它不应该与第二个不同吗?非常感谢你的解释

这是错误的:

printf("Address buffer: %d\n", &buffer);
printf("Value buffer: %d\n", buffer);
假设数组为指针的正确代码如下:

printf("Address buffer: %p\n", (void*) buffer); 
printf("Value buffer: %d\n", *buffer);
您可以将
array[x]
转换为
*(array+x)
,这意味着:

读取数组+其元素大小的x所指向的内存区域


除非它是
sizeof
或一元
&
运算符的操作数,或者是用于初始化声明中另一个数组的字符串文字,否则“T的N元素数组”类型的表达式将转换(“衰减”)为“指向
T
的指针”类型的表达式,表达式的值将是数组第一个元素的地址

假设以下代码:

char buffer[] = "Hello";
...
printf( "%s\n", buffer );
在对
printf
的调用中,表达式
buffer
的类型为“char的6元素数组”;由于它不是
sizeof
或一元
&
运算符的操作数,也不是用于初始化声明中的另一个数组,因此该表达式将转换(“衰减”)为“指向
char
”类型的表达式(
char*
),表达式的值是数组中第一个元素的地址

现在,将
printf
调用更改为

printf( "%p", (void *) &buffer );
这次,
buffer
是一元
&
运算符的操作数;不会自动转换为类型“指向
char
”的指针。相反,表达式
&buffer
的类型是“指向
char
的6元素数组的指针”,或
char(*)[6]
1(括号很重要)

两个表达式产生相同的值——数组的地址与数组第一个元素的地址相同——但两个表达式的类型不同。这很重要<代码>字符*和
字符(*)[6]
不可互换

那么,为什么这种时髦的转换魔法一开始就存在呢

当丹尼斯·里奇最初设计C时,他的设计是基于一种早期的语言B(go figure)。在B中分配数组时,如下所示:

auto arr[N];
编译器将为数组内容留出N个元素,以及存储数组第一个元素偏移量的附加单元格(基本上是指针值,但没有任何类型语义;B是“无类型”语言)。此附加单元格将绑定到变量
arr
,提供如下内容:

          +---+
arr:      |   | --+
          +---+   |
           ...    |
          +---+   |
arr[0]:   |   | <-+
          +---+
arr[1]:   |   |
          +---+
arr[2]:   |   |
          +---+
 ...       ...
          +---+
arr[N-1]: |   |
          +---+
他想要一个2字节的整数,后跟一个14字节的数组;没有一个好地方可以存放指向数组第一个元素的指针

所以他把它扔掉了;他没有为指向数组第一个元素的指针留出存储空间,而是设计了该语言,以便从数组表达式本身计算数组的位置。因此,这篇文章开头的规则是这样的



1.
%p
转换说明符需要一个
void*
表达式作为其相应的参数,因此需要强制转换。

请阅读一本好的C(或C++)编程书籍。他们解释了所有的细节。(基本上,数组可以衰减为指针)。并使用
%p
printf
指针。@BasileStarynkevitch这不是他的要求。要打印出地址,请使用
%p
转换说明符。此处已回答的可能重复项:不,您应该使用
%p
printf
指针(然后最好显式地将它们强制转换为
void*
)抱歉,也许我的输出有点误导:通过“值缓冲区”:我的意思是值缓冲区本身等于,所以在本例中是地址,而不是地址指向的值。哇,你的回答给我留下了深刻的印象,解释得很好,非常感谢你花时间回答。关于整个“从数组表达式计算”事情,你能给我一个关于这一点的链接或名称吗?@user2352375:好吧,你可以从(在线草案)开始;第6.3.2.1节是最相关的。里奇也描述了他是如何开发C。
          +---+
arr:      |   | --+
          +---+   |
           ...    |
          +---+   |
arr[0]:   |   | <-+
          +---+
arr[1]:   |   |
          +---+
arr[2]:   |   |
          +---+
 ...       ...
          +---+
arr[N-1]: |   |
          +---+
struct {
  int inode;
  char name[14];
};