C言語 - メモリ管理とライフサイクル

1. C言語のメモリ割り当て

参考1

1.1 メモリパーティション

1. C/C++ コンパイルされたプログラムが占有するメモリは、次の部分に分割されます。

  • スタック領域 (stack ): コンパイラによって自動的に割り当ておよび解放され、実行時関数用に保存されます。ローカル変数、関数パラメータ、戻りデータ、戻りアドレスなど。その動作はデータ構造のスタックに似ています。

     1.临时创建的局部变量和const定义的局部变量存放在栈区
     2.函数调用和返回时,其入口参数和返回值存放在栈区。
    
  • ヒープ領域(ヒープ):通常はプログラマによって自動的に割り当てられますが、プログラマが解放しない場合、プログラム終了時にOSのリサイクルが行われる場合があります。その割り当てはリンク リストに似ていますが、データ構造のヒープとは異なります。

    1. 堆区由程序员分配内存和释放。
    2.堆区按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,
    速度较慢,但自由性大,可用空间大。
    
  • グローバル領域(静的領域):グローバル変数と静的データを格納します。プログラム終了後にシステムにより解放されます。グローバルエリアは、初期化済みグローバルエリア(data)未初期化グローバルエリア(bss)に分かれます。グローバル変数と静的ローカル変数は一緒に格納されます。初期化されたグローバル変数と静的ローカル変数が一つの領域(データ)に初期化されていないグローバル変数と初期化されていない静的ローカル変数は別の隣接領域にあります。(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 を使用して符号なし 10 進数を出力することもできます。

2.2 静的ローカル変数

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

ここに画像の説明を挿入します
static int b = 2; ステートメントは 1 回だけ実行され、b は解放されません。したがって、 b には、初めて入ったときには値 3 が割り当てられ、2 回目に入ったときには値 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