C语言 动态内存管理

编程入门 行业动态 更新时间:2024-10-18 10:21:32

C语言 动态<a href=https://www.elefans.com/category/jswz/34/1766335.html style=内存管理"/>

C语言 动态内存管理

1.动态内存函数

1.malloc函数和free函数

malloc函数的函数声明:

void* malloc (size_t size);

malloc函数和free函数的头文件都是

#include <stdlib.h>

malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
如果开辟成功,则返回一个指向开辟好空间的指针。
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己
来决定。
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器

free函数是专门做动态内存的回收和释放的。

free的函数声明为:

void free (void* ptr);

对于free函数:
如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。

(free函数在后面的动态内存函数中也会用到,其效果和使用方法是一样的)

举一个关于malloc函数和free函数的例子

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <stdlib.h>//malloc和free的头文件
#include <string.h>
#include <errno.h>
int main()
{int arr[10] = { 0 };int* p = (int*)malloc(40);//返回值为void* 要自己设置类型//开辟成功则返回一个指向开辟好空间的指针//开辟失败则返回NULL指针if (p == NULL){printf("%s\n", strerror(errno));return 1;}//使用int i;for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d\n", *(p + i));}//释放掉内存free(p);//动态内存的释放和回收//若free释放的不是动态内存 情况未定义p = NULL;return 0;
}

2.calloc函数

calloc函数也是用来动态内存分配,它的用法与malloc相似,但是多了一个参数,并且它可以将开辟出来的空间初始化,其作用相当于malloc函数加上memset函数的结合体。

calloc的函数声明为:

void* calloc (size_t num, size_t size);

calloc函数的功能是:

为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。

与函数 malloc 的区别在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
 

举个例子:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));//calloc会将开辟出来的内存初始化成0if (p == NULL){printf("%s\n", strerror(errno));return 1;}//打印int i;for (i = 0; i < 10; i++){printf("%d\n", *(p + i));}//释放free(p);p = NULL;return 0;
}

如果对开辟出来的空间又初始化为0的需求 那用calloc函数在合适不过了。

3.realloc函数

它的函数声明为:

void* realloc (void* ptr, size_t size);

realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时
候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小
的调整。
ptr 是要调整的内存地址
size 调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
realloc在调整内存空间的是存在两种情况:
情况1:原有空间之后有足够大的空间
情况2:原有空间之后没有足够大的空间


当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小
的连续空间来使用。这样函数返回的是一个新的内存地址。
由于上述的两种情况,realloc函数的使用就要注意一些。
 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main()
{int* p = (int*)malloc(40);if (p == NULL){printf("%s\n", strerror(errno));}//使用int i;for (i = 0; i < 10; i++){*(p + i) = i + 1;}//扩容int* ptr = (int*)realloc(p, 80);//扩容到80个字节 相当于原来有40 又加上40//不要直接用原来的指针接收 如果realloc返回NULL 可能导致数据流失if (ptr != NULL){p = ptr;}for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//realloc(NULL, 40) 等价于  malloc(40);return 0;
}

2.常见的动态内存错误

1.对NULL指针的解引用操作。

2.对动态开辟空间的越界访问。

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

4.使用free释放一块动态开辟内存的一部分

5.对同一块动态内存多次释放

6.动态开辟内存忘记释放(内存泄漏)

3.柔性数组

1.柔性数组的定义方法

struct S
{int i;int a[0];//柔性数组成员
};

有些编译器可能会报错,那么可以改成下面这种:

struct S
{int i;int a[];//柔性数组成员
};

2.柔性数组的特点和使用

结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大
小,以适应柔性数组的预期大小。
 

使用:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>struct S
{int n;int arr[];
};
int main()
{int sz = sizeof(struct S);//4 结构体内存不计算柔性数组printf("%d\n", sz);//柔性数字的使用struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);if (ps == NULL){return 1;}int i;for (i = 0; i < 10; i++){*(ps->arr + i) = i;}for (i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}struct S* str = (struct S*)realloc(ps, sizeof(struct S) + 80);if (str != NULL){ps = str;}//释放free(ps);ps = NULL;return 0;
}

3.柔性数组的优势

上面的使用也可以写成下面这种形式:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>struct S
{int n;int* arr;
};
int main()
{//柔性数字的使用struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){return 1;}ps->n = 100;int* p = (int*)malloc(40);if (p != NULL){ps->arr = p;}int i;for (i = 0; i < 10; i++){*(ps->arr + i) = i;}for (i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}struct S* str = (struct S*)realloc(ps, sizeof(struct S) + 80);if (str != NULL){ps = str;}//释放free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}

与下面的相比 用柔性数组的好处显而易见

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

第二,这样有利于访问速度。

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

更多推荐

C语言 动态内存管理

本文发布于:2024-02-12 16:36:14,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1688580.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:内存管理   语言   动态

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!