动态内存分配和管理以及动态通讯录

前言

本文主要介绍动态内存函数,在动态内存分配时常见的错误,经典笔试题,内存的组成以及柔性数组的概念,最后我将对之前写的静态通讯录改进为动态通讯录。

动态内存函数

在之前的学习中,我们分配内存空间通常只是给出固定的空间大小,无法根据使用需求调整空间的大小,故动态分配内存空间是很有必要的。

malloc和free

首先认识这两个函数:
malloc
malloc函数是用来向内存申请一块儿连续的空间,参数是要申请空间的大小,单位字节,返回类型为指针类型;
既然是申请空间,就可能申请失败,所以malloc函数满足以下特点:
(1)如果开辟成功,则返回一个指向开辟好空间的指针;
(2)如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查;
(3)由于返回类型为void*,所以我们需要根据使用要求强制类型转换为我们需要的类型指针;
(4)如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
free
free函数是用来释放动态内存函数申请的空间的,一般和动态内存函数成对使用,否则会造成内存泄漏,函数参数是指针,指向动态内存函数申请的空间,返回类型为空。free函数有以下特点:
(1)如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的;
(2)如果参数 ptr 是NULL指针,则函数什么事都不做。
我想例子是最直观的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
   
	int size = 0;
	scanf("%d", &size);
	char* pa = (char*)malloc(size);
	if (pa == NULL)
	{
   
		printf("%s\n", strerror(errno));
		return 1;
	}
	//对动态内存空间进行操作
	int i = 0;
	for (i = 0; i < size / sizeof(int); i++)
	{
   
		*(pa + i) = i;
	}
	for (i = 0; i < size / sizeof(int); i++)
	{
   
		printf("%d ", *(pa + i));
	}
	//释放开辟的动态内存
	free(pa);
	pa = NULL;
	return 0;
}

上述代码我是向内存申请了size字节大小的空间,然后判断申请是否成功,如若成功,我就对这块空间进行操作,最后释放空间给操作系统。至于这里为什么要释放空间,我的理解是:动态内存函数开辟空间是在堆区开辟的,设想如果一个程序需要多次开辟空间,每次使用完开辟的空间都不释放,势必会导致内存的碎片化和内存不足,使得电脑变得卡顿,甚至程序崩溃,所以每次开辟完空间都要记得释放。

calloc

calloc函数同样是用来动态开辟内存空间的,先认识函数:
calloc
calloc函数有两个参数,第一个是要分配的元素个数,第二个是每个元素个数的大小,返回类型为指针类型,对比malloc函数,malloc函数是直接将要开辟的空间大小传给malloc,calloc函数是将空间细化成了num份,每份size字节,而且calloc函数还会将开辟的空间内容全部初始化为0。
通过例子来说明:
calloc举例
通过调试观察内存的情况,发现calloc函数确实是会初始化空间内容。

realloc

realloc函数让动态内存管理更加灵活,为什么这么说,先让我们从认识函数说起:
realloc
realloc函数有两个参数,第一个是指针,指向动态内存函数开辟的空间,第二个参数是需要的动态内存大小,返回类型是指针。为什么前面说realloc函数让动态内存管理更灵活,是因为realloc可以调整动态内存函数开辟的空间大小,参数size就是调整后的大小,单位字节
举例说明:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
   
	int size = 4;
	int num = 5;
	scanf("%d %d", &num,&size);
	char* pa = (char*)calloc(num, size);
	if (pa == NULL)
	{
   
		printf("%s\n", strerror(errno));
		return 1;
	}
	//扩容
	char* p = (char*)realloc(pa, 60);
	if (p == NULL)
	{
   
		printf("%s\n", strerror(errno));
		return 1;
	}
	pa = p;
	//对内存空间进行操作
	

	//释放开辟的动态内存
	free(pa);
	pa = NULL;
	return 0;
}

上述代码我先是开辟了20个字节大小的空间,然后采用realloc函数对空间进行了扩容,这里需要注意:扩容也可能是发生错误的,比如空间不足以用来扩容,就会返回NULL,如果不加判断就赋予pa指针,那么之前开辟的20字节大小的空间我们就会找不到,进而无法释放导致内存泄漏,所以扩容时一定要对返回的指针进行判断,判断不为NULL后,再赋予pa,然后在对空间进行操作,操作完成后,进行释放。
由此,对于realloc函数,需要注意以下几点:
(1)第一个参数,即指针只能是指向动态内存函数开辟的空间;
(2)返回值依旧需要判断,判断是否为NULL;
(3)即使扩容失败,并不会改变原空间的内容。

常见的动态内存错误

对NULL指针的解引用操作

由于没对动态内存函数返回值进行判断,直接使用导致出现的错误。例:

#include <stdlib.h>
void test()
{
   
	int* p = (int*)malloc(1000);
	*p = 20;//如果p的值是NULL,就会有问题
	free(p);
}

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

例:

#include<stdio.h>
#include <stdlib.h>
void test()
{
   
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	if (NULL == p)
	{
   
		return ;
	}
	for (i = 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值