動的メモリ空間管理

ここに画像の説明を挿入

  • 私の世界へようこそ^_^
  • 著者の記事がお役に立てば幸いです。不備があれば修正してください。一緒に学び、コミュニケーションを取りましょう!

序文:

以前記事を投稿しました: C言語の構造. 私にとってはまだ一方的なだけのところがたくさんありますが、それでも収穫は大きいです. たとえば: 構造の入れ子やメモリのアライメントを知るために、 を読みましたたくさんの情報があります。ここに感謝します。ワインを買う小さなコード農家、ブロガーは乾物でいっぱいです。
これは私が学んだ知識が十分ではないことを証明するものでもあります。ベテランの方もコメント エリアで私とコミュニケーションをとることができます。一緒に進歩しましょう。ブログを書いていると自分の欠点がたくさん見つかりますが、これは私自身の勉強でもあり、とても気に入っている一文をお話したいと思います
。 ———————————————軽く考えてください

動的記憶とは何ですか

  1. C 言語では、メモリ開発はスタック上で実行されます。つまり、これは静的メモリに属します。
int i=0;//这是向内存开辟了一块4个字节的空间来存放了变量 i
int arr[10]={
    
    0};//这是开辟了40个字节来存放数组 arr
//      在这里开辟的内存空间大小是不可变的;
//这里有人想问:我为什么想着改变着的内存空间呢?
//   你想啊,这里我们开辟了一块40个字节的数组,这么大的一块空间可不是想变大就大,
//想小就小的,这可能会和我们所需要的不一样,这会很不方便
//但是如果有一个你想多大就多大的空间呢?
//所以这就是我下来要讲的 动态内存空间管理 了

C 言語では静的メモリが解放され、その特徴は次のとおりです。
1.他所开辟的空间是固定的
2.数组在声明的时候,必须指定数组的长度,他所需要的内存在编译的时候分配

しかし、スペース要件については、わからないことがあります。スペースが大きすぎて無駄が発生する可能性もあれば、スペースが小さすぎてスタック オーバーフローが発生する可能性もあります。このようにして、動的メモリが必要です。管理者は、どれくらいのメモリが必要か、どれくらいのメモリを解放すべきかを知らせてくれます。

しかし、動的メモリが必ずしも静的メモリにスペースを空けるのに適しているというわけではありません。良いものはすべて諸刃の剣です。この文を覚えておいてください!


1. 動的メモリの概要:

動的メモリ割り当てスペースはヒープ領域内にあり、静的メモリ割り当てとは異なります。動的メモリ割り当てでは、次の関数を呼び出す必要があります。

ダイナミックメモリに関する機能の紹介

1. malloc と free

   void*  malloc (size_t  size);        

この関数はメモリ内の連続した領域 (ヒープ領域) に適用でき、この領域の開始位置のアドレスを返しますが、この領域は初期化されません。

如:
      int* pf= (int *) malloc(40);  //  40 ---->的单位是字节

40 バイトのスペースが空きましたが、それが何型であるかわからないため、必要な型 (int*) を手動でキャストする必要があります。

知らせ:
1. 割り当てが成功した場合は、割り当てられた領域へのポインタを返します。
2. 割り当てに失敗した場合は NULL ポインタが返されるため、malloc の戻り値を確認する必要があります。
3. 戻り値の型は void * であるため、malloc 関数は開かれた空間の型を知りません。使用する場合はユーザーが自分で実装します。
4. パラメータサイズが 0 の場合、malloc の動作は標準で定義されておらず、コンパイラに依存します。

这里因为我们有可能会动态内存申请失败的,所以我们应该更加加以检查,养成好习惯,在每次开辟了一块动态内存空间后面立马进行判断是否申请开辟空间成功。

  • C 言語には、動的メモリの解放とリサイクルに特別に使用される別の関数が無料で提供されています。
  void * free (void * ptr); 

彼は、動的記憶によって開かれた記憶を解放するために特に使用されます。

知らせ:

1. パラメータ ptr が指す空間が動的に開かれていない場合、free 関数の動作は未定義です。
2. パラメータ ptr が NULL ポインタの場合、関数は何も行いません。

1.当malloc函数申请的内存空间,当程序退出时,会还给操作系统;当程序不退出时,动态内存申请的内存空间,不会主动释放。一定需要free函数来释放,所以我们要养成好习惯,每每开辟一块动态内存空间,后面一定要记得free释放这块空间。
2.free只释放动态内存空间,不能对静态内存操作哦
3.free释放该指针的地址后,会导致该指针为野指针,一定给该指针重新赋值空指针(NULL)

例:

int main()
{
    
    
	//开辟一块40个字节的动态内存空间,且强转位int*类型
	int* pf =(int *) malloc(40);
	//判断是否开辟成功
	if (pf == NULL)
	{
    
    
		perror("malloc");//如果开辟失败了,打印出原因
		return 1;      //并且不用再继续往下了,就返回1
	}
	//如果开辟成功,则打印出这个地址所指的内容和往后10个的内容
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d\n", *(pf + i));
	}

	//释放开辟的内存
	free(pf);//这里注意,释放pf的地址后,pf就会变成一个野指针,
	//这里一定需要重新给他赋值上NULL,这也是个好习惯
	pf = NULL;

	return 0;
}

ここに画像の説明を挿入

この図は、動的メモリが malloc によって開かれたときに初期化されないことも示しています。

2.calloc関数

  • この関数は malloc 関数にほぼ似ており、動的メモリ割り当てにも使用されます。
   void*  calloc  (size_t  num,size_t  size);
  • この関数の機能は、サイズが size である num 個の要素用のスペースを開き、スペースの各バイトを 0 に初期化することです。
  • 関数 malloc との唯一の違いは、calloc はアドレスを返す前に、要求された空間の各バイトをすべて 0 に初期化することです。

例: 上記とほぼ同じコード。

int main()
{
    
    
	//开辟一块40个字节的动态内存空间,且强转位int*类型
	int* pf = (int*)calloc(10, sizeof(int ));
	//判断是否开辟成功
	if (pf == NULL)
	{
    
    
		perror("calloc");//如果开辟失败了,打印出原因
		return 1;      //并且不用再继续往下了,就返回1
	}
	//如果开辟成功,则打印出这个地址所指的内容和往后10个的内容
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d\n", *(pf + i));
	}

	//释放开辟的内存
	free(pf);//这里注意,释放pf的地址后,pf就会变成一个野指针,
	//这里一定需要重新给他赋值上NULL,这也是个好习惯
	pf = NULL;

	return 0;
}

ここに画像の説明を挿入

上記と同じコードですが、実行結果はすべて 0 で、calloc によって開かれた動的メモリが 0 に初期化されることがわかります。

3.realloc関数

  • realloc 関数により、動的メモリ管理がより柔軟になります。
  • 要求されたスペースが適切ではないことが判明し、メモリ サイズを柔軟に調整する必要がある場合は、realloc 関数を使用して動的に割り当てられたメモリ サイズを調整できます。
 void * realloc ( void* ptr , size_t  size);

そのパラメータ:
1.ptr は、調整するメモリ アドレスです。
2.size は、調整後の新しいサイズです。
3. 戻り値は、調整後のメモリの開始位置です
。 4. この関数は、元のメモリ空間のサイズを調整します。元のメモリ データは新しいスペースに移動されます
5. realloc がメモリ スペースを調整するときは 2 つの状況があります:
————— (1). 元の空きスペースの後にスペースを追加するとき: 存在しないことが判明します。後ろに十分なスペース、+ 図:

ここに画像の説明を挿入
1.开辟新空间 2.将旧的空间中的数据拷贝到新空间 3.释放旧的空间 4.返回新空间的起始位置地址

—————— (2). 後ろに十分なスペースがある場合は、(size - 元のバイト数) のスペース サイズを後ろに追加します。+ 図:

ここに画像の説明を挿入
直接在后面加上一块空间;

realloc 関数を使用する場合は、realloc を使用して調整できるように、まず動的メモリ空間の一部が開かれている必要があります。
成し遂げる:

int main()
{
    
    
	//开辟一块40个字节的整形空间大小
	int* pc = (int*)malloc(40);
	if (pc == NULL)
	{
    
    
		perror("malloc");
		return 1;
	}
	//初始化 1 - 10 的数字
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
    
		pc[i] = i + 1;
	}
	//想增加一些空间
	int* ptr = (int*)realloc(pc, 80);
	//     这里我想特别强调一点,为什么不让 pc指针接收,
	//而要创造一个新的指针接收呢?
	//     因为realloc增容可能会失败,那返回的就是NUKLL,
	//而如果把 NULL 给到 pc指针,那会造成内存泄露
	//    当然内存泄露是一个动态内存错误,再这篇博客的后面 
	//会一一介绍到动态内存错误
	//增加空间失败
	if (ptr == NULL)
	{
    
    
		perror("realloc");
		return 1;
	}
	//增加空间成功
	pc = ptr;//是将返回来的地址交给原来的指针维护
	ptr = NULL;

	//打印数据
	for (i = 0; i < 20; i++)
	{
    
    
		printf("%d\n", pc[i]);
	}

	//释放
	free(pc);
	pc = NULL;

	return 0;
}

ここに画像の説明を挿入
前面的1到10的初始化,后面是新增加的10个字节大小空间,并没有进行初始化。

- スペースを削減したい場合は、さらに簡単です。

スペースを削減する場合、上記の状況は存在しません。再割り当て後のパラメータのサイズを必要なサイズに直接変更できます。
例: 元のスペースのサイズを 20 バイトに削減します。

int *ptr = (int *) realloc(pc,20);

2. いくつかの一般的な動的メモリ エラー:

1. NULL ポインタに対する逆参照操作:

この問題は理解しやすいです。上で述べたはずです:
malloc が動的メモリ空間をオープンするときは、返されたアドレスを忘れずに確認する必要があります。malloc がスペースを正常にオープンするとは限らないためです。ヌル ポインタ (NULL) が返されます。ポインタを後で逆参照する必要がある場合、問題が発生します。

int main()
{
    
    
    int *ptr;
    ptr=(int*)malloc(sizeof(int));
    //这里不进行判断,如果时返回NULL则这将会出现问题
    *ptr=1;  
    
	//释放空间
    free(ptr);
    ptr=NULL;
        
    return 0;
}

2. 動的に割り当てられたスペースへの境界外アクセス

簡単に言うと、自分が開けた空間しか利用できず、この空間を越えて他の空間にアクセスすると立ち入り禁止になります。

#include<stdio.h>
#include<stdlib.h>//malloc 和 free 都在<stdlib.h>的头文件里
int main()
{
    
    
    int *ptr ;
    ptr =(int*)malloc(40); //申请一个动态内存空间为40字节
    if(ptr==NULL) //防止申请空间失败传入了空指针
    {
    
    
        perror("ptr");
        return 1;
    }
 
    for(int i=0;i<20;i++)
    {
    
    
        *(ptr+i)=i;//申请的是四十个字节,这里产生了越界
    }
    
    free(ptr);
    ptr=NULL;
    return 0;
}
 

2.1. 境界外アクセスの結果

  • 不明な古いアイアンがある場合は、以下の情報がインターネットで見つけた比較的完全な情報なので、ゆっくり味わうことができます。

1. 未定義の動作: C 言語標準では、コンパイラが範囲外アクセスの動作を保証しないと規定されており、結果は未定義です。これは、プログラムがクラッシュ、誤った出力、データ破損などの予期しない結果を引き起こす可能性があることを意味します。

2. メモリ破損: 範囲外のアクセスにより、他の変数やデータ構造のメモリ空間が破壊され、プログラムの異常な動作やクラッシュが発生する可能性があります。

3. セキュリティの脆弱性: 一部の悪意のあるユーザーは、境界外アクセスの脆弱性を利用してプログラムの実行フローを変更し、それによって悪意のあるコードを実行したり、不正なアクセス権を取得したりする可能性があります。

4. デバッグの困難: 範囲外のアクセスにより、プログラムの動作が予測不能になる可能性があり、プログラムのデバッグが困難になります。

3. free を使用して非動的に割り当てられたメモリを解放します。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
    int *p;
    *p=10;  
    free(p);  //这里的p并不是动态内存空间仍然进行了释放
    return 0;
}

记住一点:非动态无free;

4. free を使用して、動的に割り当てられたメモリの一部を解放します。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
    int *p=(int*)malloc(sizeof(int)*2);
    if(p==NULL)
    {
    
    
        perror("malloc");
        return 1;
    }
    int i=0;
    for(i=0;i<5;i++)
    {
    
        //这里只对前 5个进行赋值
		*p=i;
		p++;//这时p指针也会向高地址走去,
//这代表了p指针不再是指向这块空间的最初的起始位置地址
    }
    //而如果再对这块空间进行释放,还能只释放一部分么?
    //答案是不行的,程序会崩溃
    free(p); 
    p=NULL;
   
}

この種のエラーには、メモリ リークという別のエラーも含まれている必要があります。

動的に割り当てられたメモリの先頭へのポインタが解放される代わりに、メモリ ブロックの中間へのポインタが解放されると、メモリ リークが発生します。ポインタ位置からのメモリ空間はまだ割り当てられていますが、プログラムはこれらのメモリ空間にアクセスできず、メモリ リークが発生するためです。

所有在动态开辟空间时,最好不用动该空间的起始位置,最好重新创建一个指针进行操作,这也是一个好习惯哦;

5. ダイナミックな空間の複数のリリース

この種の間違いは、リリースしていないと思っていた怠慢によるものであるはずですが、結果はすでにリリースされていました(本当に死ぬほど泣きました)。

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	//开辟
    int *p=(int*)malloc(sizeof(int)*2);
    if(p==NULL)
    {
    
    
        perror("p");
    }
    
   //释放 
    free(p);
   //不记得自己的释放
   //~~~~~~
    free(p);  //再一次释放,会导致不可预测的后果;
    //   对这最好的解决办法就是:当我们释放了一块空间后,
    // 一定让他指为空指针
    p=NULL;
   
}
  • スペースを解放するとメンテナンスのためにヌルポインタを与えることになるので、解放したかどうか忘れて再度解放しても、事前にメンテナンスのためにヌルポインタを割り当てているのであまり影響はありません。 , そして、無料のヌルポインタは何もしないので、あまり重要ではありません。

当我们释放了一块空间后,一定让他指为空指针,这是一个好习惯哦;

6. 動的メモリ空間の解放忘れ(メモリリーク)

メモリリークについてはこれまで何度も言及されてきましたが、ついにここに来ました。

より深く理解するには、コードの一部を確認する必要があります。

void test()
{
    
    
    int*p = (int*)malloc(sizeof(int) * 2);
    //这是申请了这块空间返回地址给了指针 p
    if (p != NULL)
    {
    
    
        *p = 20;
    }
    //但是当退出该函数时,指针 p所占的空间会还给操作系统,
    //  这就代表刚刚开辟的空间无法再找到了,
    //     因为只有指针p指向该空间地址
}
int main()
{
    
    
    test(); 
    return 0;
}

それでも理解できない場合は、次のように理解することができます。私も次のように理解しています:
あなたが潜入捜査官で、上司の 1 人である警察官 P だけがあなたの潜入捜査官の身元を知っている場合, しかし、役員 P はミッション中に死亡しました。恥ずかしいことに、もう誰もあなたのことを知りません。これはメモリ リークに相当します。

切记动态开辟空间一定要记得释放,并且是正确的释放;这是一个好习惯哦。

もう少し詳しく学びましょう:

メモリ リークは慢性的な問題であり、すぐにはプログラムのクラッシュを引き起こしませんが、徐々にシステム メモリを占有し、システムの安定性とパフォーマンスに影響を及ぼし、最終的にはシステムのクラッシュを引き起こします。

内存泄漏(Memory Leak)是指程序在运行过程中无法释放已经分配的内存空间,导致系统中存在大量的无用的内存空间,最终可能导致程序崩溃甚至系统崩溃。


終わり:

通常、ヒープ領域はスタック領域よりも大きく、動的メモリは変更可能であり、必要なだけバイトを開くことができることがわかっているため、これは動的メモリにとってより重要です。この点は彼の利点を証明できます。したがって、動的メモリ空間を開くときは、利益よりも損失が大きくならないように注意する必要があります。

—————————

結局のところ、子供たちにとってコードを書いたり書いたりするのは簡単ではありません。サポートしていただきありがとうございます。あなたのサポートは子供たちにとって最大のモチベーションです。~~^_^~~

おすすめ

転載: blog.csdn.net/m0_66780695/article/details/132123639