✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
31. 有哪些情况可能会申请内存失败?
-
内存不足:当操作系统没有足够的可用内存时,new 和 malloc 都可能会失败。这通常发生在系统资源紧张的情况下,例如在同时运行多个大型程序时。
-
内存碎片化:内存碎片是指已分配的内存块之间存在未分配的小块,这可能会使大块内存无法分配。如果内存被分配和释放的方式不同,或者程序不断分配和释放内存,可能会导致内存碎片化,使得 new 和 malloc 无法成功分配所需的连续内存块。
-
操作系统限制:有些操作系统可能会限制进程可用的最大内存量或者单个内存块的最大大小。如果申请的内存超过了这些限制,new 和 malloc 都会失败。
-
内存泄漏:如果程序中存在内存泄漏,即已分配的内存没有被正确释放,可能会导致内存耗尽,从而使 new 和 malloc 无法分配所需的内存。
32. 如果使用 double free 会发生什么?
-
崩溃:释放同一块内存两次会破坏内存管理的数据结构,导致程序崩溃。这是因为第一次释放时释放了内存,并将其标记为可用,而第二次释放时也试图释放同一块内存,但此时该块内存已被标记为可用,不再属于该程序使用范围。
-
内存损坏:双重释放会导致内存损坏,可能会改变内存中的数据。这种情况下,程序可能在后续的内存访问时出现未定义的行为或导致数据不一致性。
-
不可预测的行为:双重释放可能导致程序进入不可预测的状态,导致不一致的结果。这可能会导致运行时错误、段错误或内存泄漏等问题。
33. C++ 函数调用 的压栈过程
(1) 以例子进行讲解
从代码入手,解释这个过程:
#include <iostream>
using namespace std;
int f(int n)
{
cout << n << endl;
return n;
}
void func(int param1, int param2)
{
int var1 = param1;
int var2 = param2;
printf("var1=%d,var2=%d", f(var1), f(var2));//如果将printf换为cout进行输出,输出结果则刚好相反
}
int main(int argc, char* argv[])
{
func(1, 2);
return 0;
}
//输出结果
//2
//1
//var1=1,var2=2
当函数从入口函数 main 函数开始执行时,编译器会将我们操作系统的运行状态,main 函数的返回地址、main 的参数、mian 函数中的变量,进行依次压栈;
当 main 函数开始调用 func() 函数时,编译器此时会将 main 函数的运行状态进行压栈,再将 func() 函数的返回地址、func() 函数的参数从右到左、func() 定义变量,依次压栈;
当 func() 调用 f() 的时候,编译器此时会将 func() 函数的运行状态进行压栈,再将的返回地址、f() 函数的参数从右到左、f() 定义变量,依次压栈;
从代码的输出结果可以看出,函数 f(var1)、f(var2) 依次入栈,而后先执行 f(var2),再执行 f(var1),最后打印整个字符串,将栈中的变量依次弹出,最后主函数返回。
(2) 文字化表述
函数的调用过程:
1)从栈空间分配存储空间
2)从实参的存储空间复制值到形参栈空间
3)进行运算
形参在函数未调用之前都是没有分配存储空间的,在函数调用结束之后,形参弹出栈空间,清除形参空间。
数组作为参数的函数调用方式是地址传递,形参和实参都指向相同的内存空间,调用完成后,形参指针被销毁,但是所指向的内存空间依然存在,不能也不会被销毁。
当函数有多个返回值的时候,不能用普通的 return 的方式实现,需要通过传回地址的形式进行,即地址/指针传递。