C语言学习总结(九)------动态内存管理与柔性数组

什么是动态内存

动态内存是指在程序运行期间,由程序员申请内存及释放的内存。

为什么需要动态内存分配

1.静态开辟内存不够灵活。
2.栈空间有限(小)。
3.某些条件下难以满足程序员的要求。例如需要一个在程序运行期间才知道大小的数组。

如何动态分配内存

C语言提供了四个关于内存分配的函数。malloc calloc realloc free,需要的头文件都在中。
malloc与callocc

void *malloc( size_t size );
void *calloc( size_t num, size_t size );

相同点: 两个函数都是在堆上动态的开辟一块连续的存储空间,开辟成功返回这块空间的首地址,开辟失败则 返回NULL,因此我们可以利用返回值来进行判断内存是否开辟成功,也必须进行判空操作!
因为函数的返回类型是void*因此该函数与类型无关,只是以字节为单位动态的开辟一块空间,至于怎样用,就是程序员的事了,只需进行一次强制类型转换,转换成想用的类型就行。申请的内存必须手动释放掉,否则会造成内存泄漏。
不同点: malloc开辟的空间里面的数据是随机值,并没有初始化。calloc会把开辟的每个字节初始化为0.
用法举例

int main()
{
	int* p = (int*)malloc(10 * sizeof(int));//动态开辟40个字节的内存
	if (NULL == p)  //判空
	{
		printf("Error");
		exit(1);
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
		printf("\n");
	}
	free(p);   //释放内存
	system("pause");
	return 0;
}

C语言学习总结(九)------动态内存管理与柔性数组_第1张图片

ralloc

void *realloc( void *memblock, size_t size );

realloc函数可以调整我们动态申请的内存,使得动态内存管理更加灵活。
两个参数 memblock:需要调整的内存的首地址,size为调整之后的大小。
用法举例

int main()
{
	int* p = (int*)malloc(10 , sizeof(int));//动态开辟40个字节的内存
	int* q = NULL;
	if (NULL == p)  //判空
	{
		printf("p: Error");
		exit(1);
	}
	*q = realloc(p, 100 * sizeof(int));//此处不再需要强制类型转换。由原来的40个扩大至400个
	if (NULL == q)  //判空
	{
		printf("q: Error");
		exit(1);
	}
	else
	{
		p = q;
	}	
	free(p);   //释放内存
	p = NULL;  //置空
	system("pause");
	return 0;
}

free

void free( void *memblock );

对动态开辟的内存进行释放,其中memblok,只能是指向动态内存空间的地址。而且memblock的值可以为空。free掉内存后只是取消了指针和内存之间的映射关系,指针仍然指向那块存储空间,存储空间的数据仍在,但通过该指针不能再访问这块内存了!
为什么利用malloc申请的内存是动态的?
1.mallloc是一个函数,函数在调用的时候才会执行,因此malloc申请的内存是在程序运行期间申请的。而静态内存是在编译期间分配的。
2.malloc申请的内存是可变的。

注:动态内存分配只能整体分配,整体释放

int main()
{
	int* p = (int*)malloc(10*sizeof(int));
	if (p!=NULL)
	{
		p++;//p已经不再是指向起始位置了!
	}
	free(p);
	system("pause");
	return 0;
}

C语言学习总结(九)------动态内存管理与柔性数组_第2张图片
程序已经崩溃了。

柔性数组

概念:柔性数组是指在一个结构体中,最后一个元素是一个长度为0的数组。
目的:结构体内包含柔性数组是为了在结构体内创建一个变长数组。
例如:

struct Stu
{
	int a;
	int arr[0];
};
//--------------------------
struct Stu
{
	int a;
	int arr[];
};

柔性数组的特点:
1.柔性数组前必须至少有一个元素。
2.sizeof返回值测得大小不包括柔性数组。
3.可以利用动态内存分配的方式为柔性数组开辟空间。

柔性数组大概是这样的:
C语言学习总结(九)------动态内存管理与柔性数组_第3张图片
黑色框内是a的空间,红色框内是数组arr的空间。但用sizeof测得结构体的空间只是黑色框的部分。

柔性数组的使用

struct Stu
{
	int a;
	int arr[];
};
int main()
{
	struct Stu *st = (struct Stu*)malloc(sizeof(struct Stu) + 10 * sizeof(int));
	if (st != NULL)
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			st->arr[i] = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", st->arr[i]);
		}
		printf("\n");
		free(st);
	}
	system("pause");
	return 0;

利用柔性数组的优点:其实可以在结构体内定义一个指针,然后利用指针指向堆上的一块内存,但这样做就必须单独对这块内存进行管理。而利用柔性数组呢,可以通过结构体指针一次性管理整个内存,一次申请一次释放,因此柔性数组的优点是内存方便管理,提高效率。

你可能感兴趣的:(C语言学习总结)