详解动态内存管理(二)

简介: 详解动态内存管理

4. 几个经典的笔试题


4.1 题目1:


void GetMemory(char *p)     
{
  p = (char *)malloc(100);   
}
void Test(void)
{
  char *str = NULL;
  GetMemory(str);   
  strcpy(str, "hello world");
  printf(str);   //注意,该行代码没有错误!解析会讲
}

输出:


42ffa855fc63489f9950c59314734ab5.png


解析:


void GetMemory(char *p)    //用形参 p 接收 str 
{
  p = (char *)malloc(100);    //将动态开辟的内存首地址传给指针变量 p ,并没有传给 str
}
void Test(void)
{
  char *str = NULL;
  GetMemory(str);      //函数调用结束后,str 还是空指针
  strcpy(str, "hello world");    //无法将该字符串复制到空指针内
  printf(str);
}


为什么可以这样写:


printf(str);


我们先来看看 printf 函数的原型:


int printf ( const char * format, ... );


将格式所指向的 C 字符串写入标准输出(标准输出)。如果 format 包含格式说明符(以 % 开头的子序列),则格式后面的其他参数将被格式化并插入到结果字符串中,以替换它们各自的说明符。


还记得我们之前接触的 printf 的写法有:


printf("hello world");


之所以能打印出来,是因为我们将字符串的首元素 ‘h’ 的地址传入了 printf 函数中,那么我们直接传字符串的首元素地址 str 也是一样的


4.2 题目2:


char *GetMemory(void)
{
  char p[] = "hello world";
  return p;
}
void Test(void)
{
  char *str = NULL;
  str = GetMemory();
  printf(str);
}

输出:


07786f668a9543a29bbd6e5cdb09251b.png


解析:


char *GetMemory(void)
{
  char p[] = "hello world";
  return p;   //指针p指向了字符‘h’,
}             
void Test(void)
{
  char *str = NULL;
  str = GetMemory();  //接收指针p的值,但当该函数调用结束后,局部变量 p 所指向的内容就被销毁了
  printf(str);        //所以打印出来就是乱码
}


4.3 题目3:


void GetMemory(char **p, int num)
{
  *p = (char *)malloc(num);
}
void Test(void)
{
  char *str = NULL;
  GetMemory(&str, 100);
  strcpy(str, "hello");
  printf(str);
}


输出:


7fb7b258198c42079832d68aca5ffa83.png


咋一看,似乎没啥问题,虽然输出没问题,但是我们开辟的动态内存没有进行释放,导致了内存泄漏,这虽然不影响结果,但也是很严重对问题。


4.4 题目4:


void Test(void)
{
  char* str = (char*)malloc(100);
  strcpy(str, "hello");
  free(str);
  if (str != NULL)
  {
  strcpy(str, "world");
  printf(str);
  }
}


输出:


870e91bf84494ab1b730a637fab0b494.png


输出没有问题,我们看下面的警告,因为本题没有判断 str 是否为空,所以在复制字符串的时候警告,当 free 完后,那块动态内存开辟的空间就不属于我了,str 就是野指针了,再进行访问就是非法访问。

我们可以对其进行修改一下:


void Test(void)
{
  char* str = (char*)malloc(100);
  if(str == NULL)     //判断是否为空指针
  return 1;
  strcpy(str, "hello");
  free(str);
  str = NULL;  //养成习惯,free 后就置空,防止野指针
  if (str != NULL)     //这样就不会再出错了
  {
  strcpy(str, "world");
  printf(str);
  }
}


最后


下期讲解 C/C++ 程序的内存开辟和柔性数组。


相关文章
|
编译器
【动态内存管理】
【动态内存管理】
61 0
|
5月前
|
程序员
21.动态内存管理
21.动态内存管理
|
6月前
|
程序员 编译器 C语言
带你彻头彻尾了解『动态内存管理』
带你彻头彻尾了解『动态内存管理』
|
6月前
|
编译器 程序员 C语言
动态内存管理(超详细!)
动态内存管理(超详细!)
56 2
|
6月前
|
安全 C++ 开发者
c++动态内存管理(二)
c++动态内存管理(二)
139 0
|
6月前
|
存储 安全 算法
c++动态内存管理(一)
C++ 动态内存管理 在 C++ 中,动态内存管理是一个核心概念,它允许在运行时分配和释放内存。以下是 C++ 动态内存管理需要掌握的关键知识点:
164 0
|
11月前
|
编译器
动态内存管理(1)
动态内存管理(1)
59 0
|
11月前
|
程序员 编译器 C语言
动态内存管理(2)
动态内存管理(2)
47 0
|
C语言
动态内存管理(上)
动态内存管理(上)
46 0
|
程序员 编译器 C++
【C】动态内存管理详解
C/C++程序内存分配的几个区域: 1.栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 2.堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。 3.数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。 4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。
【C】动态内存管理详解