什么是指针
从根本上来讲,指针(pointer)是一个值为内存地址的变量(或数据对象)。
想象一下你的一个同学住在宿舍楼里,你经常要找他。最简单的方法就是让他随时呆在你身边。还有一种办法就是记住他的宿舍号,每次要找他就直接到宿舍号对应的宿舍去找。你的同学就相当于一个变量,而这个宿舍号就是变量地址,指针就是记录着宿舍号的一种信息。我们常见的指向XX的指针就可以理解为对应XX房间的宿舍号
正如char类型变量的值是字符,int类型变量的值是整数,指针变量的类型是地址。由于不同类型分配的存储空间大小不同,指针不能单独声明而是要先说明他指向的类型空间。
int * p1; // 指向整型变量的指针
float * p2; // 指向浮点型变量的指针
char * p3; // 指向字符型变量的指针
struct {}*p4; // 指向结构体类型的指针
就像有的宿舍是男生宿舍有的宿舍是女生宿舍,你要先说明是男生宿舍还是女生宿舍再确定房间号
常见的指针识读
- 类型指针
int * p;
存储整型变量的地址的指针
2. 数组指针
int * p[10];
存储整型数组的地址的指针
- 指针数组
int (*p)[10];
存储整型指针元素的数组
- 指针函数
int * p(int, int);
返回值为整型指针的函数
- 函数指针
int (*p)(int, int);
指向返回值为整型的函数的指针
函数指针能够使用一个指针指向一个函数,同时还可以替换指向别的函数。如果有多个函数的申明,它们有不同的具体实现,我们可以通过让指针轮流指向他们来实现函数的不同调用,如此便实现了提供不同实现的统一接口的作用。在工程代码里面比较常见。数据结构的学习中了解一下即可。
- 多重指针
int ** p;
即存放p地址的空间的指针
用一个房间来存放另一个房间的房间号
int *** p;
***p 三重套娃。数据结构的学习中基本上能理解三重指针即可,更多重的指针基本不会用到。
符号 & 和 *
& 为取地址符
作用是获取变量的存储空间的地址(获取住户所在的房间号)
如:
int a; // 整型变量a
int * p = &a; // p的值为整型变量a的地址
我们平时使用的scanf函数就是要把输入的内容放到对应变量的地址(房间)中去
scanf("%d", &a);
* 有三种用法
- 乘法运算符
在两个变量之间的表达式时,* 的涵义为乘法运算符 - 指针
当声明类型时,* 的含义为指针。初学者通常搞不清 * 是左结合还是右结合。* 为指针时是左结合,左边没有关键字时右结合。
*如:int *p[10] 和 int (p)[10] , 前者为由整型指针所组成的数组,后者为指向由整型数据组成的数组的指针 - 取内容
一般称为解引用运算符(dereferencing operator)。表示获得地址上的值(通过房间号找到里面的住户)。* 为取内容时为右结合
tips:
1)* 和指针名之间的空格可有可无。通常,程序员在声明时使用空格,在解引用变量时省略空格。这样使用让他们的左右结合判断更直观。
2)2.和3.两个分类其实都属于间接运算符(intdirection operator),为了方便理解我把它分成两类。
3)不要解引用未初始化的指针(野指针),会导致难以预测的结果。
指针的常见使用
- 指针传参
其实应该称为 指针在函数间的通信,但是乍一看可能不太好理解。
一个函数无法对传入的参数修改从而影响到主函数,当我们想要把函数运算的结果反馈给主函数时只能使用 return方法。但是return方法只能返回一个值,当我们想要给主函数反馈多个值时就需要使用指针。
如:
#include<stdio.h>
// 两数互换
void swap(int *a, int *b){
int *temp;
temp = *a;
*a = *b;
*b = temp;
}
int main(){
int a = 3, b = 5;
printf("%d, %d \n", a, b);
swap(&a, &b);
printf("%d, %d \n", a, b);
return 0;
}
代码运行结果:
tips:
函数参数通常都是直接传递数值,这样做可以保证数据的完整性,只有程序需要在函数中改变该数值时,才会传递指针。
- 数组与指针
数组名就是数组首元素的地址。
数组是一片连续的空间存储的数据对象。可以类比为一排房间,只要知道第一个房间的房间号就能知道后面连续的n个
数组名后面进行+1操作就是对地址进行+1操作,即访问数组的下一个元素。
房间号+1就是访问下一间宿舍
.
.
.
.
参考文献
C Primer Plus (第六版) 中文版