C语言内存分配策略

C语言的特色之一是:程序员必须亲自处理内存的分配细节。

C语言使用栈(Stack)来保存函数返回地址/栈祯基址、完成函数的参数传递和函数局部变量的存储。 如果程序需要在运行的过程中动态分配内存,可以利用(Heap)来实现

基本上C程序的元素存储在内存的时候有3种分配策略:

静态分配

如果一个变量声明为全局变量或者是函数的静态变量,这个变量的存储将使用静态分配方式。静态分配的内存一般会被编译器放在数据段代码段来存储,具体取决于实现。静态分配内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,这样做的前提是,在编译时就必须确定变量的大小。 

例如IA32的x86平台及gcc编译器,全局及静态变量放在数据段的低端;全局及静态常量放在代码段的高端。

自动分配

函数内局部变量的存储单元都可以在栈上创建,函数的自动局部变量随着函数的返回(函数执行结束)会自动释放(失效),这个局部变量一般都是利用栈(Stack)来满足的。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。相比于静态分配,不必绝对要求这个变量在编译时就必须确定变量的大小,运行时才决定也不迟,但是C89仍然要求在编译时就要确定,而C99放松了这个限制。但无论是C89还是C99,都不允许一个已经分配的自动变量运行时改变大小。

所以说C函数永远不应该返回一个局部变量的地址。

要指出的是,自动分配也属于动态分配,甚至可以用alloca函数来像分配堆(Heap)一样进行分配,而且释放是自动的。

动态分配

另外一种更加特殊的情况,变量的大小在运行时有可能改变,或者虽然单个变量大小不变,变量的数目却有很大弹性,不能静态分配或者自动分配,这时候可以使用(Heap)来满足要求。ANSI C定义的堆操作函数是malloc、calloc、realloc和free。

使用(Heap)内存将带来额外的开销和风险。


请看下面的程序的地址分配:


#include 
#include 
#include 

int a = 0;  //全局初始化区
char *p1; 	//全局未初始化区

int main()
{
	int b; 
	char s[] = "abc";
	char *p2;
	char *p3 = "123456";
	static int c =0;
	p1 = (char *)malloc(4);
	p2 = (char *)malloc(16);//分配得来的就在堆区。
	 	
	
	fprintf(stdout, "stack\n");
	fprintf(stdout, "&b: %p\n", &b);
	fprintf(stdout, "&s: %p\n", &s);
	fprintf(stdout, "&p2: %p\n", &p2);
	fprintf(stdout, "&p3: %p\n", &p3);
	
	fprintf(stdout, "\nheap\n");
	fprintf(stdout, "p1: %p\n", p1);
	fprintf(stdout, "p2: %p\n", p2);
	fprintf(stdout, "p3: %p\n", p3);
	
	strcpy(p1, "123456");  //"123456"存放常量区,编译器优化使其与p3所指向的"123456"在一个地方。
	fprintf(stdout, "*p1: %p\n", *p1);
	
	fprintf(stdout, "\nmain: %p\n", main);
	
	fprintf(stdout, "\nstatic & global\n");
	fprintf(stdout, "&a: %p\n", &a);
	fprintf(stdout, "&p1: %p\n", &p1);
	fprintf(stdout, "&c: %p\n", &c);	
	
	fprintf(stdout, "const\n");
	fprintf(stdout, "&\"abc\": %p\n", &"abc");
	fprintf(stdout, "&\"123456\": %p\n", &"123456");
	
	return 0; 
}



你可能感兴趣的:(C/C++)