指针知识点整理

指针

什么是指针:

指针是一种数据变量(例如int,char),使用它可以定义指针变量,这种变量用来存储内存地址,使用指针变量可以访问对应的内存,具体访问多少
个字节由指针的类型所决定。

什么情况下使用指针

理论上我们使用指针可以访问任何位置的内存,但绝大部分内存我们是没有访问权限的,因此使用指针是容易产生错误(原因就是非法访问内存),
所以我们要在合适的时候使用指针,例如以下情况

1、函数之间共享局部变量
    函数之间共享局部变量可以使用全局变量,但是全局变量容易造成命名冲突,还容易浪费内存,故在需要大量共享局部变量时不适用
	而函数传递默认是单向值传递,无法共享变量,所以指针时函数间共享变量的最好选择
2、提高函数传递参数的效率
	函数传参默认是单向值传递(内存拷贝),当传递变量的字节数较多时(如结构体),传递变量的地址效率更高,32位系统下只需要4字节,64位系统下只需要8字节。
	但这样会带来一个风险:变量可能会被修改。    可以使用const配合指针保护变量。
3、配合堆内存使用
    堆内存无法取名(不能与标识符建立映射关系),因此必须与指针配合使用。

如何使用指针

定义指针变量: 类型* 指针变量_p;
如  int* p = NULL;
1、指针变量不能连续定义。
		int* p1,p2;   	p1是指针,p2是int类型
		int  *p1,*p2;	p1,p2都是指针	   
2、指针变量与普通变量一样默认值都是随机的(野指针),所以使用指针时一定要初始化。
3、指针的类型决定了访问内存的字节数 ,如int* 访问4个字节的内存。

指针变量的赋值与解引用

int num = 10;
int* p1 = #    //用变量的地址赋值
int* p2 = malloc(sizeof(int));  //用堆内存地址赋值
printf("%d\n",*p1); //*p1(解引用)的值为10

使用指针需要注意的问题

空指针:
		指针变量值为NULL的指针叫做空指针,这种指针不能解引用,否则会产生段错误。
		使用指针时需要对空指针进行判断
if(0 == NULL)
{
	printf("该指针为空指针\n");
}
野指针:
	指向不确定的内存的指针
	对野指针解引用的后果:
		1、段错误
		2、脏数据
		3、一切正常
	野指针比空指针危害更大,因为它是无法判断出来的,错误可能是隐藏的,短时间不会显现
	如何避免野指针:
		1、定义指针时一定要进行初始化
		2、函数不返回局部变量地址
		3、指针变量指向的内存被释放后,指针变量要及时置空(=NULL)

指针数组与数组指针

指针数组:
	是由指针变量组成的数组,它的成员都是指针变量(本质上是数组)
	类型* arr[长度];
	例如 int* arr[10];
数组指针:
	是一种指针,专门用来存储数组的地址。
	类型 (*arrp)[长度];
int* arr[10];    
printf("%d\n",sizeof(arr));  // 数组arr 40字节
int (*arr)[10];    
printf("%d\n",sizeof(arr));  // 指针arr 4字节(32位系统下)

指针的运算:

指针变量中存储的是整数,理论上整数支持的所有运算指针变量都支持,但是绝大多数的运算是无意义
指针 + n:指针+指针类型字节数*n 前进了n个元素
指针 - n:指针-指针类型字节数*n 后退了n个元素
指针 - 指针:(指针-指针)/指针类型字节数  计算出两个指针之间间隔了多少个元素
注意:只有类型相同的指针才能相减。

const与指针:

当我们为了提高传参效率而使用指针时,传参的效率提高了,但是变量也有被修改的风险,这种情况可以使用const来进行保护
const int* p;   保护指针所指向的内存不被修改
int const* p;   同上
int* const p;   保护指针的指向不能修改
const int* const p; 保护指针指向的内存和指向都不能修改
int const* const p; 同上

数组名与指针:

数组名其实是一种特殊的指针,但它是常量,不能修改它的值,它与内存之间是映射关系,不能改变,而指针与内存之间是指向关系,可以改变
与普通指针的区别:
  1:数组名是常量,普通指针是变量
  2、普通指针变量有自己的存储空间,用来存储内存编号,它与目标内存是指向关系
  3、数组名没有自己的存储空间,他就代表数组空间的首地址,他与数组内存是映射关系
  4、对数组名取地址结果还是数组名的值
	int arr[5];
	arr<=>&arr
	arr 类型 int*
	&arr 类型 int(*)[n]
	
	数组名是没有存储空间,而指针变量是有存储空间
	指向数组的指针,可以当做数组名使用
	数组名也可以当做指针使用
    数组名[i]  == *(数组名+i)
*   (指针名+i) == 指针名[i]

注意:当数组作为参数传递时变成了指针,所以长度丢失了

二级指针:

二级指针就是指向指针的指针,里面存储的是指针变量的地址。
定义:
    类型** 变量名_pp;   
int num;
int* p=&num;
int** pp=&p;
赋值:
    变量名_pp = &指针变量;
解引用:
    *pp <=> p
    **pp <=> *p<=>num

函数指针:

函数会被二进制指令存储到代码段,而函数名就是指令的首地址

函数名就是地址(整数),它代表了函数在代码段中的位置

函数指针就是指向函数的指针,里面存储的是函数在代码段中的位置

如何定义函数指针:
	1、复制函数的声明语句,
	2、给函数名加上小括号,并在函数名前加一个*
	3、给函数名重新取一个函数指针变量名
当我们把函数作为数据传递时,被调用函数,可以通过函数指针调用我们以参数形式提供的函数,这种模式叫回调	
比如我们标准库中的qsort和bsearch。
由于函数指针的类型比较长,一般会选择使用typedef进行类型重定义
	void func(int,int);
	typedef void (*FP)(int,int);

void指针:

1、以一字节为单位移动
2、不能解引用
3、它可以与任何类型的指针自动转换(只能在c语言中)
4、一般用作函数的参数、返回值
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值