C语言——内存管理与生命周期

1.C语言内存的分配

参考1

1.1内存的分区

1.一个C/C++编译的程序占用内存分为以下几个部分:

  • 栈区(stack):由编译器自动分配与释放,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等。其操作类似于数据结构中的栈。

     1.临时创建的局部变量和const定义的局部变量存放在栈区
     2.函数调用和返回时,其入口参数和返回值存放在栈区。
    
  • 堆区(heap):一般由程序员自动分配,如果程序员没有释放,程序结束时可能有OS回收。其分配类似于链表,和数据结构里的堆是两回事。

    1. 堆区由程序员分配内存和释放。
    2.堆区按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,
    速度较慢,但自由性大,可用空间大。
    
  • 全局区(静态区static):存放全局变量、静态数据。程序结束后由系统释放。全局区分为已初始化全局区(data)未初始化全局区(bss)。全局变量和静态局部变量的存储是放在一块的,初始化的全局变量和静态局部变量在一块区域(data)未初始化的全局变量和未初始化的静态局部变量在相邻的另一块区域。(bss),用 0 初始化。

    .bss段
    1.未初始化的全局变量和未初始化的静态变量存放在.bss段。
    2.初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
    3.bss段不占用可执行文件空间,其内容由操作系统初始化
    
    .data段
    1.已初始化的全局变量存放在.data段。
    2.已初始化的静态变量存放在.data段。
    3.data段占用可执行文件空间,其内容由程序初始化。
    
  • 常量区(文字常量区):存放常量字符串,字符串”ABCD“等,程序结束后由系统释放。

    常量区
    1.字符串、数字等常量存放在常量区。
    2.const修饰的全局变量存放在常量区。
    3.程序运行期间,常量区的内容不可以被修改。
    
  • 代码区:存放函数体(类成员函数和全局区)的二进制代码。

在这里插入图片描述

#include<stdio.h>
int a;//全局区中的bss 区,用0初始化,存放未初始化全局变量和未初始化static变量
int b=1;//全局区中的data区,存放初始化全局变量和初始化static变量
static int n;//全局区中的bss 区,用0初始化,存放未初始化全局变量,加static未初始化也在bss区
static int o=1;//全局区中的data区,存放初始化全局变量和初始化static变量
const int j;//全局区中的bss 区,用0初始化,存放未初始化全局变量,加const未初始化也在bss区
const int k=1;//常量区,加const的初始化了的全局变量放在常量区
const int l=1;//常量区,加const的初始化了的全局变量放在常量区

int functiona()//函数名代表函数的地址,在代码区
{
    
    }
int functionb()//函数名代表函数的地址,在代码区
{
    
    }
int main()
{
    
    	int c; //栈区
	int d=1;//栈区
	int e=2;//栈区
	const  int m=2;//栈区
	static int f;//全局区中的bss 区,用0初始化,存放未初始化全局变量和未初始化static变量
	static int g;//全局区中的bss 区,用0初始化,存放未初始化全局变量和未初始化static变量
	static int h=1;//全局区中的data区,存放初始化全局变量和初始化static变量
	static int i=1;
	int *p1 = malloc(4);    //已初始化局部指针变量p1
	int *p2 = malloc(4);    //已初始化局部指针变量p2
	printf("栈区—变量的地址\n");
	printf("未初始化局部变量c的地址为:%d\n已初始化局部变量d的地址为:%d\n已初始化局部变量e的地址为:%d\n",&c,&d,&e);
	printf("加const的初始化局部变量m的地址为:%d\n",&m);
	printf("已初始化局部变量指针p1的地址为:%d\n",&p1);
	printf("已初始化局部变量指针p2的地址为:%d\n",&p2);
	printf("\n");
	printf("全局区(bss)—变量的地址\n");
	printf("加static关键字未初始化局部变量f的地址为:%d\n加static关键字未初始化局部变量g的地址为:%d\n未初始化全局变量a的地址为:%d\n",&f,&g,&a);
	printf("加const的未初始化全局变量j的地址为:%d\n",&j);
	printf("static修饰的全局未初始化变量n的地址为n=%d\n",&n);
	printf("\n");
	printf("全局区(data)—变量的地址\n");
	printf("初始化全局变量b的地址为:%d\n加static关键字初始化局部变量h的地址为:%d\n加static关键字初始化局部变量i的地址为:%d\n",&b,&h,&i);
	printf("static修饰的全局初始化变量o的地址为o=%d\n",&o);
	printf("\n");
	printf("常量区的地址\n");
	printf("加const的初始化全局变量k的地址为:%d\n",&k);
	printf("加const的初始化全局变量l的地址为:%d\n",&l);
	printf("\n");
	printf("代码区的地址\n");
	printf("函数functiona的地址为:%d\n",functiona);
	printf("函数functionb的地址为:%d\n",functionb);
	printf("\n");
	printf("堆区的地址\n");
    printf("已初始化指针p1指向的地址为:%d\n",p1);
	printf("已初始化指针p2指向的地址为:%d\n",p1);
    /*未初始化的全局变量,static修饰的变量在bss区,会默认赋值为0*/
	printf("全局未初始化变量a的默认初始值为a=%d\n",a);
	printf("局部未初始化变量c的默认初始值为c=%d\n",c);/*局部变量不初始化分配值*/
	printf("静态未初始化变量f的默认初始值为f=%d\n",f);
	printf("const修饰的全局未初始化变量j的默认初始值为j=%d\n",j);
}

栈区—变量的地址
未初始化局部变量c的地址为:1703724
已初始化局部变量d的地址为:1703720
已初始化局部变量e的地址为:1703716const的初始化局部变量m的地址为:1703712
已初始化局部变量指针p1的地址为:1703708
已初始化局部变量指针p2的地址为:1703704

全局区(bss)—变量的地址
加static关键字未初始化局部变量f的地址为:4357200static关键字未初始化局部变量g的地址为:4357204
未初始化全局变量a的地址为:4357208const的未初始化全局变量j的地址为:4357700
static修饰的全局未初始化变量n的地址为n=4357196

全局区(data)—变量的地址
初始化全局变量b的地址为:4344368static关键字初始化局部变量h的地址为:4344376static关键字初始化局部变量i的地址为:4344380
static修饰的全局初始化变量o的地址为o=4344372

常量区的地址
加const的初始化全局变量k的地址为:4333596const的初始化全局变量l的地址为:4333600

代码区的地址
函数functiona的地址为:4198405
函数functionb的地址为:4198410

堆区的地址
已初始化指针p1指向的地址为:7474728
已初始化指针p2指向的地址为:7474728
全局未初始化变量a的默认初始值为a=0
局部未初始化变量c的默认初始值为c=-858993460
静态未初始化变量f的默认初始值为f=0
const修饰的全局未初始化变量j的默认初始值为j=0
Press any key to continue

参考文章:STM32下的内存分配

2. c语言变量的作用域与生命周期

2.1局部变量

特点:

1、在{}内部定义的变量就是局部变量。
2、只有执行到定义变量的这个语句,系统才会给整个变量分配空间。
3、当离开{}这个非静态局部变量自动释放,无法使用。
4、局部变量的作用域在当前{},离开此大括号,变量无法使用。
5、普通局部局部变量也叫自动变量auto。
6、不在同一作用域的变量可以同名。取的时候是就近原则。
7、普通局部变量不初始化默认为随机数
#include<stdio.h>
int a = 2;
int* p = &a;
int main()
{
    
    
	int a = 1;
	printf("局部变量a=%d\n",a);
	printf("全局变量a=%d\n",*p);
	printf("局部变量a的地址=%d\n",&a);
	printf("全局变量a的地址=%d\n", p);
}
局部变量a=1
全局变量a=2
局部变量a的地址=-2066614796
全局变量a的地址=1762771024

D:\VS\vsinstall\Project1\x64\Debug\Project1.exe (进程 12808)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

注意此处局部变量a的地址为:局部变量a的地址=-2066614796,因为将地址作为有符号数输出了。地址是一个无符号数,这里地址的最高位为1,因此当作为有符号数输出,看起来是负数。
也可用%u,来输出无符号十进制数即可。

2.2静态局部变量

1、在{}内部定义的变量就是局部变量。
2、函数没有调用前就存在。
3、当离开{}这个静态局部变量不会自动释放,只有程序程序结束,static变量才自动释放。
4、局部变量的作用域在当前{},离开此大括号,变量无法使用。
5、不在同一作用域的变量可以同名。取的时候是就近原则。
6、如果局部变量不初始化,默认为0
7、值有执行到的时候才初始化,初始化语句只会执行一次,但可以赋值多次。
8、静态变量只能用常量初始化

在这里插入图片描述
static int b = 2;语句只会被执行一次,且b不会被释放。因此第一次进来b被赋值为3,第二次进来被赋值为4

#include<stdio.h>

void function()
{
    
    
	int a = 1;
	static int b = 2;
	b = a + b;
	printf("b=%d\n",b);
}
int main()
{
    
    
	function();
	//printf("静态局部变量b的值为:%d",b);
	printf("11111\n");
	function();
}

在这里插入图片描述

2.3 普通局部变量与静态局部变量区别

1.内存的分配与释放:

 1. 普通局部变量只有执行到定义变量的语句才分配空间。
 2.  静态局部变量在编译阶段(函数还没有执行),变量的空间已经分配。
 3. 普通局部变量离开作用域{},自动释放。
 4.  静态局部变量只有在整个程序结束才自动释放。

2.初始化

1.普通局部变量不初始化,值为随机数。
2.静态局部变量不初始化,值为0。
3.静态局部变量初始化语句只有第一次执行时有效。
4.静态局部变量只能用常量初始化。

2.4普通全局变量

1.在{}外面(函数外面)定义的变量为全局变量。
2.只有定义了全局变量,任何地方都能使用此变量。
3.如果使用变量时,在前面找不到此全局变量的定义,需要声明才能使用。
4.全局变量不初始化,默认赋值为0。
5.声明只针对全局变量,不针对声明多次。
6.全局变量在编译阶段已经分配空间,程序结束,自动释放。
7.全局变量只能定义一次,可以声明多次。
8.不同文件,普通全局变量只能定义一次,可以声明多次。
#include<stdio.h>
int c = 1;
void function()
{
    
    
	int a = 1;
	extern d;//声明
	//int c = 2;
	static int b = 2;
	b = a + b;
	//c = b;
	printf("b=%d\n",b);
	printf("c=%d\n",c);
	printf("d=%d",d);
}
int d = 3;//在funct()函数后面定义的全局变量,需要在前面声明才可以使用,或者定义在前面
int main()
{
    
    
	function();
	printf("11111\n");
	function();
}

```c
b=3
c=1
d=311111
b=4
c=1
d=3
D:\VS\vsinstall\Project1\x64\Debug\Project1.exe (进程 1240)已退出,代码为 0。
按任意键关闭此窗口. . .
注意:如果全局变量定义了一个:int c = 1;则在函数体中如果没有定义相同名称的变量,
则取值全局变量定义的值。如果函数体中定义了相同名称的变量:int c = 2;则取局部变量的值。
C语言对全局变量的缺陷:
如果定义一个全局变量,没有赋值(初始化),无法确定是定义,还是声明。
如果定义一个全局变量同时初始化,这个肯定是定义。
如果声明一个全局变量,建议初始化,如果声明一个全局变量建议加extern关键字

2.5静态全局变量

1.静态全局变量和普通全局变量的区别就是作用域不一样。
2.extern关键字只适合普通全局变量
3.普通全局变量所有文件都能使用,别的文件不能使用。
4.静态全局变量只能在本文件中使用,别的文件不能使用。
5.不同的文件只能出现一个普通全局变量的定义。
6.一个文件只能有一个静态全局变量的定义,不同文件之间的static全局变量,就算名字相同,也是没有关系的两个变量

2.6 普通函数和静态函数(文件作用域不一样)

1.所有的文件只能有一次普通函数的定义。
2.一个文件可以有一个静态函数的定义
3.普通函数所有文件都能调用,前提是声明
4.静态函数只能在定义所在的文件中使用

猜你喜欢

转载自blog.csdn.net/qq_44772972/article/details/123622566