动态内存管理-2

简介: 动态内存管理

五. 动态内存经典笔试题分析

说明:以下题目来源于《高质量c++/c编程指南》


5.1 题目1

void GetMemory(char* p)
{
   p = (char*)malloc(100);
   }
void test(void)
{
   char* str = NULL;
   GetMemory(str);
  strcpy(str, "hello world");
   printf(str);
     free(str);
}
int main()
{
    test();
   return 0;
}


程序会崩溃,有俩点原因:1、str传的是空指针,p是对str另外一份临时拷贝,p指针指向一片动态内存开辟空间不会影响str,所以下面的函数对null指针进行解引用操作;


2、void GetMemory(char* p)这个函数申请的空间没有进行free操作,导致内存泄漏。


怎么样修改才对呢?


第一种改法:

void GetMemory(char** p)
{
   *p = (char*)malloc(100);
   }
void test( )
{
   char* str = NULL;
   GetMemory(&str);
  strcpy(str, "hello world");
   printf(str);
    str = NULL;
 }
int main()
{
  test();
  return 0;
}


此时*p就是str,修改*p就是修改str.


第二种改法:

#include<string.h>
char* GetMemory()
{
  char* p = (char*)malloc(100);
   return p;
 }
void test( )
{
   char* str = NULL;
  str= GetMemory();
  strcpy(str, "hello world");
   printf(str);
   free(str);
   str = NULL;
 }
int main()
{
  test();
  return 0;
}


此时对于GetMemory()传参没有什么用处,所以可以不用传参。


5.2 题目2

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


局部变量所申请的空间随函数调用结束,返还给操作系统,所以str所指向的空间不属于主函数,属于非法访问。


属于返回栈空间地址问题(str属于野指针)


5.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);
   }
 int main()
 {
   Test();
   return 0;
 }


这个和第一道差不多,可以正常打印出来,但是没有free,容易造成内存泄漏。


5.4 题目

void Test(void)
 {
  char* str = (char*)malloc(100);
   strcpy(str, "hello");
   free(str);
   if (str != NULL)
     {
     strcpy(str, "world");//非法访问
     printf(str);
     }
   }
int main()
{
  Test();
  return 0;
}


因为str指向的空间已经释放了,str为野指针,属于非法访问。


六 柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。

C99 中,结构体中的最后⼀个元素允许是未知⼤⼩的数组,这就叫做『柔性数组』成员。

例如:

 typedef struct st_type
2 {
3 int i;
4 int a[];//柔性数组成员
5 }type_a;

或者


 typedef struct st_type
2 {
3 int i;
4 int a[0];//柔性数组成员
5 }type_a;


6.1 柔性数组的特点

• 结构中的柔性数组成员前⾯必须⾄少⼀个其他成员。 (至少俩个成员)

• sizeof 返回的这种结构⼤⼩不包括柔性数组的内存。

• 包含柔性数组成员的结构⽤malloc ()函数进⾏内存的动态分配,并且分配的内存应该⼤于结构的大小,以适应柔性数组的预期⼤⼩。

举例:

代码1:

 struct st_type  
 {
   int i;
  int a[0];//柔性数组成员
 };
int main()
 {
   printf("%d\n", sizeof(struct st_type));//输出的是4
   return 0;
   }
 int main()
{
  int i = 0;
  struct st_type* p = (struct st_type*)malloc(sizeof(struct st_type) + 100 * sizeof(int));
   //业务处理
     p->i = 100;
   for (i = 0; i < 100; i++)
     {
     p->a[i] = i;
     }
   free(p);
   return 0;
   }


6.2 柔性数组的优势

代码2:


struct st_type
   {
  int i;
   int* p_a;
   };
   int main()
    {
     struct st_type* p = (struct st_type*)malloc(sizeof(struct st_type));
    p->i = 100;
    p->p_a = (int*)malloc(p->i * sizeof(int));
    int i = 0;
      //业务处理
   for (i = 0; i < 100; i++)
    {
     p->p_a[i] = i;
     }
      //释放空间
      free(p->p_a);
    p->p_a = NULL;
    free(p);
    p = NULL;
    return 0;
    }


上述 代码 1 和 代码 2 可以完成同样的功能,但是⽅法 1 的实现有两个好处:


第一个好处是:方便内存释放

如果我们的代码是在⼀个给别⼈⽤的函数中,你在⾥⾯做了⼆次内存分配,并把整个结构体返回给用户。⽤户调⽤free可以释放结构体,但是⽤户并不知道这个结构体内的成员也需要free,所以你不能 指望⽤⼾来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存⼀次性分配好了,并返 回给⽤⼾⼀个结构体指针,⽤⼾做⼀次free就可以把所有的内存也给释放掉。


第二个好处是:这样有利于访问速度.

连续的内存有益于提⾼访问速度,也有益于减少内存碎片。


七. 总结C/C++中程序内存区域划分

beca35eb6bd714d5dda5e27a9d77b91b_a3ba9879855543dc90e00d5c4c33d7a5.png


C/C++程序内存分配的⼏个区域:

1. 栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时 这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内 存容量有限。 栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等。栈区的详解可看(函数栈帧的创建与销毁)

2. 堆区(heap):⼀般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收 。分配⽅式类似于链表。

3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。

4. 代码段:存放函数体(类成员函数和全局函数)的⼆进制代码。

相关文章
|
3天前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
12 3
|
1月前
|
程序员
动态内存管理
动态内存管理
12 0
|
5月前
|
存储 Linux C语言
5.C++动态内存管理(超全)
5.C++动态内存管理(超全)
|
5月前
|
程序员
21.动态内存管理
21.动态内存管理
|
6月前
|
程序员 编译器 C语言
带你彻头彻尾了解『动态内存管理』
带你彻头彻尾了解『动态内存管理』
|
6月前
|
安全 C++ 开发者
c++动态内存管理(二)
c++动态内存管理(二)
139 0
|
11月前
|
程序员 编译器 C语言
动态内存管理(2)
动态内存管理(2)
47 0
|
编译器 文件存储 数据库
Day_17> 动态内存管理
Day_17> 动态内存管理
|
程序员 编译器 C语言
动态内存管理(上)
动态内存管理(上)
45 0
|
编译器 C++
动态内存管理详解
动态内存管理详解
123 0