C语言动态内存

本文详细介绍了C语言中动态内存管理函数malloc、free、calloc和realloc的使用,包括它们的功能和示例代码。同时,讨论了动态内存管理中常见的错误,如空指针解引用、越界访问、误释放等,并提供了经典笔试题和解决方案。最后,提到了结构体中的柔性数组概念及其应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

malloc

free

calloc

realloc

常见的动态内存错误

经典笔试题

柔性数组


malloc 

void* malloc (size_t size);

malloc动态的内存分配,只负责在堆区上申请空间,并且返回起始地址,不初始化内存空间

如果开辟成功返回开辟好空间的指针,如果开辟失败返回一个NULL的指针。

free

void free (void* ptr);

free是用来释放动态开辟的内存空间

int main()
{
	//int arr[10] = {0};
	//申请空间
	int* p = (int*)malloc(40);  //40表示的是字节数
	if (p == NULL)
	{
		return -1;
	}
	//开辟成功了
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//释放空间
	free(p);
	p = NULL;
	
	return 0;
}

calloc

void* calloc (size_t num, size_t size);

calloc函数在堆区上申请空间,并且初始化为0,返回起始地址。

int main()
{
	//申请10个int的空间
	int*p = (int*)calloc(10, sizeof(int));
	
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));//把错误码转换成错误信息
		return -1;
	}
	
	//申请成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
}

realloc

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

realloc用来调整空间,空间不够,可以进行调整,返回值为调整之后的起始地址,

这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

int main()
{
	//申请10个int的空间
	int*p = (int*)calloc(10, sizeof(int));
	
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));//把错误码转换成错误信息
		return -1;
	}
	
	//申请成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}

//realloc调整空间
	//空间不够了,增加空间至20 个int
	int*ptr = (int*)realloc(p, 20*sizeof(int));  //第二个参数要的是字节
	if (ptr != NULL)
	{
		p = ptr;
	}	
	else
	{
		return -1;
	}
	for (i = 10; i < 20; i++)
	{
		*(p + i) = i;
	}
	//打印
	for (i = 0; i < 20; i++)
	{
		printf("%d ", *(p + i));
	}

	//释放空间
	free(p);
	p = NULL;

	return 0;
}

常见的动态内存错误

1.对空指针*

int  main()
{
	int*p = (int*)malloc(20);
	if (p == NULL)
		return -1;
	//
	*p = 0;//直接这样写代码是有风险的!!!

	return 0;
}

2.对动态开辟的内存越界访问

int main()
{
	int* p = (int*)malloc(200);
	if (p == NULL)
	{
		return -1;
	}
	//使用
	int i = 0;
	//越界访问
	for (i = 0; i < 80; i++)
	{
		*(p + i) = i;
	}

	for (i = 0; i < 80; i++)
	{
		printf("%d\n", *(p + i));
	}

	//释放
	free(p);
	p = NULL;

	return 0;
}

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

int main()
{
	int a = 10;
	int*p = &a;
	//
	free(p);
	p = NULL;

	return 0;
}

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

int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return -1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*p++ = i;  //p已经不在指向起始位置
	}
	//释放
	free(p);
	p = NULL;

	return 0;
}

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

int main()
{
	int *p = (int*)malloc(40);
	if (p == NULL)
		return -1;
	//使用
	//...

	//2次释放-是错误的
	free(p);
	free(p);

	return 0;
}

经典笔试题

1.

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str)
}

int main()
{
	Test();
	return 0;
}

运行上面代码会导致程序奔溃,内存泄漏:

1.str传给p的时候,是值传递,p是str的临时拷贝,当malloc开辟的空间的起始地址方在p中的时候,不会影响str,str依然是NULL 。

2.当str为NULL,strcpy想把hello world拷贝到str指向的空间时,程序就奔溃,因为null没法访问。

改进:

方法一:

void GetMemory(char** p)
{
	*p = (char*)malloc(100); 
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);

	strcpy(str, "hello world"); 
	printf(str);
	//释放
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

方法二:

char* GetMemory(char* p)
{
	p = (char*)malloc(100);
	return p;
}

void Test(void)
{
	char* str = NULL;
	str = GetMemory(str);

	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

2.

返回栈空间地址的问题

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}

void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

int main()
{
	Test();
	//程序运行,打印随机值
	return 0;
}

发现运行上面的程序是打印随机值。因为每一次运行都会重新开辟一块空间。

3.

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}

void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello"); //内存泄漏没有free
	printf(str);
}

int main()
{
	Test();
	return 0;
}

运行上面代码会发现内存泄漏,因为没有进行内存释放。

4.

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");

	free(str); //提前释放
	//str = NULL; 

	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

提前释放了内存。

柔性数组

柔性数组:结构体中最后一个元素允许是未知大小的数组

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

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

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

结构的大小,以适应 柔性数组的预期大小。

方法1:

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


#include<string.h>
#include <errno.h>

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

int main()
{
	//printf("%d\n", sizeof(struct st_type));
	//包含柔性数组成员的结构体的使用,要配合malloc这样的动态内存分配函数使用
	//struct st_type st;
	struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type) + 10*sizeof(int));
	if (ps == NULL)
	{
		printf("%s\n", strerror(errno));
		return -1;
	}
	//开辟成功了
	ps->i = 100;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->a[i] = i;
	}

	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->a[i]);
	}
	//a数组的空间不够了,希望调整为20个整型数据
	struct st_type* ptr = (struct st_type*)realloc(ps, sizeof(struct st_type)+20*sizeof(int));
	if (ptr == NULL)
	{
		printf("扩展空间失败\n");
		return - 1;
	}
	else
	{
		ps = ptr;
	}

	//使用
	//...
	//释放
	free(ps);
	ps = NULL;

	return 0;
}
方法2:
struct st_type
{
	int i;//4
	int* a;//4
};

int main()
{
	struct st_type* ps = (struct st_type*)malloc(sizeof(struct st_type));

	ps->i = 100;
	ps->a = (int*)malloc(10*sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->a[i] = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->a[i]);
	}
	//a指向的空间不够了,希望可以调整大小
	int* ptr = (int*)realloc(ps->a, 20*sizeof(int));
	if (ptr == NULL)
	{
		printf("扩容失败\n");
		return -1;
	}
	else
	{
		ps->a = ptr;
	}
	//使用
	//..
	
	//释放
	free(ps->a);
	ps->a = NULL;
	free(ps);
	ps = NULL;

	return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值