【C语言菜鸟知识】——动态内存管理

-------------------------------------------------------------------------------------------------------------------------------------

< 1、栈 >
在全局变量是分配在内存中的静态储存区,非静态的局部变量是分配在内存中的动态储存区,这个储存区就是栈的区域。
< 2、堆 >
在内存中允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必声明部分定义,也不必等到函数结束时才释放,需要时可以随时开辟,不需要时随时释放。这些数据临时存放在一个特别的自由储存区,就是堆区。只能通过指针来引用

现在我们已学了两种开辟空间的方式,其一:int a = 0;这种一次开辟一小块空间,其二:int arr[10] = { 0 };这种一次开辟一大块空间。但这两种开辟方式是有局限性的,一旦开辟就无法再更改开辟空间的大小了。

举个例子:现创建了一个结构体数组,数组每个元素都是一个人的信息,而该数组能存放100个人的信息。但我仅需要存放3个人的信息,对于这个结构体数组来说,剩余的97个空间不就浪费了嘛;同理我需要存放120个人的信息,对于该数组来说是放不下的,而我又不能对其大小进行修改。

 

这两种开辟空间的方式是在栈区上开辟;栈区中申请的空间是固定死的无法修改。而动态内存是在堆区开辟空间

对于内存的动态分配管理,包括动态内存函数:malloc、calloc、realloc、free。要使用这几个函数就必须先引用一个头文件<stdlib.h>才行。

 

< 3、malloc >
在C语言中提供了动态内存分配的函数:

void* malloc(size_t size)

通过malloc函数,可以在堆区申请一块连续可用的空间供我们使用。
size ——表示我们要开辟多大的一块内存空间(单位是字节)。
该函数返回一个指针,指向已分配大小的内存。如果请求失败,则返回 NULL。

注意:
malloc内的参数是需要动态分配的字节数,而不是可以存储的元素个数!

当动态分配内存时,存储的是字符型数据,每个元素1字节,所以字节数刚好等于需要存储的元素个数(字符数+1);
如果存储的是整型或浮点型数据,字节数等于“需要存储的元素个数 * 一个元素的字节数”,
代码格式为:

type *var_name = (type*)malloc(sizeof(type)*num);

 

< 4、free >
free函数是专门用来释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。

void free(void* ptr)

1.ptr是我们申请的内存空间的起始地址。
2.如果ptr不是指向我们所开辟得内存空间,这是free函数未定义的,编译不会通过。
3.如果ptr是个空指针,那么free函数什么也不会做。

 

< 5、calloc >
calloc和malloc作用都是开辟一块内存空间。

void* calloc(size_t num,size_t size);

1、nitems -- 要被分配的元素个数。
2、size -- 元素的大小。
3、calloc会在内存中开辟num个大小为size的元素空间,并把空间的每个字节初始化为0。

4、malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。

注意:

calloc() 函数将分配的内存全部初始化为零。如果不需要初始化,可以使用 malloc() 函数代替。另外,使用 calloc() 函数时需要注意,如果分配的内存块过大,可能会导致内存不足的问题。

 

< 6、realloc >
realloc作用就是扩容

void* realloc(void* ptr,size_t size)

该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。
Ptr——指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
Size——内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。

1.ptr是要调整的内存空间的地址
2.size是调整后的空间大小
3.realloc调整可能面对下面两种情况:
a.内存空间后面还有足够大的空间,那么内存地址不变,内存空间变大。
b.内存空间后面没有足够大的空间,那么会找一个新的足够大的内存地址,将原内存空间的内容复制拷贝到新的内存地址空间,内存地址改变。

 

< 7、实例 >

            //使用 malloc分配了五个元素大小的动态分配内存,并将返回的指针赋给 data
            data = (uint8_t*) malloc(5 * sizeof(uint8_t));
            if (data == NULL)
            {
                // 内存分配失败,采取适当的处理措施
                printf("内存分配失败\n");
                return;
            }

            // 将数据复制到 data 中
            data[0] = 1;
            data[1] = 2;
            data[2] = 3;
            data[3] = 4;
            data[4] = 5;

            /* 打印最初的内存分配 */
            printf("Data1 = ");
            for (u8 i = 0; i < 5; i++)
            {
                printf("%d ", data[i]);
            }
            printf("\n");

            // 使用 realloc函数重新分配内存,将原先的五个元素扩展为十个元素大小的内存块
            data = (uint8_t*)realloc(data, 10 * sizeof(uint8_t));
            if (data == NULL)
            {
                // 内存重新分配失败,采取适当的处理措施
                printf("内存重新分配失败\n");
                return;
            }

            // 将新的数据复制到 data 中
            data[5] = 6;
            data[6] = 7;
            data[7] = 8;
            data[8] = 9;
            data[9] = 0;

            /* 打印重新的分配内存 */
            printf("Data2 = ");
            for (u8 i = 0; i < 10; i++)
            {
                printf("%d ", data[i]);
            }
            printf("\n");
            //使用 free函数释放了 data 数组的内存
            free(data);

打印出来结果:
使用 malloc分配了五个元素大小的动态分配内存,打印出来这五个元素。1、2、3、4、5
使用 realloc函数重新分配内存,将原先的五个元素扩展为十个元素大小的内存块。1、2、3、4、5、6、7、8、9、0

 

 

posted on 2023-09-25 10:43  凡仕  阅读(288)  评论(0)    收藏  举报