C语言笔记——动态存储管理

动态存储管理

我们常见的静态开辟方式有:

int a = 10;
char arr[20] = {0};

这些是在栈区开辟,空间开辟大小是已知的,且数组在声明时必须指定长度。但对于一些只有在运行时才能知道所需空间的情况,(如输入一个数n后再开辟数组a[n]),则上述开辟方式不能满足,因此,有了动态存储来解决此问题。

malloc

自由存储区:**堆(heap)**开辟

void* malloc (size_t size);
  • 申请的为一块连续可用的空间,返回为指针;
  • 开辟成功,返回一个指向开辟好的空间的指针;开辟失败,返回一个NULL指针;
  • 返回值为void*,根据需求自己决定开辟空间类型。

free

void free (void* ptr);

free函数是用来释放开辟的内存

//申请空间,判断是否为空
void main()
{
	int n;
	scanf("%d", &n);
	int *arr = (int *)malloc(sizeof(int) * n);   //按需分配内存
	if (NULL == arr)
	{
		printf("Out Of Memony.\n");
		return;
	}
	for (int i = 0; i < n; i++)
	{
		arr[i] = i + 1;
		printf("%d\n", arr[i]);
	}
	free(arr);   // free再次访问arr属于非法使用
}
  • 释放空间 ! = 释放指针
  • free为释放空间,相当于回收了使用权,但指针还指向原先地址,变为野指针
  • 释放完毕后(空间)要给指针赋空,p=NULL
  • 自己申请的空间只能释放一次,不能对已释放的空间再次执行释放指令
  • free只能在mallloc使用

错误案例:

void main()
{
	int *p = (int *)malloc(sizeof(int)* 25);
	free(p);
	for (int i = 0; i < 25; i++)
	{
		p[i] = i;       //非法访问
		printf("%d\n", p[i]);
	}
}

calloc

void *calloc(size_t num,size_t size) ; 

功能:

  • 为num个大小为size的元素开辟一块空间,并把每个字节初始化为0;相当于malloc+初始化为0.

realloc

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

功能:

  • 对动态开辟的内存大小做灵活的调整。

memblock:要调整的内存地址
size:调整之后的新大小

注意:

  • 若扩展的空间后面没有足够大的空间,则在堆上寻找更大的空间,拷贝数据,重新将指针指向新的空间
  • 若第一个参数为空NULL时,则相当于malloc
  • 若申请失败,则返回空NULL

内存泄漏和柔型数组

内存泄漏:

未释放空间或者没执行释放语句就返回退出。
动态开辟的空间一定要正确释放

柔型数组:

C99中,结构中最后一个元素允许是未知大小的数组为柔型数组(不能单独存在)。

typedef struct test
{
	char a;
	int b;
	double c;
	char arr[0];   //柔性数组成员,不占空间
}test;
void main()
{
	printf("size = %d\n", sizeof(test));
	char str[] = "hello";
	test t;
	printf("str = %s\n", t.arr);    //可以打打印出,但存在乱码
}

特点:

  1. 结构中柔型数组成员前面必须至少有一个其他成员;
  2. sizeof返回这种结构大小不包含柔型数组成员,即不占内存;
  3. 含有柔性数组成员的结构可以用动态分配,分配时应大于结构体的大小,这样可以适应柔型数组的预期大小。

你可能感兴趣的:(C语言笔记,内存管理)