c语言中二维数组行指针是什么,C语言 二维数组和指针

二维数组可以看成是元素为一维数组的数组,假设有一个三行四列的二维数组a,它定义为:

int a[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

a 是二维数组名。a 数组包含 3 行,即 3 个行元素:a[0],a[1],a[2]。每个行元素都可以看成含有 4 个元素的一维数组。而且 C 语言规定,a[0]、a[1]、a[2]分别是这三个一维数组的数组名。

b383a7b336c35c195d4813b05d03ace3.png

a[0]、a[1]、a[2] 既然是一维数组名,一维数组的数组名表示的就是数组第一个元素的地址,所以

a[0] 表示的就是元素 a[0][0] 的地址,即 a[0]==&a[0][0];

a[1] 表示的就是元素 a[1][0] 的地址,即 a[1]==&a[1][0];

a[2] 表示的就是元素 a[2][0] 的地址,即 a[2]==&a[2][0]。

所以二维数组a[M][N]中,a[i]表示的就是元素a[i][0]的地址

a[i] == &a[i][0]

a[0]、a[1]、a[2]、…、a[M–1] 分别表示二维数组 a[M][N] 第 0 行、第 1 行、第 2 行、…、第 M–1 行各一维数组的首地址,那么同样的道理,

a[0]+1 就表示元素 a[0][1] 的地址,

a[0]+2 就表示元素 a[0][2] 的地址,

a[1]+1 就表示元素 a[1][1] 的地址,

a[1]+2 就表示元素 a[1][2] 的地址

a[i]+j 就表示 a[i][j] 的地址

a[i]+j == &a[i][j]

&a[i][0]+j == &a[i][j]

在一维数组中 a[i] 和 *(a+i) 等价

这个关系在二维数组中同样适用,二维数组 a[M][N] 就是有 M 个元素 a[0]、a[1]、…、a[M–1] 的一维数组。

*(a+i)+j == &a[i][j]

a[i]+j 和 *(a+i)+j 等价,都表示元素 a[i][j] 的地址。

05b76c45f3297292849d41ba9566cad5.png

d79d305bb8d23d26783e0de96e3dfe46.png

二维数组的首地址和数组名

二维数组 a[M][N] 的数组名 a 表示的是谁的地址?”

在一维数组中,数组名表示的是数组第一个元素的地址,那么二维数组呢? a 表示的是元素 a[0][0] 的地址吗?不是!我们说过,二维数组就是一维数组,二维数组 a[3][4] 就是有三个元素 a[0]、a[1]、a[2] 的一维数组,所以数组 a 的第一个元素不是 a[0][0],而是 a[0],所以数组名 a 表示的不是元素 a[0][0] 的地址,而是 a[0] 的地址,即:

a == &a[0]

而 a[0] 又是 a[0][0] 的地址,即:

a[0] == &a[0][0]

所以二维数组名 a 和元素 a[0][0] 的关系是:

a == &(&a[0][0])

二维数组名 a 是地址的地址,必须两次取值才可以取出数组中存储的数据。对于二维数组 a[M][N],数组名 a 的类型为 int(*)[N],所以如果定义了一个指针变量 p:int *p;

希望这个指针变量指向二维数组 a,那么不能把 a 赋给 p,因为它们的类型不一样。要么把 &a[0][0] 赋给 p,要么把 a[0] 赋给 p,要么把 *a 赋给 p。前两个好理解,可为什么可以把 *a 赋给 p?因为 a==&(&a[0][0]),所以 a==(&(&a[0][0]))==&a[0][0]。

除此之外你也可以把指针变量 p 定义成 int(*)[N] 型,这时就可以把 a 赋给 p,而且用这种方法的人还比较多,但我不喜欢,因为我觉得这样定义看起来很别扭。

# include

int main(void)

{

int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

int i, j;

int (*p)[4] = a; //记住这种定义格式

for (i=0; i<3; ++i)

{

for (j=0; j<4; ++j)

{

printf("%-2d\x20", *(*(p+i)+j)); /*%-2d中, '-'表示左对齐, 如果不写'-'则默认表示右对齐;2表示这个元素输出时占两个空格的空间*/

}

printf("\n");

}

return 0;

}

# include

int main(void)

{

int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

int i, j;

for (i=0; i<3; ++i)

{

for (j=0; j<4; ++j)

{

printf("%#X\x20", &a[i][j]);

}

printf("\n");

}

return 0;

}

输出结果是:

0X18FF18 0X18FF1C 0X18FF20 0X18FF24

0X18FF28 0X18FF2C 0X18FF30 0X18FF34

0X18FF38 0X18FF3C 0X18FF40 0X18FF44

我们看到地址都是连续的。所以对于数组 a[3][4],如果把 &a[0][0] 赋给指针变量 p 的话,那么:

p == &a[0][0]; p + 1 == &a[0][1]; p + 2 == &a[0][2]; p + 3 == &a[0][3];

p + 4 == &a[1][0]; p + 5 == &a[1][1]; p + 6 == &a[1][2]; p + 7 == &a[1][3];

p + 8 == &a[2][0]; p + 9 == &a[2][1]; p + 10 == &a[2][2]; p + 10 == &a[2][3];

# include

int main(void)

{

int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

int i, j;

int *p = &a[0][0]; //把a[0][0]的地址赋给指针变量p

for (i=0; i<3; ++i)

{

for (j=0; j<4; ++j)

{

printf("%-2d\x20", *(p+i*4+j));

}

printf("\n");

}

return 0;

}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值