【C/C++】原来这样做就能避免C语言悬垂指针问题

1. 内存4区

程序在运行时,指令是存放在内存中的,程序大致占用了内存大概4个区:

代码区、数据区、栈区、堆区

1.1 代码区

程序指令存放在这里,由操作系统管理

特征:共享、且只读

1.2 数据区

  • 数据区

      存放由const修饰的常量、字符串常量等
    
  • 全局(静态)区

      存放由static修饰、全局变量等
    

注意#define与const不同,#define是预处理,在编译前由编译器简单替换,而不是作为常量在程序运行时放到内存

1.3 栈区(本文重点)

存放的数据由系统管理,自动分配释放

如:函数的参数,局部变量等

1.4 堆区(本文重点)

存放的数据由开发者手动分配释放

若开发者不释放,则系统会在程序运行结束后回收内存

如:用malloc函数申请的内存空间

1.5 分4区的意义

赋予了不同类型的变量不同的生命周期。根据实际情况需要,选择不同的变量声明方式,使开发时更灵活

但是也容易带来内存泄露等隐患,需要开发者特别注意内存管理

2. 错误代码示例(悬垂指针)

// 关键代码
void fun(int ** q) {
	int i = 5;
	*q = &i;
}

int main() {
	int * p;
	fun(&p);
	printf("%d\n", *p);
	printf("%d\n", *p);
	return 0;
}

q和&p是本身(∵函数参数的地址传递),所以这里没有用return返回*q(当然也可以用)

代码是可以运行的,运行结果是

[username@host directory]$ ./test.out
5
32766

可以看到,第一次输出的是正确的值,但是第二次输出了一个随机值,这是为什么呢?

3. 原因(悬垂指针)

通过上面内存4区的介绍,可以知道:

fun()函数中的变量qi是局部变量,存放在栈区中,栈区由系统分配释放资源。

q和&p是本身,指向同一内存单元i

但是在函数fun()释放时,变量qi也被释放掉了。

综上,仅剩p指向i的躯壳(原对象不存在了),这里p就成了悬垂指针

悬垂指针指向的内存单元已经不属于该程序(堆区的东西被系统释放),再操作往往会导致程序错误,而且难以检测

但是为啥第一次输出时是正确的值5呢?

因为系统会为程序暂时保留值,但是这一次使用后就会彻底清除了,所以看到第二次取到的值是一个随机数。

4. 如何避免

不要返回局部变量地址!!!

不要返回局部变量地址!!!

不要返回局部变量地址!!!

如果要使用别个函数中局部变量地址,记得利用堆区!!!

堆区的内存区域是由开发者手动分配释放的,在手动释放前可以随意使用

4.1 C语言

利用动态内存管理的几个函数

  • malloc()

    分配指定字节数的内存区域,初始化为0,返回首地址的void指针(可强制转换后再使用)

// 分配连续的一段内存空间
// 大小为400字节(这里设int为4字节)
// 强制转换成int *类型的指针(同整形数组),例++p时,p指针向后移4个字节
p = (int*) malloc(100 * sizeof(int));
  • calloc()

    类似malloc(),但不初始化

// 分配连续的一段内存空间
// 大小为25个int类型大小的区域
// 强制转换成int *类型的指针(同整形数组),例++p时,p指针向后移4个字节
p = (int*) calloc(25, sizeof(int));
  • realloc()

    更改以前分配的内存的大小

// 以x的大小,形同当前p指针,重新分配内存
p = realloc(p, x);
  • free()

    释放已分配的内存区域

free(p);
// 之后再p再次被分配内存之前,不能再使用

4.2 C++

4.2.1 使用new和delete

例,使用new为数组申请内存空间

// 分配5个int类型元素的数组空间
// 并将前三个元素初始化11、22、33
int *p = new int[5]{11, 22, 33};

4.2.2 使用智能指针

在C++11之后的版本,包含头文件<memory>后,可使用auto_ptr、unique_ptr、shared_ptr和weak_ptr四个智能指针

4. 总结

  1. 局部变量在程序运行时存放在栈区,在函数释放空间会被系统收回。此时再操作会引起程序错误

  2. 不要返回局部变量地址!!!

  3. 如果要使用其他函数中局部变量地址,要利用堆区!!!

发布了10 篇原创文章 · 获赞 34 · 访问量 606

猜你喜欢

转载自blog.csdn.net/qq_33973359/article/details/105456099