【C++ 高频面试题】指针和引用、关于内存泄漏和野指针问题
文章目录
- 1. 静态变量、全局变量、局部变量
- 2. 指针和引用的区别
- 3. 内存泄漏
- 4. 野指针
1. 静态变量、全局变量、局部变量
- ①局部变量:
作用范围:局部变量只在定义它的函数或代码块内有效,函数执行结束后,局部变量即失效。
生命周期:局部变量的生命周期与其作用域相同,函数或代码块执行结束后,局部变量的内存就被释放。
内存分布:局部变量通常存储在栈中。栈内存是自动管理的,局部变量在函数调用时分配,在函数结束时自动释放。
- ②全局变量:
作用范围:全局变量在整个程序的生命周期中都可以访问,它的作用范围从定义位置开始,到程序结束为止。
生命周期:全局变量从程序开始运行时分配内存,直到程序结束时释放。
内存分布:全局变量存储在全局/静态存储区,通常分为初始化的全局变量区和未初始化的全局变量区。
- ③静态变量
作用范围:
静态局部变量:与局部变量类似,但其作用范围仍然限制在定义它的函数或代码块内。
静态全局变量:只能在定义它的文件中使用,不能被其他文件访问(用于隐藏全局变量)。
生命周期:无论是静态局部变量还是静态全局变量,它们的生命周期都是整个程序的运行期间,与全局变量类似。静态局部变量只在第一次调用函数时初始化,后续函数调用时不会再重新初始化。
内存分布:静态变量也存储在全局/静态存储区,与全局变量共享同一内存区域。
2. 指针和引用的区别
🐧指针存放某个对象的地址,其本身就是变量,本身就有地址,所以可以有指向指针的指针。指针是可变的,包括所指向的地址的改变和其所指向地址中存放数据的改变。
⚽引用就是变量的别名,从一而终,不可改变,必须初始化。
不存在指向空值的引用,但存在指向空值的指针。
-
①定义和声明
指针是一个变量,其值是另一个变量的地址。声明指针时,使用*
符号。
引用是一个别名,它是在已存在的变量上创建的。在声明引用时,使用&
符号。
-
②使用和操作
-
③空值和空引用
指针可以为空(nullptr)表示不指向任何有效的地址。引⽤必须在声明时初始化,并且不能在后续改变引⽤的绑定对象。因此,没有空引⽤的概念。
-
④可变性
-
⑤用途
指针:通常用于动态内存分配、数组操作以及函数参数传递。引用:用于函数参数传递、操作符重载以及创建别名。
3. 内存泄漏
-
🐧①什么是内存泄漏?
内存泄漏是由于程序员疏忽造成程序未能正确释放掉不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。可以使用
Valgrind
,mtrace
内存泄漏工具进行检查
-
🐧②内存泄漏的分类
-
🐧③什么操作会导致内存泄漏
指针指向改变,未释放动态分配内存。 -
🐧④如何防⽌内存泄露?
将内存的分配封装在类中,构造函数分配内存,析构函数释放内存;使⽤智能指针
4. 野指针
🐧 野指针是指指向已被释放的或者无效的内存地址的指针。使用野指针可能会导致程序崩溃、数据损坏或其他不可预测的行为。
-
🏀①释放后没有置空指针
-
🏀②返回局部变量的指针
-
🏀③释放内存后没有调整指针
-
🏀④函数参数指针被释放
- 🐧如何避免野指针呢?
①释放内存后将指针置为 nullptr
②避免返回局部变量的指针
③使用智能指针 (如 std::unique_ptr 和 std::shared_ptr
)
④注意函数参数的生命周期,避免在函数内释放调用方传递的指针,或者用过引用传递指针。
-
🐧野指针和悬浮指针的区别
野指针是指向已经被释放或者无效的内存地址的指针。通常由于指针指向的内存被释放,但指针本身没有被置为nullptr
或者重新分配有效的内存,导致指针任然包含之前的内存地址。使用野指针进行访问会导致未定义行为,可能引发程序崩溃、数据损坏等问题。悬浮指针是指向已经被销毁的对象的引用。当函数返回一个局部变量的引用,而调用者使用该引用时,就可能产生悬浮引用。访问悬浮引用会导致未定义行为,因为引用指向的对象已经被销毁,数据不在有效。
关联对象的类型:
1)野指针涉及指针类型;
2)悬浮指针涉及引用类型;问题表现:
1)野指针可能导致访问已释放或无效内存,引发崩溃和数据损坏;
2)悬浮指针可能导致访问已销毁的对象,引发未定义行为;产生原因:
1)野指针通常由于不正确管理指针生命周期引起;
2)悬浮指针通常由于在函数中返回局部变量的引用引起;如何避免悬浮指针:
1)避免在函数中返回局部变量的引用;
2)使用返回指针或智能指针而不是引用,如果需要在函数之外使用函数内部创建的对象。