Cでのメモリ管理

こんにちは、将来のプログラミング魔術師たち!今日は、C言語におけるメモリ管理の fascinante な世界に飛び込みます。プログラミングの初心者であっても心配しないでください。私はこの旅をステップバイステップで案内します。これまでに多くの学生たちに教えてきたように。では、仮想の硬帽をかぶり、コンピュータメモリの建設現場を探検しましょう!

C - Memory Management

Cにおける動的メモリ管理の関数

メモリの高層ビルを建てる前に、使用するツールに慣れ親しんでみましょう。C言語には、メモリを動的に管理するための関数セットがあります。これらの関数はあなたの信頼のツールボックスのようなものです。

関数 目的
malloc() メモリのブロックを割り当て
calloc() 複数のメモリブロックを割り当ておよび初期化
realloc() 以前に割り当てられたメモリブロックのサイズを変更
free() 割り当てされたメモリをシステムに返却

これらの関数は、私たちのメモリビルの建設クルーのようなものです。それぞれが特別な仕事を持ち、私たちは彼らを深く理解します。

動的なメモリ割り当て

パーティを計画しているけれど、どれだけのゲストが来るか分からない場合、動的なメモリ割り当てが役立ちます!固定数の椅子を用意する代わりに、必要に応じて追加または削除できます。C言語でこれはどのように行うのでしょうか。

malloc()関数

私たちの最初のメモリ割り当てスーパーヒーローは malloc() です。これは「メモリ割り当て」を意味し、システムからメモリブロックをリクエストするために使用されます。

#include <stdio.h>
#include <stdlib.h>

int main() {
int *numbers;
int size = 5;

numbers = (int*)malloc(size * sizeof(int));

if (numbers == NULL) {
printf("メモリ割り当てに失敗しました!\n");
return 1;
}

for (int i = 0; i < size; i++) {
numbers[i] = i * 10;
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);
return 0;
}

これを分解すると:

  1. #include <stdlib.h>malloc() が存在する場所を指定します。
  2. numbers ポインタを宣言して、動的に割り当てられた配列を保存します。
  3. malloc(size * sizeof(int)) で5つの整数を保持する十分なメモリをリクエストします。
  4. 結果を (int*) にキャストします。なぜなら malloc() は void ポインタを返すからです。
  5. malloc() が成功したか確認します。もしない場合は、(とにかく) 不幸です。
  6. numbers を通常の配列のように使用できます。
  7. 使用が終わったら、忘れずに free() を実行します!

calloc()関数

次に、メモリ割り当ての「きれい好き」である calloc() に会いましょう。malloc() は以前にあったゴミをそのまま提供するのに対し、calloc() はすべての割り当てされたメモリをゼロに初期化します。

#include <stdio.h>
#include <stdlib.h>

int main() {
int *numbers;
int size = 5;

numbers = (int*)calloc(size, sizeof(int));

if (numbers == NULL) {
printf("メモリ割り当てに失敗しました!\n");
return 1;
}

for (int i = 0; i < size; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);
return 0;
}

ここでの主要な違い:

  1. calloc() は2つの引数を取ります:要素の数と各要素のサイズ。
  2. すべての要素はゼロに初期化されるため、出力はすべてゼロになります。

メモリのリサイズと解放

時々、私たちのパーティは予想以上に大きくなったり小さくなったりします。その場合に便利なのが realloc() です!

realloc()関数

realloc() は、私たちのメモリブロックを拡大または縮小できる魔术師のような存在です。

#include <stdio.h>
#include <stdlib.h>

int main() {
int *numbers;
int size = 5;

numbers = (int*)malloc(size * sizeof(int));

if (numbers == NULL) {
printf("メモリ割り当てに失敗しました!\n");
return 1;
}

for (int i = 0; i < size; i++) {
numbers[i] = i * 10;
printf("numbers[%d] = %d\n", i, numbers[i]);
}

// 配列を拡張しましょう
size = 10;
numbers = (int*)realloc(numbers, size * sizeof(int));

if (numbers == NULL) {
printf("メモリ再割り当てに失敗しました!\n");
return 1;
}

// 新しい要素を埋めます
for (int i = 5; i < size; i++) {
numbers[i] = i * 10;
}

// すべての要素を表示します
for (int i = 0; i < size; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);
return 0;
}

ここで何が起きているか:

  1. まず5つの要素で始めます。
  2. realloc() を使用して配列を10要素に拡張します。
  3. realloc() は元のデータを保持し、さらにスペースを提供します。
  4. 新しい要素を埋め、すべてを表示します。

free()関数

最後に、私たちのメモリ管理チームの清掃員である free() があります。割り当てたメモリを使用が終わったら、必ず free() を実行してください!

#include <stdio.h>
#include <stdlib.h>

int main() {
int *numbers = (int*)malloc(5 * sizeof(int));

if (numbers == NULL) {
printf("メモリ割り当てに失敗しました!\n");
return 1;
}

for (int i = 0; i < 5; i++) {
numbers[i] = i * 10;
printf("numbers[%d] = %d\n", i, numbers[i]);
}

free(numbers);  // 清掃!
numbers = NULL; // フリーメモリの使用を避けるための良き慣習

// 'numbers' を今使おうとするのは悪いアイデア!

return 0;
}

覚えておくこと:

  1. 割り当てたメモリを使用が終わったら必ず free() を実行します。
  2. フリーメモリの使用を避けるためにポインタを NULL に設定します。
  3. 自分で割り当てたメモリ以外を free() しないでください。

そして、ここまでで、私たちはメモリ管理の高層ビルを建て、パーティのゲストのためのスペースを確保し、必要に応じて再配置し、パーティが終わった後の清掃まで行いました。優れたメモリ管理は、良いホストであることと同じです。ゲストのための十分なスペースを確保し、アレンジを柔軟にし、パーティが終わった後はきちんと清掃します!

これらの概念を練習し続ければ、すぐにあなたはプログラムのメモリのマスター建筑师になれるでしょう。幸せなコーディングを、そしてメモリ漏れのないプログラムを!

Credits: Image by storyset