c语⾔⼆维数组指针(指向⼆维数组的指针)
⼆维数组在概念上时⼆维的,有⾏和列,但在内存中所有的数组元素都时连续排列的,它们之间没有“缝隙”。以下⾯的⼆维数组 a 为例:int a[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
从概念上理解,a的分布像⼀个矩阵:
10 1 2 3
2 4 5 6 7
38 9 10 11
但在内存中,a的分布时⼀维线性的,整个数组占⽤⼀块连续的内存:
c语⾔中的⼆维数组时按⾏排列的,也就是先存放a[0]⾏,在存放a[1]⾏,最后存放a[2]⾏;每⾏中的4个元素也是依次存放,数组a为int类型,每个元素占⽤4个字节,整个数组共占⽤4x(3x4)=48字节。
c语⾔允许把⼀个⼆维数组分解称多个⼀维数组来处理,对于数组a,它可以分解称三个⼀位数组,即a[0],a[1],a[2].每⼀个⼀维数组⼜包含4个元素,例如a[0]包含a[0][0],a[0][1],a[0][2],a[0][3].
假设数组a中第0个元素的地址为1000,那么每个⼀维数组的⾸地址如下图表⽰:
为了更好的理解指针和⼆维数组的关系,我们先来定义⼀个指向a的指针变量p
int (*p)[4] =a ;
括号中的*表明p是⼀个指针,它指向⼀个数组,数组的类型为int[4],这正是a所包含的每⼀个⼀维数组的类型。
[]的优先级⾼于*,()是必须要加的,如果⾚裸裸地写作int *p[4],那么应该理解为int *(p[4]),p就成了⼀个指针数组,⽽不是⼆维数组指针。
对指针进⾏加法(减法)运算时,它前进(后退)的步长与它指向的数据类型有关,p指向的数据类型是int[4],那么p+1就前进4x4=16字节,p-1就后退16个字节,这正好是数组a所包含的每个⼀维数组的长度,也就是说,p+1会使得指向指向⼆维数组的下⼀⾏,p-1会使得指针指向数组的上⼀⾏。
数组名a在表达式中会被转换为和p等价的指针。
下⾯我们就来探索以下如何使⽤指针p来访问⼆维数组中的每个元素,按照上⾯的定义:
1)p指向数组a的开头,也即第0⾏;p+1前进⼀⾏,指向第1⾏。
2)*(p+1)表⽰取地址上的数据,也就是整个第1⾏数据,注意是⼀⾏数据,是多个数据,不是第1⾏中的第0个元素,下⾯的运⾏结果有⼒地证明了这⼀点:
1#include<stdio.h>
2int main(){
3 int a [3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
4 int *(p)[4] = a;
5 printf("%d\n",sizeof(*(p+1)));
6 return 0;
7}
8//运⾏结果
916
3)*(p+1)+1表⽰第1⾏第1个元素的地址。
*(p+1)单独使⽤时表⽰的时第1⾏数据,放在表达式中会被转换为第1⾏数据的⾸地址,也就是第1⾏第0个元素的地址,因为使⽤整⾏数据没有实际的含义,编译器遇到这种情况都会转换为指向该⾏第0个元素的指针;就像⼀维数组的名字,在定义时或者个sizeof, & ⼀起使⽤时才表⽰整个数组,出现在表达式中就会被转换为指向数组第0个元素的指针。
4)*(*(p+1)+1)表⽰第1⾏第1个元素的只,很明显,增加了⼀个*表⽰取地址上的数据。
根据上⾯的结论,可以很容易推出以下的等价关系:
a+i = p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) ==*(*(p+i)+j)
使⽤指针遍历⼆维数组。
1#include<stdio.h>
2int mian(){
3 int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
4 int (*p)[4];
5 int i,j;
6 p = a;
7 for(i=0;i < 3;i++){
8 for(j=0; j < 4;j++) printf("%2d" ,*(*(p+i)+j));
9 printf("\n");
10 }
怎么定义二维数组c语言11 return 0;
12}
13//运⾏结果
14 0 1 2 3
15 4 5 6 7
16 8 9 10 11
指针数组和⼆维数组的区别
指针数组和⼆维数组指针有着本质的区别:指针数组时⼀个数组,只是每个元素保存的都是指针,以上⾯的p1为例,在32环境下它占⽤
4x5=20个字节的内存,⼆维数组指针是⼀个指针,它指向⼀个⼆维数组,以上⾯的p2为例,它占⽤4个字节的内存。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论