"迷途"的野指针,都快找不着北了
指针,C语言开发者表示很淦,指针的使用,很多人表示不敢直面ta,不像Java一样,有垃圾自动回收功能,我们不用担心那么多内存泄漏等问题,那C语言里边呢,指针又分为了"野指针","迷途指针" 。 你是不是更迷糊了,这篇一起来攻克ta!
- 发现我的封面似乎致敬了一下路痴"索隆",刚好跟我们今天的主角一样,找不着北的"迷途"指针hhh
悬垂指针/迷途指针定义
- 当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针(也叫迷途指针)。
野指针定义
- 野指针指的是还没有初始化的指针(导致我们不知道他会指向哪里)
int* p;
//没有初始化就使用他
printf("%p", p);
编译器一般会提示你出错了!
常见错误:
1。指针定义时未被初始化:
- 指针在被定义的时候,如果程序不对其进行初始化的话,它会随机指向一个区域 。
这种指针就是我们上边所说的野指针
//先定义一个指针(没有初始化)
int *p ;
//然后就使用这个指针
*p =12;
2。指针释放后没有置空:
- 我们在用malloc()开辟空间的时候,要检查返回值是否为空
- 如果为空,则开辟失败;
- 如果不为空,则指针指向的是开辟的内存空间的首地址。
- 指针指向的内存空间在用free()或delete释放后,此时指针指向的就是“垃圾”内存。如果我们没有对其进行置空或者其他赋值操作的话,就有可能会成为悬垂指针/迷途指针 。
free
free() 只能释放动态分配的内存空间,并不能释放任意的内存。下面的写法是错误的:
int a[10];
free(a);
注意:free() 不会改变 np 变量(一个指向结构体的指针)本身的值,调用 free() 后它仍然会指向相同的内存空间
可以把他理解为,原本np指向了一个房子,现在free了,把房子里的人赶了出去,而np仍然指向这个房子
但是此时该内存已无效,不能被使用。
把他们打印出来的话还是一样的,但是再访问的话
free之后访问到的数据就奇奇怪怪的了
规避方法
建议在 free操作后 将 np 的值设置为 NULL,例如:
free(np);
np=NULL;
3。在方法中定义变量,返回该变量的地址
- 先来看一个实例
#include"stdio.h"
int* tempAddress() {
int temp1[] = { 1,2,3 };
return temp1;
}
int* tempAddress2() {
int temp2[] = { 4,5,6 };
return temp2;
}
int main() {
//第一次
int* temp = tempAddress();
printf("%d\n", *temp);
//调用另一个完全不一样的函数
tempAddress2();
//重新输出
printf("%d\n", *temp);
}
诶?明明第一次还能输出出来来着,怎么后边调用了另一个完全不一样的函数之后就输出变得那么奇怪了呢?
栈
- 要知道,我们每个方法执行的时候,都会为这个方法去分配一个栈帧,当这个函数返回时,为栈帧分配的那一块内存区域可能就已经被释放了,但是数据还未清理
- 但是任何接下来的函数调用都可能又会把刚才释放掉的那块空间给占用了。导致再输出temp所指向的值时,就变成我们新修改的值了
堆
可能看到这里有的同学会有疑问了?诶,那free跟这个方法栈的回收有什么区别呢?为什么free过后是直接不能访问呢,而方法栈的回收却只是把区域回收了,但是数据还没有清理掉
其实我们free,通常都是搭配malloc来使用的,何谓malloc,malloc是我们程序员手动在堆中开辟一个空间,可以自己进行管理,不会像栈一样,出了函数就自动被回收了
来看我们用malloc能不能解决上边那个问题
int* tempAddress() {
//int a[] = { 1,2,3 };
int* a = (int*)malloc(sizeof(int) * 3);
a[0] = 1;
return a;
}
int* tempAddress2() {
//int b[] = { 4,5,6 };
int* b = (int*)malloc(sizeof(int) * 3);
b[0] = 4;
return b;
}
int main() {
int* temp = tempAddress();
printf("%d\n", *temp);
tempAddress2();
printf("%d\n", *temp);
- 是不是美滋滋,我们可以自己手动控制这块区域了,要回收也是我们自己回收,不会说出了函数体就被自动回收了
堆栈需要注意的问题
内存空间不足,内存泄漏
malloc一时爽,一直malloc一直爽,随着我们开发不断的malloc,可能会带来什么问题呢?
- 最显而易见的当然是我们的内存空间分配的问题,当我们malloc的数量,空间内存越来越大时,势必会造成堆内存的无限膨胀,。长期运行将会导致可用内存越来越少,程序也将会变得越来越卡顿。如果我们不手动释放,那就要到程序结束才会释放。可能会出现内存泄露(就是我们前边所提及到的)等问题
堆栈溢出/缓冲区溢出
使用过多的存储器时导致调用堆栈产生的溢出,也是缓冲区溢出中的一种
最常见的情况就是无限递归了
int fun()
{
//这里递归没有一个终止条件,会无限调用
return fun();
}
写在最后
- 关于递归,在之后的数据结构专栏我们还会涉及到(归并排序和快速排序等) , 还有不同语言的垃圾回收机制, 等到melo进一步学习了Java中的垃圾回收后,我们再来聊一聊!
"迷途"的野指针,都快找不着北了的更多相关文章
- 使用AFNetworking时, 控制器点击返回销毁了, 但还是会执行请求成功或失败的block, 导致野指针异常
原本我以为是我程序框架有问题...后来才知道, 无知真可怕... __unsafe_unretained __block typeof(self) weakSelf = self; AFHTTPSes ...
- 野指针与'关键字'NULL
野指针与'关键字'NULL 一.NULL是什么? 在C/C++中的标准定义: #ifdef __cplusplus //条件编译,判断是c++还是c环境 #define NULL 0 //c++环境 ...
- 关于空指针NULL、野指针、通用指针 (转)
reference:https://www.cnblogs.com/losesea/archive/2012/11/16/2772590.html 首先说一下什么是指针,只要明白了指针的含义,你就明白 ...
- 野指针(Wild pointer)和悬垂指针(dangling pointer)
详细参考如下: Dangling pointer(悬垂指针.迷途指针)和 Wild pointer(野指针) 迷途指针经常出现在混杂使用malloc() 和 free() 库调用: 当指针指向的内存释 ...
- 奇思妙想:利用野指针和lower_bound()/upper_bound()函数实现整数二分
众所周知,c++的STL中提供了三个二分查找函数,binary_search(),lower_bound(),upper_bound(),功能分别是找某值是否在数组中出现,找到数组中第一个大于等于某值 ...
- iOS开发_内存泄漏、内存溢出和野指针之间的区别
今天,在工作群中,被问到了内存泄漏和野指针指向的区别,自己答的不是很好,特意回来查了资料,在博文中总结一下经验,欢迎指正. 内存泄漏:是指在堆区,alloc 或new 创建了一个对象,但是并没有放到自 ...
- NULL指针、零指针、野指针
1.1.空指针 如果 p 是一个指针变量,则 p = 0; p = 0L; p = '\0'; p = 3 - 3; p = 0 * 17;p=(void*)0; 中的任何一种赋值操作之后, p 都成 ...
- 黑马程序员-nil Nil NULL NSNull 野指针和空指针
空指针1.空指针指不含有任何内存地址的指针.在没有具体初始化之前,其被符值为0Dog * dog = nil;Dog * dog = NULL;都为空指针2.野指针指指向的内存为垃圾内存,导致其值不确 ...
- C中的野指针—如何避免
转自:http://www.cnblogs.com/viviwind/archive/2012/08/14/2638810.html 先看一个例子: struct student{ char* nam ...
随机推荐
- ECShop 文章添加缩略图功能
为 ECShop 文章添加缩略图 ECShop 文章不包含缩略图比较遗憾,不过它的文章里包含一个附件上传,而且一般不会用到,这样,我们就可以改动一下,让它成为缩略图. 首先在 includes ...
- Git(2) - git安装、本地仓库与远程仓库使用详细指南
git版本控制工具 下载地址:https://www.git-scm.com/download/win选择对应版本的工具,下载后是一个exe执行文件: 常用git命令 命令 作用 git init(在 ...
- Android命令行启动模拟器
我们在平时的开发中会经常需要使用模拟器进行调试,这个时候我们就要先打开Android Studio来启动模拟器,然后再运行App.这个流程中启动Android Studio需要花费一些时间,而模拟器的 ...
- 将可执行程序设为linux服务启动
将可执行程序设为linux服务启动 如何将我们自己的程序设为linux的一个服务程序,并实现开机启动,需要经过如下三步: 1 把可执行程序放在一个linux系统可以找到的地方. ...
- 【译】.NET Core 3.0 发布小尺寸 self-contained 单体可执行程序
.NET Core 提供的发布应用程序选项 self-contained 是共享应用程序的好方法,因为应用程序的发布目录包含所有组件.运行时和框架.您只需要告诉使用者应用程序的入口 exe 文件,就可 ...
- c++ 的学习 第二集函数的重载
1. 规则 函数名相同参数个数不同.参数类型不同.参数顺序不同 2. 注意 返回值类型与函数重载无关 调用函数时,实参的隐式类型转换可能会产生二义性 返回值类型与函数重载无关 什么意思? 返回 ...
- P4424-[HNOI/AHOI2018]寻宝游戏【结论】
正题 题目链接:https://www.luogu.com.cn/problem/P4424 题目大意 \(n\)个\(m\)位二进制数,开始是一个\(0\). 然后依次对所有二进制数进行\(n\)次 ...
- AT4995-[AGC034E] Complete Compress【树形dp】
正题 题目链接:https://www.luogu.com.cn/problem/AT4995 题目大意 \(n\)个点的一棵树,上面有一些棋子,每次可以选择两个棋子移动到他们之间的路径上相邻的点上, ...
- MFC修改窗口图标
Visual Studio写MFC应用程序,默认的程序左上角图标是自带的(如下图),想要自己个性化定制一个新的图标则需要以下几个步骤. 一.准备工作(icon图标) 首先准备一个自己个性化定制的图片, ...
- Linkerd stable-2.11.0 稳定版发布:授权策略、gRPC 重试、性能改进等!
公众号:黑客下午茶 授权策略 Linkerd 的新服务器授权策略(server authorization policy)功能使您可以细粒度控制允许哪些服务相互通信.这些策略直接建立在 Linkerd ...