C语言(动态内存分配)

644 阅读3分钟

C语言内存分配:

静态内存:也就是栈空间内存,不用程序员自己分配。

1、栈区(stack):编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。栈里面的变量通常是局部变量、函数参数等。windows下,栈内存分配2M(确定的常数),超出了限制,提示stack overflow错误。自动分配,释放。

动态内存分配:由 malloc 等分配的内存块,和堆是十分相似的,不过它是用 free 来结束自己的生命的。

2、堆区(heap):由 new 分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个 new 就要对应一个 delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。堆可以动态地扩展和收缩。 程序员手动分配释放,操作系统80%内存。

3、全局区或静态区。

4、字符常量区。

5、程序代码区。

void main(){
	//静态内存分配,在栈内存中
	int a[100*1024*1024];
	getchar();
}

运行结果.png

会出现stack overflow错误,也就是栈溢出。

void main(){
	//动态内存分配
	int* p = malloc(1024*1024*sizeof(int));
	//printf("%#x\n",p);
	//释放
	free(p);
	getchar();
}

上面就是使用malloc动态分配sizeof(int)M内存,然后使用free释放分配的内存。

静态内存分配:分配固定大小的内存空间。 存在问题:1、容易超出栈内存最大值,也就是造成栈溢出。 2、为了防止内存不够用会开辟更多的空间,容易浪费内存。

动态内存分配:在程序运行过程中,动态指定需要使用的内存大小,手动释放,释放之后这些内存还可以被重新使用。

创建一个数组,动态指定数组的大小

void main(){
	int size;
	scanf("%d",&size);
	
	//开辟内存,大小size*sizeof(int)字节
	int* p = malloc(size*sizeof(int));
	//p是数组的首地址,p就是数组的名称
	//给数组元素赋值(使用这一块刚刚开辟出来的内存区域)
	int i = 0;
	for (; i < size; i++){
		p[i] = rand() % 300;
		printf("%d     %#x\n", p[i], &p[i]);
	}
	//释放p
	free(p);

	getchar();
}

realloc :重新分配内存

void main(){
	int size;
	scanf("%d",&size);
	
	//开辟内存,大小size*sizeof(int)字节
	int* p = malloc(size*sizeof(int));
	//p是数组的首地址,p就是数组的名称
	//给数组元素赋值(使用这一块刚刚开辟出来的内存区域)
	int i = 0;
	for (; i < size; i++){
		p[i] = rand() % 300;
		printf("%d     %#x\n", p[i], &p[i]);
	}

	int addSize;
	printf("输入数组增加的长度:");
	scanf("%d", &addSize);
	//内存不够用,扩大刚刚分配的内存空间
	int* p2 = realloc(p, (addSize + size)*sizeof(int));
	if (p2 == NULL){
		printf("重新分配失败");
	}

	//重新赋值
	int j = 0;
	printf("\n\n");
	for (; j < (size + addSize); j++){
		p2[j] = rand() % 100;
		printf("%d   %#x\n", p2[j], &p2[j]);
	}
	//手动释放内存
	if (p != NULL){
		free(p);
		p = NULL;
	}
	if (p2 != NULL){
		free(p2);
		p2 = NULL;
	}
	getchar();
}

运行结果.png

重新分配内存的两种情况: 1、缩小,缩小的那一部分数据会丢失 2、扩大,(连续的) (1)如果当前内存段后面有需要的内存空间,直接扩展这段内存空间,realloc返回原指针; (2)如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据库释放掉,返回新的内存地址; (3)如果申请失败,返回NULL,原来的指针仍然有效。

内存分配的几个注意细节: 1.不能多次释放 2.释放完之后(指针仍然有值),给指针置NULL,标志释放完成 3.内存泄露(p重新赋值之后,再free,并没有真正释放内存)