刚开始学c语言的时候,老是会认为,一级指针能够用来访问一维数组,那么二维数组就要用二级指针来访问啦。。。。html
实际上二级指针和二维数组真的没什么关系,并且,切记千万不要用二级指针访问二维数组。。。。。小程序
下面是几个有关的小程序,加深印象。。。。。。。。数组
实验环境:主机CPU酷睿i5,vs2012函数
程序1:spa
int _tmain(int argc, _TCHAR* argv[]) { int **p= NULL; int a[2][3] = {1,2,3,4}; p = a; return 0; }
结果:编译错误,错误提示:没法从“int [2][3]”转换为“int **设计
可见,二级指针和二维数组名,根本就不是一类东西。3d
程序2:指针
int _tmain(int argc, _TCHAR* argv[]) { int **p= NULL; int a[2][3] = {1,2,3,4}; p = (int **)a; printf("指针的长度为:%d\n",sizeof(p)); printf("值为:%d\n",(int)(*p)); p++; printf("值为:%d\n",(int)(*p)); getchar(); return 0; }
输出结果:code
为啥能够输出结果呢:纯属巧合!!!!!htm
什么巧合呢:在个人机器上指针的长度和int类型的长度都恰好为4个字节。
把程序放在虚拟机中跑一下,虚拟机的系统是CentOS7,64位的。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int a[2][2]={1,2,3,4}; int **p =(int **)a; printf("值为:%d\n",(int)(*p)); p++; printf("值为:%d\n",(int)(*p)); char *pointer; printf("指针的长度为:%zd\n",sizeof(pointer)); return 0; }
结果:编译错误,提示:
缘由是,在个人虚拟机中指针占8个字节吗,而int占四个字节。
可是long是占8个字节,因此改为long也能够实现主机中的效果。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { long a[2][2]={1,2,3,4}; long **p =(long **)a; printf("值为:%ld\n",(long)(*p)); p++; printf("值为:%ld\n",(long)(*p)); char *pointer; printf("指针的长度为:%zd\n",sizeof(pointer)); return 0; }
结果为:
缘由和第一个程序同样,纯属巧合:在个人虚拟机中指针和long都占8个字节。
在写这个程序的时候还有个小插曲(小错误),也设计了两个知识点,顺便分享一下,写上面程序的时候。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int a[2][2]={1,2,3,4}; int **p =(int **)a; printf("值为:%d\n",(long)(*p)); p++; printf("值为:%d\n",(long)(*p)); char *pointer; printf("指针的长度为:%zd\n",sizeof(pointer)); return 0; }
输出结果为:
在输出long型数据的时候我不当心用了%d,而不是%ld。
看一下用%ld的效果:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int a[2][2]={1,2,3,4}; int **p =(int **)a; printf("值为:%ld\n",(long)(*p)); p++; printf("值为:%ld\n",(long)(*p)); char *pointer; printf("指针的长度为:%zd\n",sizeof(pointer)); return 0; }
输出结果为:
为何会这样? 仍是要从内存角度看:
在个人虚拟机中,指针占8个字节,而p是个二级指针,*p就是个int类型的指针,占8个字节,因此其实*p占据了a[0]和a[1]。
至于为何结果是8589934593.这还要涉及一个字节序的问题(这里就不解释了)
个人cpu是英特尔的,通常x86系列的cpu都是采用低字节序。
因此a[0]和a[1]两个单元在内存中相似于:
高地址------------------------------------------------------------------------------------低地址
00000000 00000000 00000000 00000010 00000000 00000000 00000000 00000001
把这段内存解释成long类型的数据就是8589934593
------------------------------------------------------------------------------------------------------------------------------
还要注意的是我上面,那两个巧合之下能运行的程序,都是用*p访问的,若是用**p会报错,由于**p就是*p指向的内存空间的值,而*p指向的内存,也就是8589934593地址空间,是未知的。
总之记住,二级指针和二维数据没啥关系
问题来了,既然不能用二级指针访问二维数据,那怎样用指针访问二维数组呢?
在我以前的随笔 由typedef和函数指针引发的危机 中,提到了,要声明某种类型的指针变量,只需先声明处该类型的变量,而后加上*便可(注意优先级)
那么怎样用指针访问二维数组呢?
先来回忆一下怎样用指针访问一维数组。在访问一位数组时,咱们实际上声明的是一个和数组元素类型相同的指针变量,指向了数组第一个元素的地址,而后在用这个指针访问数组。
好比访问int b[3]= {1,2,3}.
b中的元素为int类型,因此咱们要声明一个int类型的指针变量 如int *p ,而后将p指向b的第一个元素的地址,即p = &b[0],数组的首地址和第一个元素的地址是同样的,因此也能够用p=b;
这里须要强调的是,指针类型和数组元素的类型一致,而不是数组类型一致,好比b的类型是有三个int类型元素的数组,而b中元素是int类型,b是数组类型,而元素是int类型,是不同的。上面之因此可以用p=b,不是说p是数组类型的指针,只是数组的首地址,和数组中第一个元素的地址同样罢了。p是个int类型的指针而不是数组类型的指针,这一点必定要记住。。。。
回到二维数组来,拿int a[2][3]= {1,2,3,4,5,6}来讲, 数组a的元素为 一个含有三个int类型数据的数据,即a的元素是一个一维数组,这个数组含3个元素。。。。
那么怎样声明指向a数组中元素的指针变量呢? 在 由typedef和函数指针引发的危机 提到,方法及时先声明一个该类型的变量,而后加上*便可,
a中元素为含有3个int数据的数组,定义这样一个普通变量为: int p[3],而后在变量名前面加上*便可,可是要注意运算符的优先级,由于*的优先级比[]低,因此要加括号,即int (*p)[3]。
这样再将p指向a的第一个元素的地址:p = &a[0],而后就能够用p来访问数组a啦!
给出程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int a[2][3] = {1,2,3,4,5,6}; int (*p)[3] = &a[0]; printf("值为:%d\n",(*p)[0]); printf("值为:%d\n",(*p)[1]); printf("值为:%d\n",(*p)[2]); p++; printf("值为:%d\n",(*p)[0]); printf("值为:%d\n",(*p)[1]); printf("值为:%d\n",(*p)[2]); getchar(); return 0; }
结果为:
再来一个程序,加深一下理解
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int a[2][3][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; int (*p)[3][4] = &a[0]; int i = 0; for(;i < 3; i++) { int j = 0; for(; j < 4;j++) printf("值为:%d\n",(*p)[i][j]); } p++; i = 0; for(;i < 3; i++) { int j = 0; for(; j < 4;j++) printf("值为:%d\n",(*p)[i][j]); } return 0; }
运行结果:
最后,贴上一张,来自csdn的图
但愿对你有帮助,有纰漏的地方还请指正,谢谢。。。。