动态内存管理(二)

简介: 动态内存管理

4.经典笔试题


4.1 题目一


void Memory(char* ptr)
{
  ptr = (char*)malloc(20);
}
void test()
{
  char* p = NULL;
  Memory(p);
  strcpy(p, "crush");
  printf(p);
}
int main()
{
  test();
  return 0;
}


0fc3d974f6b54ad217d05819ba4e56f4_d913589276ce4173aa6ad2ef1d58a0c0.png

1.当程序开辟动态内存退出函数Memory时,临时变量ptr被销毁,开辟的动态内存没有被释放,再也找不到,由此造成内存泄漏。 2.p是空指针,strcpy执行时,会对p解引用然后会崩溃的


4.2 题目二


char* Memory()
{
  char ch[] = "hello crush";
  return ch;
}
void test()
{
  char* p = NULL;
  p = Memory();
  printf(p);
}
int main()
{
  test();
  return 0;
}


当程序离开函数 Memory时,数组 char ch[]就会被销毁,所以指针 p接收到一块不明内容的地址,打印结果就是未知的,也就是野指针。


d5a4b45c8130af8eca3a4c59da3d0963_c62b48a1b87b4e4cb5bbb5894b8bad8e.png


4.3 题目三


void Memory(char** ptr, int num)
{
  *ptr = (char*)malloc(num);
}
void test()
{
  char* p = NULL;
  Memory(&p, 20);
  strcpy(p, "crush");
  printf(p);
}
int main()
{
  test();
  return 0;
}


3018eaa2eff3de71682b58c2815eb1e9_91773a8d71bb420bbfedcca9d46d5698.png


唯一的缺点就是没有对开辟的动态内存进行释放,和将指针置为空指针。


9aae90a9611e1105c4ab77daca9ed836_0f70979dc23f4f38b93968d67b0cf63b.png


4.4 题目四


void test()
{
  char* p = (char*)malloc(20);
  strcpy(p, "crush");
  free(p);
  if (p != NULL)
  {
  strcpy(p, "crush");
  printf(p);
  }
}
int main()
{
  test();
  return 0;
}


8009fbfb87b870711737f6fc79f39385_bf2e24cefbe742f79982627c6feba159.png


典型野指针,动态开辟的内存被释放之后,指针 p只能记得地址,但不能继续使用,因此变成野指针。


5.柔性数组


C99标准中,结构体中最后一个元素允许是未知大小的数组,称作柔性数组


struct M
{
  int i;
  int arr[];//柔性数组
};

5.1柔性数组的特点


1. 结构体中的柔性数组成员前面必须至少一个其他成员
 2. sizeof返回结构体大小时,不包括柔性数组的内存
 3. 包含柔性数组的结构体需要用malloc()函数进行内存的动态分配
 并且分配的内存必须大于结构体的大小,以满足柔性数组对内存的需求


struct M
{
  int i;
  int arr[];//柔性数组
};
int main()
{
  printf("%d\n", sizeof(struct M));
  return 0;
}

image.png


5.2柔性数组的使用

#include<stdio.h>
#include<string.h>
#include<errno.h>
struct M
{
  int n;
  int arr[];//柔性数组
};
int main()
{
  //柔性数组的使用
  struct M* p = (struct M*)malloc(sizeof(struct M) + 20);
  if (p == NULL)
  {
  printf("%s\n", strerror(errno));
  return;
  }
  p->n = 0;
  int i = 0;
  for (i = 0; i < 5; i++)
  {
  p->arr[i] = i;
  }
  for (i = 0; i < 5; i++)
  {
  printf("%d ", p->arr[i]);
  }
  printf("\n");
  //扩容
  struct M* ptr = (struct M*)realloc(p, 40);
  if (ptr != NULL)
  {
  p = ptr;
  }
  //释放内存
  free(p);
  p = NULL;
  return 0;
}



78113f521b98908f0c8806f197b9dd07_66cd08e446844590b041dc57ab099869.png

e424c0f24f17830a34d5109c739a2a2d_64083aa63d2340aeb3206761353087e2.png


类似柔性数组的使用方法


#include<stdio.h>
#include<string.h>
#include<errno.h>
struct M
{
  int n;
  int* arr;
};
int main()
{
    //动态内存开辟
  struct M* p = (struct M*)malloc(sizeof(struct M));
  if (p == NULL)
  {
  printf("%s\n", strerror(errno));
  return;
  }
  p->n = 0;
  p->arr = (int*)malloc(20);
  int i = 0;
  for (i = 0; i < 5; i++)
  {
  p->arr[i] = i;
  }
  for (i = 0; i < 5; i++)
  {
  printf("%d ", p->arr[i]);
  }
  //扩容
  int* ptr = (int*)realloc(p->arr, 40);
  if (ptr != NULL)
  {
  p->arr = ptr;
  }
  //释放
  free(p->arr);
  free(p);
  p = NULL;
  return 0;
}


1415397e54229aae30ceb2fa0255fbbd_118832a7ead64de38d816e2760df5256.png

300bd97112cb33e13d1849d708968a91_f249410db7c24501a18c86546aba5f7e.png


5.3柔性数组的优点


上面两种方法都可以实现相同的目的-柔性数组的使用

相比之下,还是第一种方法更好一些


优点1:方便内存释放

第一种方法只需要释放一次内存即可,而第二种方法需要释放两次


优点2:访问速度更快

连续的内存有利于提高访问速度,也有利于减少内存碎片


目录
相关文章
|
6月前
|
编译器 C语言
动态内存管理(1)
动态内存管理(1)
52 4
|
C语言 Python
动态内存管理(下)
动态内存管理(下)
59 0
|
6月前
|
程序员
21.动态内存管理
21.动态内存管理
|
7月前
|
程序员 编译器 C语言
带你彻头彻尾了解『动态内存管理』
带你彻头彻尾了解『动态内存管理』
|
7月前
|
编译器 程序员 C语言
动态内存管理(超详细!)
动态内存管理(超详细!)
64 2
|
7月前
|
程序员 C语言 C++
详解动态内存管理!
详解动态内存管理!
|
程序员 C语言 C++
动态内存管理-2
动态内存管理
50 0
|
编译器 文件存储 数据库
Day_17> 动态内存管理
Day_17> 动态内存管理
动态内存管理(下)
动态内存管理(下)
43 0
|
C语言
动态内存管理(上)
动态内存管理(上)
50 0