动态内存管理(动态内存管理函数) malloc calloc realloc

  • 动态内存函数malloc  free  (成对出现)

1.malloc——动态内存开辟函数——开辟后未初始化,内存中存放的是随机值。

void* malloc(size_t size)// ——函数原型

这个函数向内存申请一块连续可用空间,并返回指向这块空间的指针。

-如果开辟成功,则返回一个指向开辟好空间的指针

-如果开辟失败,则反回一个NULL指针因此malloc的返回值一定要做完检查再使用。

-返回类型是void*,所以malloc函数并不知道开辟的空间类型,具体再使用者使用的时候决定(强转)。

-如果 size为0,则malloc的行为是标准未定义的,取决于编译器。

2.free——动态内存回收释放函数

c语言提供了free函数,专门用来做动态内存的释放和回收的

void* free(void* ptr)——函数原型  (ptr)是malloc返回的那个指向开辟空间的指针。

free(ptr)后需要把ptr指针置为NULL。

free函数用来释放动态开辟的内存。

-如果参数ptr指向的空间不是动态内存所开辟的,那么free函数的行为未定义。

-如果ptr是NULL指针,则函数什么都不干

malloc free 函数都在头文件stdlib.h头文件中。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <errno.h>
int main()
{
           //代码1
           int num = 0;
           sacnf("%d", &num);
           int arr[num] = {0};
           //代码2
           int *ptr =(int *)malloc(num*sizeof(int));//动态空间的开辟
           if (ptr==NULL)//判断动态内存是否开辟成功!!!
           {
                      printf("%s\n", strerror(errno));//打印错误原因
           }
           else
           {
                      int i = 0;
                      for (i = 0; i < num; i++)
                      {
                                 *(ptr + i) = 0;//将开辟的动态空间初始化
                      }
           }
           free(ptr);//释放了ptr所指向的动态内存。
           ptr = NULL;//将ptr保存的之前开辟的动态空间的地址置NULL
           system("pause");
           return 0;
}
  • calloc 函数 free(成对出现)使用需要注意的事项与malloc都相同。

1.calloc函数与malloc 对比只要有两个区别,函数原型,calloc在返回地址之前已经把开辟空间每个字节都初始化为0。

void*calloc( size_t num, size_t size);——函数原型

3.ptr 是要调整的内存地址。

4.size是调整之后新的大小。

5.返回值为调整之后的内存起始位置。

6.这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。(存在两种情况。)

7.realloc在调整内存空间有两种情况

--原有空间之后足够大

--原有空间之后没有足够的空间。

情况1时:要扩展的内存就直接在原有内存之后直接追加,原有空间不发生变化。(原来开辟空间返回的指针(地址)不发生改变)

情况2时:原有空间之后没有足够大的空间,在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新内存地址(原来开辟的空间realloc函数自行free掉了然后重新开辟新的大小的空间并返回新的指针(地址)。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <errno.h>
int main()
{
           int *ptr = malloc(100);
           if (ptr != NULL)
           {
                      //业务处理
           }
           else
           {
                      exit(EXIT_FAILURE);//失败退出
           }
           //扩展容量
           int *p = NULL;
           p = (int*)realloc(ptr, 1000);
           if (p != NULL)
           {
                      ptr = p;//将拓展后的新地址赋给原来开辟动态空间返回的指针。
           }
           //业务处理
           free(ptr);//释放动态内存
           ptr = NULL;//置为空指针
           return 0;
}
  • 常见的动态内存错误

1.对(动态开辟内存失败后返回的)NULL指针的进行接引用操作。

2.对动态开辟空间的越界访问。(注意控制连续动态内存访问循环的次数)

3.对非动态开辟的内存使用free释放。

4.使用free释放一块动态开辟的内存的一部分(不要对动态内存开辟后返回的指针本身进行操作,假如操作了则在free函数执行前将指针还原,然后free(释放回收)。否则将会发生错误且内存泄漏))

5.对同一快动态内存进行多次释放

6.动态内存忘记释放(内存泄漏)一定要正确释放成对出现只要有动态开辟函数在使用完后一定要进行释放操作(free,指针NULL)。

  • 经典笔试题

  • 柔性数组

结构体中最后一个元素允许是未知大小的数组,这就叫做柔性数组.

typedef struct st_type
{
           int i;
           int a[0];//或者int a[];//柔性数组成员
}type_a;

1.柔性数组的特点

a.结构体中的柔性数组前面必须至少有一个其他成员.

b.sizeof返回的这种结构体大小不包括柔性数组的内存。

c.包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于该结构体的大小,以适应柔性数组的预期大小

b.例子

           typedef struct st_type
           {
                      int i;
                      int a[0];//或者int a[];//柔性数组
           }type_a;
           printf("%d\n", sizeof(type_a));//输出4为结构体大小,不包括柔性数组大小。
           system("pause");
           return 0;
}

c.例子

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <errno.h>
int main()
{
           typedef struct st_type
           {
                      int i;
                      int a[0];//或者int a[];//柔性数组
           }type_a;
           int i = 0;
           type_a*p = (type_a*)malloc(sizeof(type_a)+100 * sizeof(int));
           p->i = 100;
           for (i = 0; i < 100; i++)
           {
                      p->a[i] = i;
           }
           free(p);
           p = NULL;
           system("pause");
           return 0;
}

2.柔性数组的优点

a.方便内存释放

b.有利于访问速度

连续的内存有益与访问速度,也有益于减少内存碎片.

猜你喜欢

转载自blog.csdn.net/SoYangA/article/details/81276885