系列文章目录
文章目录
目录
前言
一、什么是指针
指针是用来存放地址的变量,指针有着不同的类型,不同的类型决定了解引用时访问的权限和步长,但指针的大小是统一的,在32位平台为4个字节,62平台为8个字节
1.定义指针
基本格式:>
指针指向变量的类型 *指针名 = &变量
char ch='0';
char *pc=&ch; //字符指针
int a=0;
int *p=&a; //整型指针
2.野指针
野指针就是指向未知空间的指针,下列三种情况可能会导致野指针的出现:>
(1)指针变量未初始化
跟没有赋值的变量一样,虽然没有赋值但是不代表这个变量没有数值,而是会默认初始化为零,所以对于指针没有初始化,它就会指向一块随机的空间
(2)指针(数组)越界
指针的越界,其中数组是最常用的,也是最常出现越界的情况,比如
int arr[3]={0,1,2};
int *p=arr;
此时,如果对*(p+3)进行解引用,由于这个数组下标只能是0,1,2,(p+3)已经越界了,那么如果再它解引用,就是非法访问内存
(3)指针指向的空间被释放
指向的空间已经被系统回收,如果再强行访问,那么也是非法访问。常见于自定义函数内创建指针,并且以这个指针作为返回值,那么,在出函数的时候,指针指向的空间已经被销毁了,那么就变成一个野指针,还有就是接下来会学到的动态开辟内存中,动态内存已经被释放(free)了,原来的指针也会变成野指针,所以要对它手动置空(p=NULL)
char*p=(char*)malloc(n*sizeof(int));
free(p);//释放动态内存,指针p指向的空间不在属于它
p=NULL;
注意:>
为了避免野指针的出现,在指针使用前要检查有效性
3. 指针运算
(1)指针加减整数
指针加减整数,这个整数就是指针在原地址上的偏移量
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int *p=arr;
p+=2; //此时指针指向第二个元素
p-=1; //此时指针指向第一个元素
注意:>
arr[i] / i[arr]编译时会转为*(arr+i)/ *(i+arr)
(2)指针减指针
指针与指针相减,等于两个指针之间的元素个数
注意:>
两个相减的指针必须是同一类型
(3)指针关系运算
由于内存中的空间也是有分为高地址和低地址(例如数组是从低地址到高地址连续存放的)所以指针也存在着大小关系
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int *p=arr;
p+=3;
此时,指针p的地址的大小应该大于arr的地址
注意:>
标志规定--->指针可以指向数组后面空间的地址,但是不能指向数组前面的空间地址,在指针关系运算时应特别注意
4.二级指针
存放指针地址的指针变量
int a=0;
int *p1=&a;
int **p2=&p1;
第一颗星*代表指向的类型是整型指针,第二颗星*代表p2是指针
二、字符指针
char ch='0';
char *pc=&ch;
const char *ps="abcdef"
指针pc中存储的是字符ch的地址,字符串指针ps存储的是字符串首元素a的地址
注意:>
字符串指针ps指向的是字符串常量,是不能更改的。所以该字符指针前面应该用const修饰,因此两个不同的字符串指针可以指向同一个字符串的空间
三、指针数组
用来存放地址的数组
char *s[10]={"aaa","bbb","ccc","ddd"};
四、数组指针
基本格式:>
//一维数组指针
数组的类型 (*指针名)[数组大小] =&数组名
//二维数组
数组的类型 (*指针名)[数组大小(列下标)] =&数组名
注意:
1.&数组名的地址等于数组名的地址,但是两者意义是不同的,对于一维数组取数组名的地址取的是整个数组的地址,二维数组取数组名的地址表取的是第一行数组的地址,而数组名是首元素的地址
2.[ ]的优先级高于*。所以,定义数组指针时,要将星号*与指针名括起,才表示它是指针
3.数组的类型表示--->int [ ],char [ ],用sizeof(int [ 4])可以计算出数组的大小
解引用:>
//一维数组
*((*p)+i)
//二维数组
*(*(p+j)+i)
(*p)表示拿到数组名*(p)=arr,*(p+j)表示第j行,加减i表示访问数组的第几个元素,也就是偏移量,最外面的星号表示拿到第i个元素
五、数组传参和指针传参
(1)一维数组
实际参数
int arr[大小]
形式参数
int arr[]
int arr[大小]
int *p;
实际参数
int *arr[大小]
形式参数
int *arr[]
int *arr[大小]
int **arr;
(2)二维数组
实际参数
int arr[大小1][大小2]
形式参数
int arr[][大小2]
int arr[大小1][大小2]
int (*arr)[大小2]
注意:>
二维数组传参不能省略列下标
六、函数指针
指向函数的指针
(1)定义
函数返回类型 (*指针名)(形参1...形参n) =&函数名/函数名
注意:>
1.对于函数&函数名与函数名两者意义是完全相同的
2.()优先级高于*
(2)引用
1.(*指针名)(实际参数)
2.指针名(实际参数)
3.函数名(实际参数)
注意:>
1.对于函数指针的引用 (*指针名)=指针名=函数名
2.(*指针名)中的*没有意义,无论多少个*都可以
七、函数指针数组
指向函数指针的数组,实质是数组
(1)定义
函数返回类型 (*指针名[数组大小])(形式参数1...形式参数n)={函数1,...,函数n)
注意:>
函数指针数组中各个函数的返回类型和形参是完全相同的
(2)引用
(指针名[i])(实际参数)
(*指针名[i])(实际参数)
注意:>
指针名[i]=*指针名[i]=对第i个函数的引用
八、函数指针数组的指针
函数返回类型 (*(*指针名)[大小])(形式参数1...形式参数n)
九、回调函数
回调函数就是一个通过函数指针调用的函数,把函数的指针传递给另一个函数,并且在这个函数里面,通过指针调用传入的函数
总结
以上就是有关指针的基础知识