指针知识点及易错点总结

(本文示例代码环境为 VS2017下纯C代码 ,C++因为类型检测增强,代码会直接标红,需要强转才能运行)

1.指针

1.1指针简介

指针是一种数据类型,自身占用内存空间(win32平台,所有指针占用4字节内存空间),指针存储的 是内存地址的编号。
指针变量指向谁,就把谁的地址赋值给指针变量。指针通过 * 解引用,操作的是指针变量指向的内存空间,可以实现 取值间接赋值

1.2指针的声明和使用

在指针声明时,* 号表示所声明的变量为指针。
在指针使用时,* 号表示操作指针所指向的内存空间。

易错点: * 只能用来操作指针。
用一级指针接收二级指针的值,并不能实现二次解引用。
用二级指针接收一级指针的值,同样不能实现二次解引用。

**示例1:**一级指针接收并操作二级指针的值

int main() {
	int a = 10;
	int *p1 = &a;

	int *p2 = &p1;		//q2为一级指针
	int **p3 = &p1;		//q3为二级指针

	//p2和p3保存的值相等,但是p2未一级指针,只能解引用一次
	printf("%d\n", **p3);//此处正常输出10
	printf("%d\n", **p2);//err "*"的操作数必须是指针(vs2017报错提示)
	return 0;
}
	

调试查看内存截图如下:
这里写图片描述
注:上图中十六进制数 0x007df982 等于 十进制数 8255784


**示例2:**一级指针接收并操作二级指针的值

int main() {
	int a = 10;
	int *p1 = &a;

	int **p2 = p1;		
	printf("%d\n", *p2);    //此处正常输出为10
	printf("%d\n", *(*p2));
	//此代码编译时不报错,运行时异常退出(本质上为操作野指针)
	system("pause");
}

调试查看内存截图如下:
这里写图片描述
注:上图中十六进制数 0x0000000a 等于 十进制数 10

**总结:**初学指针的同学大多容易突发奇想,具体表现为把自己搞懵圈,然后很容易把哪些思想中规中矩而且的同学也带进坑里。
有想法就去尝试,实践是检验真理的唯一标准,往往是一些非常规的新奇想法更容易促进对知识点的理解。

1.3野指针,万能指针,空指针

1.3.1野指针
野指针指针操纵的内存空间必须是我们已经向操作系统申请的合法空间,如果指针指向了我们不具备操作权限的区域,即为野指针。出现野指针不会直接引发错误,操作野指针指向的内存区域才会出问题,并不一定是程序直接挂掉。
野指针出现的四种情况:

  1. 指针变量未初始化
  2. 指针释放后未置空
  3. 指针操作超越变量作用域
int * test() {
	int a = 10;
	int *p = &a;
	return p;
}
int main() {
#if 0
	// 1.指针变量未初始化
	int *p;
	printf("%d\n", *p);
	//操作指针p会报C4700错误(使用了未初始化的局部变量"p")
	//这种错误,编译器会直接报错,很容易避免
#endif

#if 0
	// 2. 指针释放后未置空
	int *p = malloc(16);
	free(p);
	printf("%d\n", *p);
	//指针释放后,可以理解为操作系统已经收回这段内存空间的使用权限
	//此时指针指向的就是“垃圾”内存,程序会固定输出-572662307
	//有兴趣的同学可以深入探讨一下这段数字的含义
#endif

#if 0
	// 3.指针操作超越变量作用域
	int *p = test();
	printf("%d\n", *p);
	//此处输出10,即为test函数中的a值
	//编译器做了一层优化,虽然输出值正常,但是不能这样使用。
#endif

	system("pause");
	return 0;
}

总结:避免野指针的最好方法就是初始化置空,和释放后置空。

1.3.2 空指针
空指针并不是NULL,而是把指向NULL的指针称为空指针,这个操作称为将指针置空。其实置空就是用NULL覆盖了原先指针存储的地址空间,严格意义上讲,置空后的指针仍然是一个野指针,同样不能对其进行操作。

野指针可能引发很多奇怪的问题,我们一定要尽量避免操作野指针,但是如果代码量级很大,我们操作一个 “陌生” 指针之前可以知道其是否是野指针吗?

所以说指针使用过后(野指针)置空即为判断一个指针是否合法的前置条件,置空后我们可以使用if语句测试该指针是否为NULL,有效排除操作野指针对我们程序的影响。
我们写代码时,要注意指针置空的妙用,养成良好的变成习惯。

1.3.3万能指针
void *指针即为万能指针,可以指向任意变量的内存空间,可以接收任意类型变量的值,这样做的意义大家会慢慢发觉。但是现阶段我们需要注意,不能对万能指针解引用。

int main() {
	int *a = 10;
	void *p = &a;
	printf("%d\n", *p);//编译报错,不允许使用不完整类型
	system("pause");
	return 0;
}

1.14指针常量
在编辑程序时,指针作为函数参数,如果不想修改指针对应内存空间的值,需要使用const修饰指针数据类型

int main() {
	int a = 100;
	int b = 200;

	//指向常量的指针
	//修饰*,指针指向内存区域不能修改
	//等价于const int * p1 = &a;
	int const *p1 = &a;
	//*p1 = 111;	//err(表达式必须是可修改的左值)
	p1 = &b;		//指针指向可以变

	//指针常量
	//修饰p2,指针指向不能变指针指向的内存可以修改
	int * const p2 = &a;
	//p2 = &b;		//err(表达式必须是可修改的左值)
	*p2 = 222;	    //指针指向的内存可以修改

	//总结 对于 * 和 p const 修饰谁(紧挨着谁),谁就不能被修改
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值