指针

PS:本文假设你对指针已有一定的了解,能熟练运用最简单的指针。

概念

首先解释一下两个概念

  • 指针的类型
  • 指针指向的类型

    指针的类型

    1
    2
    3
    4
    5
    (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
2
3
4
5
(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 去掉就可以得到指针指向的类型。
这个语句的意思就是,先读取指针变量中的地址,再读取该地址对应的值。

如何获得指针变量中地址对应的值

1
2
3
4
最简单的一个例子
int a=3; //定义一个int类型的变量a,并赋值为3;
int * p = &a; //定义一个int*类型的指针变量p,并赋值变量a的地址;
printf("%d",*p);

很明显,通过 * 指针变量 就可以获得指针变量中地址对应的值

1
2
3
4
5
6
再来一个一维数组的
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的含义是不一样的。

1
2
3
4
5
6
7
8
再来一个二维数组
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

二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的。

1
2
3
4
最后最后
int *(p1[3]); //指针数组,用来储存三个地址,可以去掉括号;
int (*p2)[3]; //二维数组指针,不能去掉括号;
//一定要注意区别。
1
2
结构体
待填坑
1
2
指向函数的指针
待填坑
坚持技术分享,如果帮助到了您,您的支持将鼓励我继续创作!