二维数组和指针
我有以下代码片段:
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
-
据我所知,board(ie)数组名称代表第一个子arrays(即)
board[0]
和地址 -
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
缺点是这种类型转换可能会导致编码错误。