PS:本文假设你对指针已有一定的了解,能熟练运用最简单的指针。
概念
首先解释一下两个概念
- 指针的类型
- 指针指向的类型
指针的类型
(1)int *p; 定义一个类型为 int* 的变量p 指针的类型是int*
(2)char *p; 定义一个类型为 char* 的变量p 指针的类型是char*
(3)int **p; 定义一个类型为 int** 的变量p 指针的类型是int**
(4)int (*p)[3]; 定义一个类型为 int (*)[3] 的变量p 指针的类型是int(*)[3]
(5)int *(*p)[3]; 定义一个类型为 int *(*)[3] 的变量p 指针的类型是int*(*)[3]
很明显,把变量名去掉就可以得到指针的类型。
指针指向的类型
(1)int *p; 定义一个类型为 int* 的变量p 指针指向的类型是int
(2)char *p; 定义一个类型为 char* 的变量p 指针指向的类型是char
(3)int **p; 定义一个类型为 int** 的变量p 指针指向的类型是int*
(4)int (*p)[3]; 定义一个类型为 int (*)[3] 的变量p 指针指向的类型是int()[3]
(5)int *(*p)[3]; 定义一个类型为 int *(*)[3] 的变量p 指针指向的类型是int*()[3]
很明显,将*p去掉就可以得到指针指向的类型。
这个语句的意思就是,先读取指针变量中的地址,再读取该地址对应的值。
如何获得指针变量中地址对应的值
最简单的一个例子
int a=3; 定义一个int类型的变量a,并赋值为3;
int * p = &a; 定义一个int*类型的指针变量p,并赋值变量a的地址;
printf("%d",*p);
很明显,通过 * 指针变量
就可以获得指针变量中地址对应的值
再来一个一维数组的
int a[3];
int *p = &a[0]; or int *p = a; a储存的就是a[0]的地址,且不可更改
p[0] = 0; p[1] = 1; 对数组赋值,等价于a[0] = 0; a[1] = 1;
*p = 0; *(p+1) =1; 对数组赋值,等价于a[0] = 0; a[1] = 1;
printf("%d%d%d%d",p[0],p[1],*p,*(p+1)); 依次输出a[0]a[1],a[0],a[1]
这里要重点掌握int *p = a; *(p+1) =1;
这里 p+1
并不是代表地址数加一,它与指针的类型有关系
C标准并没有具体给出规定哪个基本类型应该是多少个字节数,而且这个也与OS、编译器有关。下面给出在32位环境下的图。
这里可以这样理解,对于不同的指针类型,虽然每次都走一步,但是他们一步所对应的长度是不同的。
所以指针一定要分类型,不同类型的指针,p+1的含义是不一样的。
再来一个二维数组
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
int (*p)[4] = a; 定义一个类型为int(*)[4]的指针变量 p指向的数据类型是int [4]
printf("%d",*p); 这里看似是输出第一行的数据,但是一行数据是没有意义的,所以编译器将它转换为数组的首地址,即 a[0][0] 的地址,在转为十进制输出。
printf("%x",*p); 这样输出的就是 a[0][0] 的地址
printf("%d",p[0][0]); 最好理解的方式
printf("%d",*(*p)); 这里输出 a[0][0] 的值
printf("%d",*(*(p+1)+1) ) 这里输出 a[1][1]的值 *(p+1)获得第一行地址,*(p+1)+1获得a[1][1]的地址,这里步长为16 *(*(p+1)+1)获得a[1][1]的值,这里步长为4
二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的。
最后最后
int *(p1[3]); 指针数组,用来储存三个地址,可以去掉括号;
int (*p2)[3]; 二维数组指针,不能去掉括号;
一定要注意区别。
结构体
待填坑
指向函数的指针
待填坑
网友评论