结构数组成员地址问题

structure array member address problems

#include<stdio.h>

struct Book {
    char * name;
    int page;
};

void demo(struct Book bookArr[]);

int main(){
    struct Book bookArr[] = {{"c struct",1},{"c struct",2}};
    printf("bookArr address from main: %p\n",&bookArr);
    printf("bookArr[0] address from main: %p\n",&bookArr[0]);
    demo(bookArr);
    return 0;
}

void demo(struct Book bookArr[]){
    printf("bookArr address from demo: %p\n",&bookArr);
    printf("bookArr[0] address from demo: %p\n",&bookArr[0]);
}
The output: 
bookArr address from main: 0x1040bb350
bookArr[0] address from main: 0x1040bb350
bookArr address from demo: 0x1040bb328
bookArr[0] address from demo: 0x1040bb350
Program ended with exit code: 0

demo中的bookArr在启动时复制了main中的bookArr,所以我能理解为什么两个函数的bookArr地址不同,但我不能理解为什么两个函数的bookArr[0]地址相同.演示不是已经分配了完整的 BookKarr 吗? bookArr[0] 和 bookArr[1] 都是指针吗?但事实并非如此

main函数中的bookArr是数组

表达式中的大多数数组会自动转换为指向其第一个元素的指针,但一元 & 运算符的操作数是其中的一个例外。

通常情况下,数组的位置及其第一个元素在内存中的地址相同。 (数组中第一个元素之前没有多余的space。)

bookArr[0]bookArr[1] 不是指针而是结构(struct Book`)。

事实上,只有一个 Book 数组存在,并且两个函数都引用同一个数组。但是,每个函数都通过不同的局部变量访问该数组。

在任一函数中,&bookArr 都不是数组开始的地址。它是 局部变量 的地址,它保存指向数组开头的指针。

如果你要打印 bookArr 本身,它本身就是一个指针,你会看到它们都指向相同的内存位置。

对于初学者来说,考虑一个简单的例子:

#include <stdio.h>

void f( int *px )
{
    printf( "in f &( *px ) = %p\n", ( void * )&( *px ) );
    
}
int main(void) 
{
    int x = 10;
    
    printf( "in main &x    = %p\n", ( void * )&x );
    
    f( &x );
    
    return 0;
}

程序输出可能如下所示:

in main &x    = 0x7ffccc31de34
in f &( *px ) = 0x7ffccc31de34

也就是说,变量 x 通过指向它的指针通过引用传递给函数 f。

取消引用函数 *px 中的指针,您可以直接访问存储变量 x 的内存。变量 x 本身没有传递给函数。它是指向已传输变量的指针。

因此使用表达式 &( *px )&( px[0] ) 或只是 px 你将在 main 中获得原始变量 x 的地址。

当您传递数组时,它会隐式转换为指向其第一个元素的指针。另一方面,具有数组类型的函数参数也被调整为指向数组元素类型的类型指针。

也就是这个函数声明:

void demo(struct Book bookArr[]);

相当于:

void demo(struct Book * bookArr);

所以数组本身并没有被复制到函数中。它是指向传递给函数的第一个元素的指针。

所以参数bookArr的值得到的是数组第一个元素的地址。事实上,参数 bookArr 获取表达式 book &bookArr[0] 的值,其中 bookArr 在 main 中声明。所以实际上在 main 中声明的数组的所有元素都通过引用传递给函数,因为使用指针算法你可以获得数组中每个元素的地址。即bookArr是数组第一个元素的地址 *表达式你也可以这样写 &bookArr[0]), bookArr + 1 是数组第二个元素的地址,依此类推

注意这个调用中的main

 printf("bookArr address from main: %p\n",&bookArr);

表达式 &bookArr 没有类型 struct Book *。它的类型为 struct Book ( * )[2] 因为在 main 中你有一个数组。另一方面,在函数演示中,bookarr 的类型为 struct Book *(由于将参数调整为指向数组元素类型的指针),表达式 &bookArr 的类型为 struct Book ** 并产生参数的地址(本地函数的变量)。