前言
动态内存管理是计算机编程中的一个重要概念,它涉及到在程序运行时分配和释放内存。动态内存管理允许程序在需要时分配内存,而不是在编译时或运行时静态地分配固定大小的内存。接下来我们将学习几个函数,通过这几个函数来开辟和释放内存。以及柔性数组的学习。
malloc和free都声明在 stdlib.h 头⽂件中
void* malloc (size_t size)
- size_t 是一个无符号整数类型,通常用来表示要分配的内存块的大小(以字节为单位)。
- malloc 返回一个 void 指针(通常需要显式类型转换为适当的指针类型),该指针指向分配的内存块的起始地址。如果分配失败,malloc 返回 NULL 指针。
void free (void* ptr)
- ptr 是一个指向要释放的内存块的指针。
- 这个指针应该是之前由 malloc、calloc 或 realloc 返回的指针(也就是说,如果指向的空间不是动态开辟的,那free函数的行为是未定义的)。
举例:
#include
#include
int main(){
int num = 0;
scanf("%d", &num);
int arr[num] = { 0 };
int* ptr = NULL;
ptr = (int*)malloc(num * sizeof(int));//开辟大小为num个int,并将返回的指针赋给ptr
if (NULL != ptr){//判断ptr指针是否为空
int i = 0;
for (i = 0; i < num; i++){
*(ptr + i) = 0;
}
}
free(ptr);//释放ptr所指向的动态内存
ptr = NULL;//是否有必要?
return 0;
}
void *calloc(size_t num_elements, size_t element_size);
- num_elements 是要分配的元素数量。
- element_size 是每个元素的大小(以字节为单位)。
- calloc 返回一个 void 指针,指向分配的内存块的起始地址。如果分配失败,calloc 返回 NULL 指针。
举例:
#include
#include
int main(){
int* p = (int*)calloc(10, sizeof(int));//开辟10个int,并初始化为0
if (NULL != p){
int i = 0;
for (i = 0; i < 10; i++){
printf("%d ", *(p + i));
}
}
free(p);
p = NULL;
return 0;
}
void *realloc(void *ptr, size_t new_size);
- ptr 是一个指向要重新分配的内存块的指针,通常是先前由 malloc、calloc 或 realloc 返回的指针。
- new_size 是新的内存块大小(以字节为单位)。
- realloc 返回一个 void 指针,指向重新分配后的内存块的起始地址。如果分配失败或者 new_size 为零,realloc 返回 NULL 指针。此外,如果 ptr 为 NULL,则 realloc 的行为等同于 malloc(new_size),即它将分配一块新的内存块。
使用realloc函数需要注意一个问题:
用malloc或calloc开辟内存后,使用realloc调整大小时有两种情况:
- 原有空间之后有⾜够⼤的空间
- 原有空间之后没有⾜够⼤的空间
#include
#include
int main() {
int* arr;
size_t original_size = 3;
size_t new_size = 5;
// 分配一个包含3个整数的数组
arr = (int*)malloc(original_size * sizeof(int));
if (arr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 重新分配内存大小,将 ptr 的值更新为 realloc 的返回值
arr = (int*)realloc(arr, new_size * sizeof(int));
if (arr == NULL) {
printf("内存重新分配失败\n");
return 1;
}
// 释放内存
free(arr);
return 0;
}
请问运⾏Test 函数会有什么样的结果?
void GetMemory(char* p){
p = (char*)malloc(100);
}
void Test(void){
char* str = NULL;
GetMemory(str);//将空指针作为实参
strcpy(str, "hello world");//如果开辟动态内存成功,p是起始点,但str依然是空指针,所以不会打印
printf(str);
free(str);
}
请问运⾏Test 函数会有什么样的结果?
char* GetMemory(void){
char p[] = "hello world";//很明显,p是局部变量
return p;
}
void Test(void){
char* str = NULL;
str = GetMemory();//数组p在GetMemory函数结束后销毁,所以返回值是NULL
printf(str);//因此并不会打印hello world
free(str);
}
请问运⾏Test 函数会有什么样的结果?
//这是第一题的正确修改,结果是hello
void GetMemory(char** p, int num){
*p = (char*)malloc(num);
}
void Test(void){
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
free(str);
}
请问运⾏Test 函数会有什么样的结果?
void Test(void){
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);//释放过早,不会打印world
if (str != NULL){
strcpy(str, "world");
printf(str);
}
}
柔性数组(Flexible Array Member)是一种C语言中的高级数据结构,它允许你在结构体的末尾定义一个大小可变的数组,这个数组的大小是在运行时动态确定的。柔性数组在处理变长数据时非常有用,例如在解析网络协议、文件格式等情况下。
柔性数组的定义方式是在结构体内部的最后一个成员定义一个数组,但不指定数组的大小。这个数组的大小会在结构体实例分配内存时动态确定。
下面是一个示例:
#include
#include
// 定义包含柔性数组的结构体
typedef struct FlexibleArrayStruct {//将struct FlexibleArrayStruct重命名为fas
int length; // 数组的实际长度
int data[]; // 柔性数组,它的大小在运行时确定
}fas;
int main() {
// 计算结构体的总大小,包括柔性数组的空间
size_t size = sizeof(fas) + 5 * sizeof(int);
// 动态分配内存来创建一个包含柔性数组的结构体实例
fas* myStruct = (fas*)malloc(size);
if (myStruct == NULL) {
printf("内存分配失败\n");
return 1;
}
// 设置柔性数组的长度
myStruct->length = 5;
// 使用柔性数组存储数据
for (int i = 0; i < myStruct->length; i++) {
myStruct->data[i] = i * 2;
}
// 访问柔性数组的数据
printf("柔性数组的内容:");
for (int i = 0; i < myStruct->length; i++) {
printf("%d ", myStruct->data[i]);
}
printf("\n");
// 释放内存
free(myStruct);
return 0;
}
如果你喜欢这篇文章,点赞+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。