C语言 动态内存管理 malloc

C语言 动态内存管理 malloc,第1张

C语言 动态内存管理 malloc

文章目录

1.函数介绍

1.1malloc free1.2calloc1.3realloc 2.常见错误

2.1对NULL指针解引用2.2对动态开辟空间越界访问2.3对非动态开辟空间free释放2.4free释放动态开辟空间的一部分内容2.5对同一块空间多次释放2.6动态开辟空间忘记释放 3.试题分析

3.1第一题3.2第二题3.3第三题3.4第四题 4.柔性数组

1.函数介绍 1.1malloc free


malloc会在堆中开辟一块连续的空间,空间大小是size,以字节为单位。开辟成功返回一个指向开辟好的空间的指针,开辟失败返回NULL指针,所以在使用malloc函数后一定要进行检查。malloc函数返回的是void*的空指针,所以在使用时需要将其强转成对应类型。


free函数能释放动态开辟过的内存,函数参数就是指向动态开辟空间首地址的指针。如果指针为NULL,free函数什么都不做,free函数指向的空间不是动态开辟的,程序会出错。

使用模式

void test()
{
	int* p = (int*)malloc(40);
	if (p == NULL)//判断指针是否为空
	{
		printf("%s", strerror(errno));//打印错误信息并且退出程序
		return;
	}
	//使用
	free(p);//使用后将p指向的空间释放
	p = NULL;//这是p是野指针,将p置为NULL
}

malloc和free是一对函数,使用了malloc函数一定要使用free函数释放内存。

1.2calloc


calloc和malloc一样是开辟动态内存的函数,不一样的是calloc会将开辟空间初始化为0。参数中的num是要开辟的元素个数,size是一个元素的字节数。返回类型也是void*,使用时要注意强转类型。

void test1()
{
	int* p = (int*)calloc(4, 4);
	if(p == NULL)
	{
		printf("%s", strerror(errno));
		return;
	}
	free(p);
	p = NULL;
}
1.3realloc


使用realloc函数调整动态内存空间的大小,memblock是指向一块动态内存的指针,size是调整后的空间大小,以字节为单位。如果调整空间失败,函数返回NULL。在函数调整空间成功的情况下,有两种情况

    原有空间后有足够空间,函数返回的指针与原来相同原有空间后没有足够空间,函数会找到一块足够大的空间,返回的指针与原来不同
    使用
void test1()
{
	int* p = (int*)calloc(4, 4);
	if(p == NULL)
	{
		printf("%s", strerror(errno));
		return;
	}
	p = (int*)realloc(p, 80);
	free(p);
	p = NULL;
}
2.常见错误 2.1对NULL指针解引用
int main()
{
	int* p = (int*)malloc(INT_MAX);
	*p = 1;
	free(p);
	p = NULL;
	rturn 0;
}

没有检查malloc返回的指针是否为空,INT_MAX是一个二十几亿的数字,malloc函数开辟失败返回空指针,p为空指针,对p解引用是非法的。

2.2对动态开辟的空间越界访问
int main()
{
	int* p = (int*)malloc(10 * 4);
	if (p == NULL)
		return 0;
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
	p = NULL;
	return 0;
}

i为10的时候,p + i指向第11个整形,而malloc只开辟了10个整形大小的空间,*(p + i)属于越界访问。当使用动态开辟的空间时,注意开辟空间的大小,小心越界。

2.3对非动态开辟空间free释放
void test()
{
	int a = 1;
	int* p = &a;
	free(p);
}

p指向a,不是动态内存开辟的空间,使用free释放p会导致错误

2.4free释放动态开辟空间的一部分内容
void test()
{
	int* p = (int*)malloc(40);
	p++;
	free(p);
}

当p不指向动态开辟空间的起始位置时,使用free释放会导致程序错误。在动态开辟内存时,一定要有一个指针始终指向空间的起始位置。

2.5对同一块空间多次释放
void test()
{
	 int *p = (int *)malloc(100);
	 free(p);
	 free(p);//重复释放
}
2.6动态开辟空间忘记释放
void test()
{
	 int *p = (int *)malloc(100);
	 if(NULL != p)
	 *p = 20;
}

当忘记释放动态开辟空间时,会导致内存的浪费,称作内存泄漏。当使用了malloc时一定要对应使用free。

3.试题分析 3.1第一题
void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

问:Test函数有什么问题?
两个

    调用GetMemory函数时传递的是值,并没用传递地址,因此str没有指向动态内存开辟的空间,而是一个空指针,将"hello world"的内容拷贝到str中是错误的。p所指向的动态内存没有释放,导致内存泄漏。
3.2第二题
char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

打印结果乱码。

GetMemory函数返回栈空间变量的地址,这是一个严重的错误,GetMemory函数执行完创建的局部变量销毁,p指针指向的hello world同样销毁,此时p为一个野指针,这时不能再使用p指针。

3.3第三题
void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}

与第一题相同,传址调用改变了str的内容,此时str指向一块动态开辟的空间,但是没有free释放,导论了内存泄漏。

3.4第四题
void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

释放内存之后继续使用原有空间。

总结,在开辟动态内存后一定不能忘了free释放掉内存并置空指针,同时也不能继续使用之前的内存。

4.柔性数组

结构体的最后一个成员为柔性数组,sizeof该结构体得到的是除了柔性数组其他成员的大小,除了柔性数组以外至少还应该有一个成员。目前我还不知道应用场景,先放一个使用
两种写法,一种在结构体中创建arr[]或arr[0]数组,一种创建指针

struct S1
{
	int i;
	int arr[];
};
struct S2
{
	int i;
	int* p;
};

int main()
{
	struct S1* p = (struct S1*)malloc(sizeof(struct S1) + 80);
	p->i = 0;
	int i = 0;
	if (p != NULL)
	for (i = 0; i < 10; i++)
	{
		p->arr[i] = i;
	}
	free(p);
	p = NULL;


	struct S2* ps = (struct S2*)malloc(sizeof(struct S2));
	if (ps != NULL)
	{
		ps->p = (int*)malloc(100);
		if (ps->p != NULL)
		{
			//使用
		}
		free(ps->p);
		ps->p = NULL;
		free(ps);
		ps = NULL;
	}
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5714183.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存