C语言-动态内存分配(12.1)

简介: C语言-动态内存分配(12.1)

思维导图:



1.为什么存在动态内存分配

我们现在学习了一些内存开辟的方式:


int main()
{
  int i;//在内存栈区开辟4个字节空间
  char arr[5];//在栈空间上开辟5个字节的连续空间
  return 0;
}

但是,这样开辟的内存是静态的,固定的:


1. 空间开辟大小是固定的。


2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。


如果想要在编译过程中开辟空间,就需要用到动态内存。


2.动态内存函数的介绍

2.1 malloc

void* malloc (size_t size)


2.2 free

void free (void* ptr)


例:


#include 
#include 
int main()
{
  //申请40给字节,用来存放10个整形
  int* p = (int*)malloc(40);//malloc申请的空间不会初始化
  if (p == NULL)            //直接返回起始地址
  {
  perror("malloc");//如果空间开辟失败要报错并返回
  return 1;
  }
  //使用空间
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  printf("%d\n", *(p + i));
  }
  //释放申请的内存
  free(p);
  p = NULL;
  return 0;
}

输出:


输出:

-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451

malloc不会自己初始化,所以打印随机值。


例:


#include 
#include 
int main()
{
  //申请40给字节,用来存放10个整形
  int* p = (int*)malloc(40);//malloc申请的空间没有初始化
  if (p == NULL)            //直接返回起始地址
  {
  perror("malloc");//如果空间开辟失败要报错并返回
  return 1;
  }
  //使用空间
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  *(p + i) = i + 1;//初始化赋值
  printf("%d ", *(p + i));
  }
  //释放申请的内存
  free(p);
  p = NULL;
  return 0;
}

输出:


输出:1 2 3 4 5 6 7 8 9 10

2.3 calloc

void* calloc (size_t num, size_t size)


例:


#include 
#include 
int main()
{
  int* p = (int*)calloc(10, sizeof(int));//10是要初始化的个数,sizeof(int)是每个的大小
  if (NULL == p)
  {
  perror("calloc");//判断内存是否申请成功
  return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  printf("%d ", *(p + i));//calloc申请空间后,会把空间初始化成0
  }                                              //再返回起始地址
  //释放
  free(p);
  p = NULL;
}


输出:


输出:0 0 0 0 0 0 0 0 0 0

2.4 realloc

void* realloc (void* ptr, size_t size)


realloc函数可以追加更多动态内存。


例:


#include 
#include 
int main()
{
  int* p = (int*)malloc(5 * sizeof(int));//开辟一段动态内存20个字节
  if (NULL == p)
  {
  perror("malloc");//检查是否创建成功
  return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 5; i++)
  {
  *(p + i) = i + 1;
  }
  //不够用,增加5个整形的空间
  int* ptr = (int*)realloc(p, 10 * sizeof(int));//这里是开辟到40个字节
  //realloc函数开辟内存空间有两种情况:
  //1.原内存块后面空间足够,在原内存块后面追加内存
  //2.原内存块后面空间不够,另外找一片区域开辟内存,将原内存块释放
  if (ptr != NULL)
  {
  p = ptr;//为什么不直接用p接收?
  //如果内存追加失败,直接用p接收的话,原本已经开辟的动态内存空间就会被覆盖
  }
  for (i = 0; i < 10; i++)
  {
  printf("%d ", *(p + i));
  }
  //释放
  free(p);
  p = NULL;
  return 0;
}

输出:


输出:

1 2 3 4 5 -842150451 -842150451 -842150451 -842150451 -842150451

3.常见的动态内存错误

例1:


开辟动态内存记得要判断,最后释放内存。


#include 
#include 
int main()
{
  int* p = (int*)malloc(100);
  //内存开辟后没有判断是否开辟成功
  int i = 0;
  for (i = 0; i < 10; i++)
  {
  *(p + i) = 0;//危险代码,我们无法知道是否存在非法访问
  }
  //并且最后也没有将开辟的内存还给操作系统
  return 0;
}

例2:


动态内存开辟了多少就用多少,小心越界访问。


#include 
#include 
int main()
{
  int* p = (int*)malloc(100);//开辟了100字节空间
  //判断
  if (p == NULL)
  {
  perror("malloc");
  return 1;
  }
  int i = 0;
  for (i = 0; i < 100; i++)//造成越界访问
  {
  *(p + i) = 0;//一个整形4个字节
  }
  //释放
  free(p);
  p = NULL;
  return 0;
}

例3:


不要乱释放其他内存空间。


int main()
{
  int a = 10;
  int* p = &a;
  //你没有权限乱释放其他的内存空间
  free(p);//不能对栈区的内存释放
  return 0;
}

例4:


不要多次释放内存空间。


#include 
#include 
int main()
{
  //开辟空间
  int* p = (int*)malloc(100);
  //判断
  if (p == NULL)
  {
  perror("malloc");
  return 1;
  }
  //使用
  int i = 0;
  for (i = 0; i < 25; i++)
  {
  *p = i;
  p++;//p指针不断往后移动
  }
  //释放的时候指针应该指向起始地址,否则程序又会出错
  free(p);
  p = NULL;
  return 0;
}

例5:


#include 
#include 
int main()
{
  //创建
  int* p = (int*)malloc(100);
  //判断
  if (p == NULL)
  {
  return 1;
  }
  //释放
  free(p);
  free(p);//已经释放了,重复释放会导致程序出错
  return 0;
}

这就要说到最后置为空指针的好处了:


#include 
#include 
int main()
{
  //创建
  int* p = (int*)malloc(100);
  //判断
  if (p == NULL)
  {
  return 1;
  }
  //释放
  free(p);
  p = NULL;//置为空指针后程序就不会崩溃了
  free(p);//p为空指针时,程序不会报错
  return 0;
}


例5:


在实现函数时开辟了动态内存要记得及时释放或者返回地址,


不然就再也找不到那段内存空间了,最后导致内存泄漏。


#include 
#include 
void test()
{
  int* p = (int*)malloc(100);
  //忘记释放
}//出了函数就找不到了,因为变量p被销毁了
//造成内存泄漏
int main()
{
  test();
  return 0;
}


例6:


这道题也是类似的:


#include 
#include 
void test()
{
  int* p = (int*)malloc(100);
  if (p == NULL)
  {
  return;
  }
  //使用
  if (1)
  return;//出问题//内存泄漏
  //释放
  free(p);
  p = NULL;
}
int main()
{
  test();
  return 0;
}


要小心出现内存泄漏,记得释放空间。


写在最后:

以上就是本篇文章的内容了,感谢你的阅读。


如果喜欢本文的话,欢迎点赞和评论,写下你的见解。


如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。


之后我还会输出更多高质量内容,欢迎收看。


相关文章
TU^
|
13天前
|
C语言
C语言内存函数和字符串函数模拟实现
C语言内存函数和字符串函数模拟实现
TU^
26 0
|
7天前
|
存储 算法 C语言
C语言指针与二维数组在函数参数传递和动态内存管理中的应用
C语言指针与二维数组在函数参数传递和动态内存管理中的应用
16 0
|
7天前
|
存储 C语言
C语言变量的内存地址深入探究
C语言变量的内存地址深入探究
25 0
|
8天前
|
存储 程序员 C语言
C语言(15)----动态内存讲解
C语言(15)----动态内存讲解
18 1
|
8天前
|
C语言
C语言(11)----内存函数
C语言(11)----内存函数
13 1
|
8天前
|
存储 测试技术 C语言
C语言内存管理函数研究
C语言内存管理函数研究
16 0
|
9天前
|
存储 编译器 C语言
玩转C语言——C语言中内存存储
玩转C语言——C语言中内存存储
16 0
|
9天前
|
程序员 编译器 C语言
C语言——动态内存管理
C语言——动态内存管理
14 0
|
9天前
|
C语言
C语言内存操作函数
C语言内存操作函数
16 1