二维数组和指针

我有以下代码片段:

char board[3][3] = { {'1','2','3'}, {'4','5','6'}, {'7','8','9'} }; printf("address of board : %p\n", &board); printf("address of board[0] : %p\n", &board[0]); 

两个printf()语句都打印相同的值: 0x0013ff67

  1. 据我所知,board(ie)数组名称代表第一个子arrays(即) board[0]和地址

  2. board[0]表示第一个数组中的第一个元素的地址(即) board[0][0]

为什么我在所有printf()语句中都获得相同的地址? 我希望两种语句都有不同的地址。

我对这些东西很新,并且不理解这种行为。 请赐教。

虽然它是一个2D数组,但在内存中它将表示为线性数组。 所以当你说,板[0] [0]它仍然指向该线性arrays中的第一个元素,因此相同的存储器地址。

据我所知,board(ie)数组名称代表第一个子arrays(即)板[0]的地址

只有在这些背景之外使用board才会出现这种情况

  • 作为&运算符的操作数
  • 作为sizeof操作数

当任何一个适用时,表达式board表示数组并保持数组的类型( char[3][3] )。 将&运算符应用于它会导致获取数组的地址,这当然等于其第一个元素的地址,只是具有不同的类型( char(*)[3][3]而不是char(*)[3] )。 关于arraysboard的情况与第一个子arraysboard[0]

当您在这些上下文之外使用它时,您将获得第一个元素的地址(在您的情况下为子数组)。 该地址不是一个对象,而只是一个值。 值没有地址,但对象有。 试图申请并将其失败。 例如

 // error: trying to apply '&' on something that has no address &(1 ? board : board) 

请注意,上述任何内容均适用于C; 不一定是C ++。

当然这会打印相同的地址。
想想像这样的2Darrays一分钟,

int ** ptr;

地址*ptr确实等于&(**ptr)

因为基本上,这就是你的代码正在做的事情。

并记住,在内存中,2Darrays将被线性映射。

您可能知道面向对象的语言(如Java或Python),现在您正在学习C语言。 考虑char board[3][3]时,Java和C之间的区别在于C中的board变量在内存中表示为相邻内存地址的9个字符。 像这样:

 board: 1 2 3 4 5 6 7 8 9 

在C中, &board产生与&board[0]&board[0][0]相同的存储器地址。

与此相反,在Java中,变量将被声明为char[][] board ,其内存表示在概念上看起来像这样:

 board: ptr(A) ptr(B) ptr(C) A: 1 2 3 B: 4 5 6 C: 7 8 9 

其中ptr(x)指向ptr(x)内存地址。 因此,在Java中, board指向与board[0]不同的内存地址。


你说在C中,&board产生与&board [0]和&board [0] [0]相同的内存地址。 但我只能通过板[0] [0](或)*板[0](或)**板访问第一个元素。 为什么会这样?

虽然表达式&board&board[0]&board[0][0]产生相同的地址,但C语言的类型系统阻止您访问char值。 在C编译器中,类型是(概念上):

 board: type char[3][3] board[0]: type char[3] board[0][0]: type char 

假设char类型的变量,我们可以写:

 char c; c = board[0][0]; 

但不能写:

 char c; c = board; // Error c = board[0]; // Error 

因为左侧的类型与作业右侧的类型不兼容。

如果您确定地址指向char ,则可以使用类型转换:

 char c; c = *(char*)board; // Works OK c = *(char*)board[0]; // Works OK 

缺点是这种类型转换可能会导致编码错误。