枚举类型和动态内存管理

本文详细介绍了C语言中的枚举类型,包括其定义、优点以及与#define的区别。同时探讨了动态内存管理的必要性,讲解了malloc、free、calloc和realloc函数的用法及常见错误,最后涉及柔性数组的特性和使用方法。
摘要由CSDN通过智能技术生成

一.枚举类型

1.什么是枚举

枚举就是一一列举,在生活中有些值可以一一列举,例如月份,星期

例子如下

enum Color
{
	RED,
    GREEN,
	BLUE
};

大括号中的内容为枚举常量。

若不进行赋值,默认第一个值为0,依次向下递增1

enum Color
{
	RED=5,
    GREEN,
	BLUE
};

此时RED GREEN BLUE 依次变成5,6,7

enum Color
{
	RED,
    GREEN=5,
	BLUE
};

若这样写,则依次变成0,5,6

2.枚举类型的优点

枚举类型通常用来给常量赋值

a.与#define相比,enum定义的变量具有类型,且方便调试。在预处理阶段,编译器会直接将定义的替换成数字

b.enum增加了程序的可读性,例如在以往的计算器编写时,可在switch选择时给予数字以特殊的意义,使使用者更清楚计算器的功能

c.enum具有作用域,#define的类型是全局变量

二.动态内存管理

1.动态内存管理的必要性

以往我们向内存申请空间,往往直接创建一个变量。

char s[5] = { 0 };

这样创建的变量往往一旦申请,就无法改变其长度和大小。

但在实际情况中,空间申请的不合理可能会造成浪费或者短缺,而动态内存就能很好地解决这个问题。

2.malloc和free

void* malloc(size_t size);

首先是malloc函数,他的功能是向内存申请一块连续可用的空间(size的值传入申请的空间大小),并返回这个空间的起始地址。(返回void*是因为向内存申请的数据类型完全由使用者决定)

a.注意,若malloc开辟成功,则返回空间的起始地址,若开辟失败,则返回NULL,因此malloc返回值一定要做检查,具体使用如下

int main()
{
	int* p = (int*)malloc(20);//开辟空间,申请一个20字节的空间
	if (p == NULL)//判断malloc函数是否返回正常
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)

	{
		*(p + i) = i + 1;
	}
	
	free(p);//释放空间,p成为野指针
	
	p = NULL;//避免p成为野指针
	
return 0;
}

b.当参数size为0时,其行为编译器未定义,不一定可以通过编译

c.free函数的参数是需要释放空间的起始地址,并且free无法释放非动态申请的空间

d.free函数的作用是将空间的访问权限还给操作系统,若不把释放空间后的指针置为NULL,会造成野指针的情况

下面有一种情况:


	int* p = (int*)malloc(20);//开辟空间,申请一个20字节的空间
	if (p == NULL)//判断malloc函数是否返回正常
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)

	{
		*p =i+1;
         p++;
	}
	
	free(p);//释放空间,p成为野指针
	
	p = NULL;//避免p成为野指针

可以这样写吗?

答案是不行,在for循环中我们已经改变了p的位置,导致free函数执行时p已经不指向空间的起始位置

3.calloc和realloc

a.calloc函数

void* calloc (size_t num, size_t size);

其功能为,向内存申请num个每个大小为size的内存,且初始化为0

具体使用,创建五个每个大小为四个字节的空间

int* p2 = (int*)calloc(5, sizeof(int));//calloc可将申请的空间初始化为0

if (p2 == NULL)//判断calloc函数是否返回正常
{
	perror("calloc");
	return 1;
}
int i = 0;

for (i = 0; i < 5; i++)

{
	printf("%d ", *(p2 + 1));
}
//释放空间,p成为野指针
free(p2);
//避免p成为野指针
p2 = NULL;

b.realloc函数

其功能为将某个已申请的空间进行调整,其参数如下:要修改的空间起始位置ptr,要修改形成的大小size

void* realloc (void* ptr, size_t size);
int* p = (int*)malloc(20);//开辟空间,申请一个20字节的空间

if (p == NULL)//判断malloc函数是否返回正常
{
	perror("malloc");
	return 1;
}

for (i = 0; i < 5; i++)

{
	*(p + i) = i + 1;
}
int* ptr = (int*)realloc(p, 40);//用realloc函数将原本申请的空间修改为40个字节
if (ptr == NULL)
{
	perror("realloc");
	return 1;
}
p = ptr;
//realloc可以实现和malloc类似的功能,只需要传入空指针即可
/*若用局部变量开辟空间,申请空间不释放,会造成内存泄漏*/

realloc函数的调整原理(有两种):

1:要将原本的20字节扩展为40字节,其后的空间恰好未分配,直接续上即可

2:之后的空间已经的分配,不足以直接续上

此时会在空间中找一份40字节的空间,将原数据拷贝到新空间,返回新空间的地址,并释放旧空间

注意:空间调整失败,realloc返回NULL

不可直接将调整后的地址直接覆盖旧地址,若realloc调整失败,旧空间也会出错,正确方法应如上代码所示

realloc若传入NULL,其功能与malloc类似

4.常见的动态内存管理的错误

a.对空指针的解引用操作

void test()
{
	int* ps = (int*)malloc(INT_MAX);
	*ps = 20;
	free(ps);
}

这里没有检查malloc的返回值,而这里的ps为空指针,会造成程序崩溃

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

int* p = (int*)malloc(20);//开辟空间,申请一个20字节的空间

if (p == NULL)//判断malloc函数是否返回正常
{
	perror("malloc");
	return 1;
}

int i = 0;
for (i = 0; i <= 5; i++)

{
	*(p + i) = i + 1;
}

这里i=5时会造成越界访问

c.对非动态内存的free释放

d.对动态空间的部分释放


	int* p = (int*)malloc(20);//开辟空间,申请一个20字节的空间
	if (p == NULL)//判断malloc函数是否返回正常
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)

	{
		*p =i+1;
         p++;
	}
	
	free(p);//释放空间,p成为野指针
	
	p = NULL;//避免p成为野指针

这里的p已经发生位置移动,free只能从空间的起始位置开始释放

e.对同一空间多次释放

f.动态内存忘记释放,造成内存泄漏

若程序忘记回收,在结束后会由操作系统回收,这里较为危险的情况是程序一直运行的情况

谁申请,谁释放(不管是函数,还是在main函数内部)

5.动态内存管理的一些应用

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
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;
}

注意在函数之间尽量使用传址调用

三.柔性数组 

struct s_type
{
	int i = 0;
	int a[0];
};

柔性数组需建立在结构体内,且为最后一个成员没有指定大小

1.柔性数组的特点

a.因为未指定数组大小,计算结构体大小时往往不包含数组大小

b.柔性数组往往使用动态内存管理进行分配

c.柔性数组的创建 使用 修改

struct S
{
	int i ;
	int a[];
};
int main()
{

	struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));
	return 0;
	ps->i = 0;
	int j = 0;
	for (j = 0; j < 5; j++)
	{
		ps->a[j]=j;
	}
	struct S* ptr =(struct S*) realloc(ps, sizeof(struct S) + 10 * sizeof(int));
	if (ptr != NULL)
	{
		ps = ptr;
	}
	free(ps);
	ps = NULL;
}

  • 45
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值