c语言总结 6:动态内存管理

  • 动态内存分配介绍
    在开辟空间时,内存中主要有三个区,为栈区,堆区,静态常量区,栈区中中主要存储局部变量和形式参数,栈区存储由动态内存函数开辟的空间,静态常量区存储有static关键字的全局变量(但不完全是)和静态数据
  • 动态内存函数
    1.malloc
    void* malloc(size_t size)
    这个函数向内存申请一个连续可用的空间,并返回这块空间的指针,若开辟成功,返回开辟好空间的指针,若开辟失败,返回NULL指针,因此malloc函数的返回值要做检查。
    2.free
    专门用来做动态内存的释放和回收,表示系统回收这个空间,这个空间归还给操作系统。
    3.calloc
    void* calloc(size_t n,size_t size)
    函数是为n个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0
    4.realloc
    void* realloc(void* ptr,size_t size)
    ptr为要调整的内存地址,size为调整之后大小,调整原内存空间大小后,将原来内存中的数据移动到新的空间
    realloc模拟实现
void* my_realloc(void* memblock, size_t size)
{
	void* new_base = malloc(size);//开辟新空间
	assert(new_base != NULL);
	memcpy(new_base, memblock, size);//拷贝原内容
	free(memblock);//释放原空间
	memblock = new_base;//改变指针方向
	return memblock;//返回新开辟空间的地址
}

5._alloca
这个函数不能free,因为申请的空间在栈区

  • 常见动态内存错误
    1.对NULL指针的解引用操作
void test()
{
	int *p = (int*)malloc(INT_MAX / 4);
	*p = 20;
	free(p);
}

如果p的值为NULL,就会出现问题,应该改正为

void test()
{
	int *p = (int*)malloc(INT_MAX / 4);
	if (p == NULL)
	{
		perror("use malloc");
		exit(EXIT_FAILURE);
	}
	*p = 20;
	free(p);
}

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

void test()
{
	int i = 0;
	int *p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		perror("use malloc");
		exit(EXIT_FAILURE);
	}
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
}

只开辟了10个整形空间,可是却访问到了第11个,越界。
3.使用free释放一块动态内存开辟内存的一部分

void test()
{
	int *p = (int*)malloc(100);
	p++;
	free(p);
}

因为p++后不再指向动态内存的起始位置。
4.对同一块动态内存多次释放

void test()
{
	int *p = (int*)malloc(100);
	free(p);
	free(p);
}

重复释放
5.内存泄漏

void test()
{
	int *p = (int*)malloc(100);
	if (NULL == p)
	{
		*p = 20;
	}
}

忘记释放空间会造成内存泄露,应该正确释放空间。

  • 经典笔试题
void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void test()
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf("%s",str);
}

结果程序会崩溃,因为在传递参数时传的是值,给p重新开辟了空间,str并没有改变,应该是址传递,改为

void GetMemory(char**p)
{
	*p = (char*)malloc(100);
}
void test()
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str, "hello world");
	printf("%s", str);
}
char* GetMemory()
{
	char p[] = "hello world";
	return p;
}
void test()
{
	char *str = NULL;
	str = GetMemory();
	printf("%s", str);
}

return p指返回地址,char p[]只是创建了临时空间,函数结束时销毁,因此在测试时地址虽然获取了回来,但是地址返回空间的值改变了。应该改为

char* GetMemory()
{
	static char p[] = "hello world";
	return p;
}
void test()
{
	char *str = NULL;
	str = GetMemory();
	printf("%s", str);
}
void test()
{
	char *str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf("%s", str);
	}
}

在空间释放后又使用它,访问了非法内存,应该预防野指针,改为:

void test()
{
	char *str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf("%s", str);
	}
}
  • 柔性数组
    结构中的最后一个元素允许是未知大小的数组
struct S
{
	int n;
	char arr[];//柔性数组
	
};
int main()
{
	struct S *p=(struct S*)malloc(sizeof(struct S) + 10 * (sizeof(char)));
	int i = 0;
	struct S *ptr;
	p->n = 10;
	for (i = 0; i < 10; ++i)
	{
		p->arr[i] = i + 1;
		printf("%d ", p->arr[i]);
	}
	printf("\n");
	ptr = realloc(p,sizeof(struct S)+20 * (sizeof(char)));
	if (ptr != NULL)
	{
		p = ptr;
	}
	p->n = 20;
	for (i = 0; i < 20; ++i)
	{
		p->arr[i] = i + 1;
		printf("%d ", p->arr[i]);
	}
	printf("\n");
	free(p);
	p = NULL;
	system("pause");
	return 0;
}

输出结果为1 2 3 4 5 6 7 8 9 10 和 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值