目次
作成するのは簡単ではありませんが、このブログが役に立った場合は、忘れずにメッセージを残して「いいね!」をしてください。
C言語をしばらく学習していますが、今日はC言語の記憶の主要な5つの領域についてまとめたいと思います。C言語を深く理解するためには非常に必要な知識です。5 つの主要な領域を理解することは、C 言語の最下層をさらに学習するのに非常に役立ちます。
1 C言語のメモリパーティション
1.1 5 つのメモリ パーティション
C 言語のメモリは、次の図と表に示すように、大きく 5 つの領域に分類できます。
メモリイメージ領域 | コンテンツ | 権限 |
スタック領域 | 関数内の通常の変数 | 読み書き可能 |
ヒープ領域 | 動的に割り当てられるメモリ | 読み書き可能 |
(グローバル) 静的変数領域 | 静的に変更された変数 | 読み書き可能 |
一定面積 | 変数を初期化するための定数 | 読み取り専用 |
コードエリア | コード命令 | 読み取り専用 |
nt k=1;
void main()
{
int i=1;
char *j;
static int m=1;
char *n="hello";
printf("栈区地址为:0X%x\n",&i);
j = (char*)malloc(2); //一般不确定需要多大空间的时候用
free(j);//及时释放
printf("堆区地址为:0X%x\n",j);
printf("全局变量地址为:0X%x\n",&k);
printf("静态变量地址为:0X%x\n",&m);
printf("文字常量区地址为:0X%x\n",n);
printf("程序区地址为:0X%x\n",&main);
}
char *i="hello";
char j[10]="hello";
printf("0X%x\n",i); //存放在文字常量区
printf("0X%x\n",j); //存放在栈区
j[1]='*';//可以直接赋值
//*(i+1)='*'; //等价于i[1]='*';
//不可以这样赋值, 因为i是指针,指向的是文字常量区,里面的内容是不能修改的
i=j; //这样可以
printf("%s\n",i);
printf("%x\n",i);
j=i;//这样不可以,因为j虽然也是地址,但是不是指针变量,不能直接赋值
1.2 メモリパーティションの概要
1.2.1 スタック領域(スタック)
栈区
コンパイラによって自動的に割り当ておよび解放され、手動で管理することなくオペレーティング システムによって自動的に管理されます。
スタック上のコンテンツは関数のスコープ内にのみ存在し、関数の実行が終了するとコンテンツは自動的に破棄されます。
#include<stdio.h>
char *getMem()
{
char buf[64]; //局部变量 栈区存放
strcpy(buf, "123456789");//向buf所代表的内存中写入内容
//printf("buf:%s\n", buf);
return buf;//返回所分配内存区域的第一个元素的地址
}
void main()
{
char *tmp = NULL;
tmp = getMem(10);
if (tmp == NULL)
{
return ;
}
printf("tmp:%s\n", tmp);//输出tmp:
system("pause");
return ;
}
メモリ分析:
- スタック領域は
由高到低
メモリアドレス方向に増加し、その最大サイズはコンパイル時に決まり、速度は速いですが自由度が悪く、最大容量は大きくありません。 - 書庫エリアは
先进后出
原則として、先に入った者は家の最奥でブロックされ、後から入った者は戸口で、戸口から入った人は解放されると先に出ます。 -
スタックストレージコンテンツ
- スタック領域に一時的に作成され
局部变量
格納されます。const定义的局部变量
- 関数が呼び出されて返されると、その
入口参数
合計が返回值
スタック領域に格納されます。
平たく言えば:
スタック領域には、関数内で定義された int a、int b、const int a、char p、char arr[] などのローカル変数が格納され、関数の仮引数などが格納されます。スタック領域のデータはコンパイラによって管理され、呼び出し後に自動的に解放され、スタックにプッシュされ、スタックからポップされます。先入れ後出しの原則。たとえば、関数呼び出しを実行すると、コンパイラはまず次のコードのアドレスをスタックにプッシュし、次に呼び出した関数内のローカル変数や仮パラメータなどをスタックにプッシュし、関数呼び出しが完了するのを待ちます。スタックは、呼び出した関数の前にスタックにプッシュされたすべての変数と仮パラメータをクリアし、次のコードのアドレスに従ってプログラムを実行します。後続のプログラムもこの方法で実行されます。スタック領域のサイズは通常 1M 程度であるため、あまり大きな配列を定義しないでください。
1.2.2 ヒープ領域(ヒープ)
堆区
メモリの割り当てと解放はプログラマによって行われます。プログラマがそれを解放しない場合、プログラムの終了時にオペレーティング システムによって再利用される可能性があります。
#include <stdio.h>
char *getMem(int num)
{
char *p1 = NULL;
p1 = (char *)malloc(sizeof(char) * num);
if (p1 == NULL)
{
return NULL;
}
return p1;
}
void main()
{
char *tmp = NULL;
tmp = getMem(10);
if (tmp == NULL)
{
return ;
}
strcpy(tmp, "111222"); //向tmp做指向的内存空间中copy数据,注意不是向指针变量tmp中
printf("tmp:%s\n", tmp);//输出tmp:111222
system("pause");
return ;
}
メモリ分析:
- ヒープ領域は
由低到高
メモリアドレス方向に増加し、そのサイズはシステムメモリ/仮想メモリの上限によって決まり、速度は遅いですが、自由度が高く空き容量が大きいです。
ヒープ領域のメモリを動的に割り当て、解放するなど
の関数を利用して、動的なメモリ分散を実現します。malloc()
free()
void *malloc(size_t);
- パラメータ
size_t
は割り当てのサイズ (バイト単位) です。 - 戻り値は、
void*
割り当てられた領域の最初のアドレスを指す型ポインタです
(void *
型ポインタは他の型のポインタに変換できます)。
関数を使用してメモリを解放しないと、メモリ リークfree()
が発生します。
void free(void * /*ptr*/);
- パラメータは、
ptr
割り当てられたメモリの最初のアドレスです。 - 戻り値はありません。
平たく言えば:
プログラマーによる手動の適用と解放
例: int p=(int )malloc(sizeof(int)10)。これは、40 バイトのヒープ領域が適用されていることを意味し、適用後に解放することを忘れないでください。
コード領域はコードを保存するために使用され、コードはバイナリ ストレージに変換されます。
1.2.3 (グローバル) 静的領域
これは通常、コンパイル中に記憶サイズが決定できる変数の記憶領域に使用されますが、プログラムの実行時間全体で表示される全局变量
合計にも使用されます静态变量
。
大域ゾーンは、 と 、で構成されます。 .bss段
.data段
可读可写
#include <stdio.h>
char * getStr1()
{
char *p1 = "abcd";
return p1;
}
char *getStr2()
{
char *p2 = "abcd";
return p2;
}
void main()
{
char *p1 = NULL;
char *p2 = NULL;
p1 = getStr1();
p2 = getStr2();
//打印p1 p2 所指向内存空间的数据,不是p1 p2中的数据
printf("p1:%s , p2:%s \n", p1, p2);//输出p1:abcd , p2:abcd
//打印p1 p2 的值
printf("p1:%d , p2:%d \n", p1, p2);//输出p1:19184372 , p2:19184372
system("pause");
return;
}
メモリ分析:
.bss段
初期化されていないグローバル変数と初期化されていない静的変数は、.bss セクションに保存されます。
0 に初期化されたグローバル変数と 0 に初期化された静的変数は、.bss セクションに格納されます。
.bss セグメントは実行可能スペースを占有せず、その内容はオペレーティング システムによって初期化されます。.data段
初期化されたグローバル変数は .data セグメントに保存されます。
初期化された静的変数は .data セグメントに保存されます。
.data セグメントは実行可能ファイルのスペースを占め、その内容はプログラムによって初期化されます。
平たく言えば:
グローバル領域はかなり特殊で、さらにグローバル変数領域、スタティック変数領域、定数領域に分かれています。グローバル変数領域はグローバル変数を格納する領域であり、スタティック変数領域は静的に変更された変数(スタティックローカル変数、スタティックグローバル変数を含む)を格納する領域であり、staticが含まれる限り存在します。定数領域には、文字定数のほか、const で修飾されたグローバル変数が格納されます。const で修飾されたローカル変数はここには存在しないので、混同しないようにしてください。グローバル領域に格納されたものはすべてオペレーティングシステムによって管理され、プログラムの終了時にオペレーティングシステムによって解放されます。定数領域に格納されたデータはポインタを使っても変更できません const で変更したローカル変数はポインタで変更できると言われるかもしれませんが、ローカル変数は定数領域に格納されません。
1.2.4 定面積
字符串
、数字
その他の定数は定数領域に格納されます。const
変更されたグローバル変数は定数領域に格納されます。
プログラムの実行中は、定数領域の内容を変更することはできません。
1.2.5 コード領域
程序执行代码
コード領域に格納されているため、値を変更することはできません(変更するとエラーになります)。コード領域に格納される場合もあります字符串常量
。define定义的常量
.exeファイル生成後に上記5つの領域、コード領域、グローバル領域が作成されますので、.exeファイルをダブルクリックすることでプログラムを実行し、スタック領域とヒープ領域を生成します。
下の写真の真上にあります。
#include<stdio.h>
#include<string.h>
int a = 10;
static int b = 20;
void fun(int x)
{
char *p = "Hello";
printf("形参x的地址=%d\n\n", &x);
printf("Hello的地址=%d\n\n", "Hello");
printf("指针变量p的地址=%d\n\n", &p);
return;
}
int main(int argc,const char *argv[])
{
int c = 10;
int d = 20;
static int e = 30;
char *p = "Hello";
printf("\n全局变量a的地址=%d\n\n", &a);
printf("静态全局变量b的地址=%d\n\n", &b);
printf("静态局部变量e的地址=%d\n\n", &e);
printf("字符串\"Hello\"的地址=%d\n\n", "Hello");
printf("局部变量c的地址=%d\n\n", &c);
printf("局部变量d的地址=%d\n\n", &d);
printf("指针变量p的地址=%d\n\n", &p);
fun(5);
system("pause");
return 0;
}
図を使って簡単に説明すると、
グローバル領域には、グローバル変数、静的変数、文字定数、および const で変更されたグローバル変数が格納されます。スタック領域には、ローカル変数や関数の仮パラメータや、一部のコードのアドレスが格納されます。スタック領域の内容は変更可能です。ヒープ領域は、プログラマが手動で適用および解放します。malloc 関数によって適用され、free 関数によって解放されます
。