C语言动态内存管理

动态内存管理

#define _CRT_SECURE_NO_WARNINGS 1

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

int main()
{
	//int a;//4
	//char arr[5];//5
	//动态内存开辟
	//int arr[10] = {0};//40字节
	int* p = (int*)malloc(40);  //malloc申请开辟内存的单位是字节
	int i = 0;
	//assert(p != NULL);
	if(p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	for(i=0; i<10; i++)
	{
		*(p+i) = i;
	}
	for(i=0; i<10; i++)
	{
		printf("%d ", *(p+i));
	}
	//
	free(p);
	p = NULL;
// 	while(1)
// 	{
// 		malloc(1);
// 	}
	return 0;
}

 int main()
 {
 	int arr[10] = {0};
 	int *p = arr;
 
 	free(p);//err
 	p = NULL;
 	return 0;
 }
calloc(size_t num, size_t size):  开辟num个size字节长度的空间,并且初始化为0
calloc 比 malloc 多了个将开辟的每个字节初始化为0,而且开辟空间个数给定(num)
int main()
{
	int*p = (int*)calloc(10, sizeof(int));//注意calloc还需要给出10(size_t num),即将10个int型初始化为0
	int i = 0;
	int *ptr = NULL;

	if(p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	for(i=0; i<10; i++)
	{
		printf("%d ", p[i]);
	}
	ptr = realloc(p, 2000*sizeof(int));
	if(ptr != NULL)
		p = ptr;

	free(p);
	p = NULL;
	return 0;
}

常见的动态内存错误:
void test()
{
	int* p = (int*)malloc(10);
	if(p == NULL)
	{
		return;
	}

	if(1)
		return;//return 必须在free后面
	//...
	free(p);  //函数提前返回,free无效
	p = NULL;
}

int main()
{
	test();
	getchar();
	return 0;
}

错误一:对NULL指针的解引用
void test()
{
	int *p = (int *)malloc(INT_MAX/4);
	//if(p == NULL) //这一步必须进行 空指针判断
	//{
	//	return;
	//}
	*p = 20;//如果p的值是NULL,就会有问题
	free(p);
}
int main()
{
	return 0;
}


错误二:对非动态开辟的内存使用free释放
void test()
{
	int a = 10;
	int *p = &a;
	free(p);//ok?  错误,因为前面没有动态开辟
}
int main()
{
	test();
	return 0;
}


错误三:对同一块动态内存多次释放(free)
int main()
{
	int *p = (int *)malloc(40);
	int i = 0;
	if(p == NULL)
	{
		return;
	}
	//
	for(i=0; i<5;i++)
	{
		printf("%d ", *(p+i));
	}

	free(p);
	free(p);//重复释放
	p = NULL;
	return 0;
}
错误四:对动态开辟的空间越界访问
void test()
{
	int i = 0;
	int* p = (int*)malloc(sizeof(int)* 10);
	if (NULL == p)
	{
		exit(EXIT_FAILURE);
	}
	for (i = 0; i <= 10; i++)//开辟了10个,这里访问了11个,访问越界
	{
		*(p + i) = i;
	}
	free(p);
}
错误五:使用free释放一块动态内存的一部分(并不是完全释放)
void test()
{
	int* p = (int*)malloc(100);
	p++;    //p已经走了一步,再去free释放-->Error  p作为所动态内存的首地址不能改变
	free(p);//p不再指向动态内存的起始位置
}
错误六:忘记释放
void test()
{
	int* p = (int*)malloc(100);//只开辟,后面没有对应的free来释放
	if (NULL == p)
	{
		*p = 20;
	}
}
int main()
{
	test();
	while (1);
}



题目一:
void GetMemory(char *p)
{
	p = (char *)malloc(100);
}
void Test(void)
{
	char *str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);//???  程序崩溃    会造成内存泄漏  形参p是str的一份临时拷贝 形参出函数就不存在了
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

修改-->传二级指针
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();
	system("pause");
	return 0;
}


题目二:
char *GetMemory(void)
{
	char p[] = "hello world";//局部变量的开辟是在栈上(出函数则自动销毁)
	return p;				 //返回栈空间上的地址,属于访问非法地址 +static (静态区)就OK
}
void Test(void)
{
	char *str = NULL;
	str = GetMemory();
	printf(str);
}

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


int* Test()
{
	int a = 10;
	return &a;//返回的是形参的地址,形参出函数即销毁,无意义
}
int main()
{
	int *p = Test();
	printf("hehe\n");
	printf("%d\n", *p);
	return 0;
}

int Test()
{
	int a = 10;
	return a;
}

int main()
{
	int b = Test();
	return 0;
}
题目三:
void GetMemory2(char **p, int num)
{
	*p = (char *)malloc(num);
}
void Test(void)
{
	char *str = NULL;
	GetMemory2(&str, 100);
	strcpy(str, "hello");
	printf(str);
	//free(str);//不能忘记释放 而且这里都是传址操作,传值的话并不能将str赋为空
	//str = NULL;
}
int main()
{
	Test();
	return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
题目四:
void Test(void)
{
	char *str = (char *) malloc(100);
	strcpy(str, "hello");
	free(str);//这里已经释放了
	//str = NULL;
	if(str != NULL)//再去访问 就属于非法访问了   free后面加上str = NULL;就不算非法访问,但是已经为空了,没有意义
	{
		strcpy(str, "world");
		printf(str);
	}
}

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

int main()
{
	char *p = "abcdef";
	*p = 'w';
	return 0;
}


柔性数组:结构中的最后一个元素允许是位置大小的数组--即柔性数组
struct S
{
	int a;
	char arr[0];//柔性数组:0可写可不写,表示大小未知
};

struct B
{
	int a;//4
	char* arr;//4  指针形式给出的话大小就是4,所以必须是数组形式 char arr[]形式
};

void test2()
{
	char *ptr = NULL;
	struct B* ps = (struct B*)malloc(sizeof(struct B));
	ps->arr = (char *)malloc(100*sizeof(char));

	ps->a = 20;
	strcpy(ps->arr, "abcdef");
	printf("%s\n", ps->arr);
	printf("%d\n", ps->a);
	ptr = realloc(ps->arr, 200s*sizeof(char));
	if(ptr != NULL)
		ps->arr = ptr;
	//...
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
}

void test1()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S)+100*sizeof(char));
	struct S* ptr = NULL;
	ps->a = 20;
	strcpy(ps->arr, "abcdef");
	printf("%s\n", ps->arr);
	printf("%d\n", ps->a);

	ptr = realloc(ps, sizeof(struct S)+200*sizeof(char));
	if(ptr  != NULL)
		ps = ptr;
	//....
	free(ps);
	ps = NULL;
}

int main()
{
	test2();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值