二维数组和指针

7
我有以下代码片段:
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代表第一个子数组的地址(即)board[0]

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

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

我对此还很陌生,不理解这种行为。 请给我一些启示。

4个回答

5

虽然它是一个二维数组,但在内存中它将被表示为线性数组。因此当您说board [0] [0]时,它仍然指向该线性数组中的第一个元素,因此指向相同的内存地址。


1

当然,这将打印相同的地址。
花一分钟时间思考二维数组,

int **ptr;


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

因为基本上,这就是你的代码在做什么。

并且请记住,在内存中,二维数组将被线性映射。


1
据我所知,数组名(即)board表示第一个子数组的地址(即)board [0]。除非在以下情况下使用了board:
- &运算符的操作数 - sizeof的操作数
当任何一种情况发生时,表达式board表示数组并保持数组类型(char [3] [3])。对其应用&运算符会得到该数组的地址,这当然等于其第一个元素的地址,仅具有不同的类型(而不是char (*) [3],而是char (*) [3] [3])。关于数组board的所有内容都适用于其第一个子数组board [0]。
当你在这些上下文之外使用它时,你会获得第一个元素(在你的情况下是子数组)的地址。该地址不是对象,只是一个值。值没有地址,但对象有地址。尝试在它上面应用&将失败。例如:
// error: trying to apply '&' on something that has no address
&(1 ? board : board)

请注意,上述内容适用于 C 语言,但未必适用于 C++。

嗨,谢谢你的回复,我有点理解了。你能提供一个简单的示例程序来解释你的评论吗?那会非常有帮助。谢谢。 - intex0075
@intex,你提出的问题就是我将要提供的简单示例程序。 - Johannes Schaub - litb

1

也许你已经掌握了像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) 指向 x 的内存地址。因此,在 Java 中,board 指向的内存地址与 board[0] 不同。


你说在C语言中,&board与&board[0]和&board[0][0]产生的内存地址相同。但是我只能通过board[0][0](或)*board[0](或)**board访问第一个元素。为什么会这样?虽然表达式&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

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


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接