技術共有

ゼロから学ぶC言語33 - メモリ管理(1)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. 基本的な状況
C 言語のメモリ管理は、システム管理とプログラマのユーザーマニュアル管理の 2 つの部分に分かれています。システムが管理するメモリは主に関数内の変数(ローカル変数)で、関数の実行時にこの部分の変数がメモリに入り、関数終了後はこの部分が「スタック領域」となります。を実行すると、オペレーティング システムがメモリから自動的にアンロードします。ユーザーが手動で管理するメモリは、主にプログラムの実行プロセス全体にわたって存在する変数(グローバル変数)です。この部分が配置されているメモリ領域を「ヒープ領域」と呼びます。これらの変数は手動でメモリから解放する必要があります。ユーザーによる。使用後に解放するのを忘れた場合、プログラムの終了時にオペレーティング システムに引き渡されるまで、メモリが占​​有され続けます。
2. ボイドポインタ
コンピュータのメモリ空間には固有のアドレスコードが割り当てられており、指定されたメモリ領域はメモリポインタによって見つけることができます。ポインター変数には型が必要です。例: int* p=&x; は整数変数 x のアドレスを指す int 型ポインターを宣言します。コンパイラーはこのアドレスからデータを取得するときに、int 型であることを認識します。データが保存されます。どのようなタイプのデータが格納されているかが不明で、最初にブロック メモリ アドレスを見つけたい場合は、void タイプ ポインタが使用されます。 void 型ポインタは不定型ポインタとも呼ばれ、任意の型のデータを指すことができます。
void 型のポインタは他の型のポインタに変換でき、格納されたコンテンツを「*」メソッドで解析できないことを除いて、その使用法には特別なことは何もありません。
int x = 10; //整数変数 x を宣言します。
void* p = &x; //void ポインターを宣言し、x のアドレスを指し、int ポインター (&x) が void ポインターに変換されることを示します。
int* q = p; // void ポインタは整数ポインタに変換されます。
printf( "%in", *q ); //実行結果: 10
void* と void の違いに注意してください。void は型なしであり、関数の宣言に使用される場合は戻り値がないことを意味しますが、void* は型なしですがポインターを持ちます。
3. メモリ管理に関する機能
1、malloc()
この関数は別々に覚えておくことができます。m はメモリの略語で、alloc はメモリを割り当てる略語です。
機能: ヒープ領域から連続メモリ ブロックを適用します (注意: ヒープ領域メモリはプログラマによって管理される必要があり、使用後に破棄する必要があります。これは常に覚えておく必要があります)。 使用形式: malloc (1 を参照)。
パラメータ: パラメータ 1 はメモリ ブロック サイズです (size_t 型の非負の整数、sizeof の戻り値はこの型です)
戻り値: void* ポインター (割り当てられたメモリを受け取るために使用する任意のタイプのポインターを使用します)
使用法: malloc 関数を使用して宣言された変数はヒープ領域にあるため、匿名宣言メソッドがよく使用されます。つまり、以下に示すように、特定の変数のアドレス メソッドを使用する代わりに、malloc はポインタを直接返します。
int* ptr = (int*) malloc(sizeof(int)); //ヒープ領域に int ポインタ変数が宣言されています
括弧内の強制変換は必要ありません。malloc は void* を返します。これは int* で受け取ることができます。これにより、コードが理解しやすくなります。
予防:
a. malloc 関数を使用してインクルードします。<stdlib.h>ヘッダー ファイル (のみが含まれるなど)<stdio.h>コンパイルは問題なく実行されますが、正しく実行されないことに注意してください。
b. ptr に値を割り当てます: *ptr=1000;。
c. malloc を free と組み合わせて使用​​します (後で説明します)。free (ptr) を忘れないでください。
d. Malloc はアドレスの割り当てに失敗する可能性があり、失敗した場合は NULL を返します。このため、処理のために if ステートメントを追加できます。
e. malloc は、初期化に関係なく、メモリを割り当てるだけです。初期化が必要な場合は、別の関数を呼び出す必要があります。
f. malloc が最も一般的に使用されるのは、配列およびカスタム データ構造にメモリを割り当てることです。
2、メモリセット()
機能: ポインタが指すメモリ ブロック内の各バイトに初期値を割り当てます。
パラメータ: パラメータ1 対象メモリへのポインタ パラメータ2 代入内容(int型のASCIIコード値またはchar型の文字) パラメータ3 割り当てるバイト数(size_t型)
戻り値:対象メモリを指すポインタを返します。パラメータ1と同様、受け取っても意味はありません。
使用法: memset(ptrDestMem,'A',sizeof(char)*1024) //長さ 1024 バイトのメモリ ブロックの各バイトに文字 A を割り当てます
予防:
a. この関数が属するヘッダー ファイルは次のとおりです。<string.h> , 一部のコンパイラはこのヘッダファイルをインクルードしなくても正常に使用できますが、実行中にエラーが発生する場合はインクルードしてください。
b. memset は (ビットではなく) バイトに対する操作であることに注意してください。パラメータ 3 は、割り当てる必要があるバイト数を指します。これは、ターゲット メモリ内のバイト数以下にすることができますが、制限を超えることはできません。
c. パラメータ 2 の値は 1 バイト(int 型 255)に収まる値を超えることはできません。
2、無料()
機能: malloc とペアになった関数。malloc 関数によって割り当てられたメモリを解放し、メモリ リークを防ぐために使用されます。
パラメータ: malloc 関数によって返されるポインタ
使用法: 無料(ptr);
予防:
a. free を使用する場合にインクルードする必要があるヘッダー ファイルも次のとおりです。<stdlib.h> 、 忘れないで。
b. free 関数は 1 回のみ実行でき、同じメモリアドレスを繰り返し解放したり、解放したポインタを再度使用したりすることはできません。
c. 最初に malloc と free をペアで記述し、忘れないように途中に他のコードを挿入することをお勧めします。
3、再割り当て()
re、もう一度という意味、alloc 割り当ての略語、together はメモリの再割り当てを意味します
機能: 割り当てられたメモリ ブロックのサイズを変更します (増加または減少)。
パラメータ:パラメータ1、元のメモリブロックポインタ、パラメータ2、増減後のメモリブロックサイズ(静止サイズt型)
戻り値:void*ポインタ(独自のポインタ型変数で受け取れます)
使用法: void* newPtr=realloc(ptr,sizeof(int)*10);
予防:
a. realloc 関数を使用する場合は、それも含める必要があります。<stdlib.h> 。
b. 元のポインタが指すメモリ ブロックは新しいポインタに置き換えられているため、プログラムの終了時に解放されるべきは新しいポインタであり、元のポインタを解放する必要はありません。解放しないと操作エラーが発生します。起こる。
c. realloc はメモリの割り当てに失敗し、失敗すると NULL を返す可能性があるため、これに対処するための if ステートメントを追加することをお勧めします。
4. 応用例

  1. #include<stdio.h>
  2. #include<stdlib.h> //malloc、free、realloc
  3. #include<string.h> //memset
  4. int main(void)
  5. {
  6. //A void指针的使用
  7. float PI = 3.14159;
  8. void* pPI = &PI;
  9. float r = 2.5;
  10. printf("半径2.5圆的面积:%fn", r * r * *(float*)pPI);//*(float*)pPI—pPI强转为float指针后再解出指向的值
  11. //B malloc、memset、free函数使用
  12. int n = 8;
  13. void* pMyMem = malloc(sizeof(char)*n); //char占1字节,malloc分派n字节的内存,返给void指针
  14. if (pMyMem == NULL)return 0; //若分派内存失败,程序结束
  15. void* myMem2=memset(pMyMem,'B',sizeof(char)*8); //对malloc分派的内存区块个字节都写入字符'B'。
  16. //并用myMem2接收返回的指针
  17. if (pMyMem == myMem2)printf("memset写入区块指针与其返回的指针相同n");
  18. char* transCh = pMyMem; //将void指针转成char型指针
  19. printf("显示写入内容:");
  20. for (int i = 0; i < n; i++)
  21. {
  22. printf("%c ", *transCh); //显示写入的字符
  23. transCh++;
  24. }
  25. printf("n");//换行
  26. free(pMyMem); //释放malloc函数分派的内存
  27. //free(ch); //只有malloc分派的内存才需要释放,且只释放一次(这里会报错)
  28. //C realloc、free函数的使用
  29. int* pMem = malloc(sizeof(int)*5);
  30. if (pMem == NULL)return 0;
  31. for (int i = 0; i < 5; i++) pMem[i] = (i+1)*10;
  32. for (int i = 0; i < 5; i++) printf("%i ", pMem[i]);
  33. printf("n重新增加分派内存后n");
  34. int* newpMem = realloc(pMem, sizeof(int) * 10);
  35. if (newpMem == NULL)return 0;
  36. for (int i = 0; i < 10; i++) newpMem[i] = (i + 1) * 10;
  37. for (int i = 0; i < 10; i++)printf("%i ", newpMem[i]);
  38. free(newpMem); //释放realloc的内存
  39. //free(pMem);//pMem已被重置,不能再释放,此语句会造成运行失败
  40. getchar(); //暂停屏幕
  41. return 0;
  42. }