C语言基础知识之指针

系列文章目录



前言


一、什么是指针

指针是用来存放地址的变量,指针有着不同的类型,不同的类型决定了解引用时访问的权限和步长,但指针的大小是统一的,在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)

九、回调函数 

回调函数就是一个通过函数指针调用的函数,把函数的指针传递给另一个函数,并且在这个函数里面,通过指针调用传入的函数


总结

以上就是有关指针的基础知识

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值