malloc の使い方(malloc/free/memset)


この難しいテーマを自分はうまく説明できるだろうか。

C 言語を使うには

以下のいずれかの環境があれば試すことができる。

  • mac に xcode をインストールしている。
  • windows に cygwin(およびgcc) をインストールしている。
  • Linux か FreeBSD をインストールして、Cコンパイラをインストールしている。

malloc とは

malloc は標準で用意されているライブラリだ。
メモリの確保(解放)を行う。

コマンドラインから man malloc と打つと使い方が表示される。Mac の場合次のような感じで表示される。

NAME
calloc, free, malloc, realloc, reallocf, valloc -- memory allocation

使い方

ポインタ = malloc(バイト数);

とコールすると、バイト数分のメモリが確保され、確保したメモリへのポインタが返る。

確保したメモリは、

free(ポインタ);

をコールするまで解放されない。

確保したメモリは初期化されないので、通常は、

memset(ポインタ, 0, バイト数);

のようにして 0 で初期化する。(string.h の include が必要)
文字列の終端が \0(=0) だったり、NULL ポインタ(=0) が
データの末尾を表していることが多いため、0 で初期化することが
多いだろう。

指定した数のデータ

実行時に毎回データ数が変わるような場合、malloc でデータ数分のメモリを確保することになるだろう。

int の場合

int n = 100;

int *intp = (int*)malloc(sizeof(int) * n); // int 100個分のデータ領域
memset(intp, 0, sizeof(int) * n);

*(intp + 10) = 123;
intp[10] = 123; // 上と同じ。こちらのほうがわかりやすいと思う。

// コンパイルエラーにはならないが、C 言語では何もチェックしないので
// 異常な動作になる。
*(intp + 1000) = 123;
intp[1000] = 123;

char の場合

int n = 100;

char *strp = (char*)malloc(n); // 100文字分のデータ領域
memset(strp, 0, n);

// example 1
strcpy(strp, "hogehoge");

// example 2
*(strp + 30) = 'a';
strp[30] = 'a'; // 上と同じ

// C 言語では確保したメモリを越えようがコピーするので、
// 異常な動作になる。
strcpy(strp, 100文字を超える文字列へのポインタ);

いわゆるリスト

C 言語でリスト(追加削除のできるデータ構造)を扱おうとするとmalloc を使ってリスト構造を作る必要があるだろう。

typedef struct node_st {
int v;
struct node_st *next;
} node_t;

と宣言されているとして、node_t を一つ分確保する場合。

node_t *nodep = (node_t*)malloc(sizeof(node_t));
memset(nodep, 0, sizeof(node_t));
nodep->v = 123;
nodep->next = NULL; // いちおう初期化

prev_nodep = 前の要素を検索するルーチン();
prev_nodep->next = nodep;
nodep->next = NULL;

ちなみにリストを扱う場合は、man queue にあるようなマクロを使うことができる。

以下のようなリストがある。

  • 単方向リスト SLIST
  • 単方向TAILIQ STAILQ
  • 双方向リスト LIST
  • 双方向TAILQ TAILQ

TAILQ は末尾の要素へのアクセスが速い。
単方向は先頭から末尾へのアクセスのみで、双方向はあるノードの前後のノードへのアクセスができる。
という違いがある。(双方向のほうがデータサイズは大きくなる)