Calloc
[Wikipedia|▼Menu]

malloc(マロック, エムアロック)、calloc、reallocは、動的メモリ確保を行うC言語標準ライブラリ関数である[1][2][3]。確保したメモリの解放にはfree関数を使用する。

mallocが使用する実際のメモリ確保機構には様々な実装がある。それらの性能は、実行時間と要求されるメモリの両面で様々である。
原理詳細は「動的メモリ確保」を参照

C言語は通常メモリを「静的メモリ確保」か「自動メモリ確保」で管理する。静的変数は主記憶上にプログラムが存在する期間中ずっと確保されている。自動変数(局所変数)は通常コールスタック上に確保され、対応するサブルーチンが実行中の間だけ存在する。しかし、いずれの方法も限界があり、確保できるメモリ量(変数のサイズ)はコンパイル時に決められてしまう。必要なサイズが実行時でないと判明しない場合、例えばディスク上のファイルから任意のサイズのデータを読み込むような場合、固定サイズのデータオブジェクトだけでは不十分である。

確保されたメモリの生存期間(使用可能期間)も問題となる。静的でも自動的でも確保されたメモリの生存期間はあらゆる状況に対応できるものではない。スタック上のデータは複数の関数呼出をまたいで持続できないし、静的データは必要かどうかにかかわらずプログラムが動作中ずっとメモリ領域を確保し続ける。しかし、そうではなく確保したメモリの生存期間をプログラマが自由に制御できる必要がある場合も多い。

これらの制限は動的メモリ確保を使用することで解決する。メモリの管理は明示的に行う必要が出てくるが、柔軟性が向上する。「ヒープ領域」はこのために用意されたメモリ領域である。C言語では、malloc関数を使ってヒープ領域からメモリブロックを確保する。プログラムはmallocの戻り値であるポインタを使って、そのメモリブロックにアクセスする。メモリブロックが不要になったら、そのポインタをfreeに渡して解放し、他の用途に再利用できるようにする。

ヒープではなくCのスタックフレームから実行時に動的にメモリを確保するライブラリルーチンもある[注釈 1]。このように確保したメモリは呼び出した関数から抜ける時点で自動的に解放される。ただし、スタックオーバーフローに注意する必要がある。GCC言語拡張の可変長配列C99標準でサポートされ[8]、実行時に大きさを決定でき任意の静的スコープの範囲で存在するメモリ確保法が言語構文に組み込まれたが、C11ではサポート必須ではなくオプションに格下げとなった。
C言語での動的メモリアロケーション

mallocはC言語におけるヒープ領域からのメモリ確保に使われる基本関数である。その関数プロトタイプはstdlib.hヘッダに次のように定義されている[1]。void *malloc(size_t size)

ここで、sizeバイトのメモリが確保される。確保が成功するとそのメモリブロックへのポインタが返される。

ANSI Cにおいてmallocが返すのは、void型へのポインタ (void *) であり、そのポインタが指す領域のデータ型が不明であることを示している。C言語では汎用ポインタvoid *と任意の型TへのポインタT *との間の型変換 (キャスト) は暗黙的に実行されるため、mallocの戻り値は特に明示的な型変換を記述せずとも任意の型へのポインタ変数にそのまま代入できる。しかし、明示的に型変換を記述する必要が無いにもかかわらず、あえて意図的に型変換を記述することもある。明示的に型変換を記述する目的は、かつてANSI以前の仕様のC(K&R C)においては、void *が存在せず、mallocはchar *を返していたからである[9][10]。また、C言語よりも厳密な型システムを持つC++では、T *からvoid *への型変換は暗黙的に行なわれるものの、void *からT *への型変換は暗黙的に行なわれないため、C/C++両方でコンパイルすることのできるソースコードを書く際には型変換の記述が必要となる。int *ptr = (int *)malloc(sizeof(int) * 10);

しかし、stdlib.hをインクルードし忘れた場合(malloc関数の前方宣言がない場合)、C99よりも前のバージョンのCコンパイラはmallocがint型を返す関数であるとみなす。mallocの戻り値を明示的に型変換していると、ヘッダーをインクルードし忘れたことに気づかない。一方、明示的に型変換していないと、コンパイル時にintをポインタ型変数に代入しようとしているとして何らかの警告あるいはエラーメッセージがコンパイラから表示されることでインクルード忘れに気づける可能性がある[11][9][12]。例えば64ビットのシステムでLP64というデータモデルを採用している場合、longとポインタは64ビットだが、intは32ビットとなる。この場合stdlib.hのインクルード忘れに気づかないと、mallocが実際には64ビットのポインタを返すのに、32ビットの値を返すと暗に宣言したことになり、バグが生じる可能性がある。ただし、多くのコンパイラは宣言のない関数を使用していると(キャストの有無にかかわらず)コンパイル時に警告を出す。C99以降では前方宣言のない関数の戻り値をintとみなさなくなったため、コンパイルエラーとなる。

C99およびC++03まではスレッドの概念が標準化されていなかったため、スレッドセーフ性に関しては何も言及がなかったが、C11およびC++11以降はスレッドセーフであることが規定されるようになった[13][14][15][16]
メモリの解放

mallocで確保されたメモリは持続性がある。プログラム終了時か明示的にプログラマが解放しない限り存在し続ける。解放はfree関数で行われる。そのプロトタイプは次のようになる。void free(void *pointer)

ここで、pointerの指すメモリブロックが解放される。
関連する関数

mallocはメモリブロックを確保して返すが、その領域は初期化されていない。必要に応じてメモリは個別に初期化する。例えば、memset関数で初期化したり、個別の代入文で初期化したりする。他にもcalloc(カロック、シーアロック)関数を使って、メモリ確保と初期化を行うこともできる。そのプロトタイプは以下のようになる。void *calloc(size_t nelements, size_t bytes)

bytesのサイズのメモリ領域をnelements個格納できるメモリ領域を確保する。確保された領域はゼロで初期化される。

メモリブロックを大きくしたり小さくしたりできれば便利である。これはmallocとfreeを組み合わせて、新たなメモリブロックを確保して内容を前のメモリブロックからコピーし、前のメモリブロックを解放することで実現できる。しかし、この方法は回りくどい。代わりにrealloc(リアロック)関数を使うことができる。そのプロトタイプは以下の通りである。void *realloc(void *pointer, size_t bytes)

reallocは指定されたサイズのメモリ領域へのポインタを返す。新しいサイズが前のサイズより大きければブロックは大きくされ、逆ならば小さくされる。

vallocはmallocとほとんど同じだが、メモリ確保がページ境界になる点が異なる。vallocで確保された領域へのポインタをreallocに渡すことはできない[1]。また、これは標準Cライブラリに含まれる関数ではない。
使用例

スタック上に10個の整数の配列を作成する一般的な方法は次の通りである。int array[10];

同様の配列を動的に確保するには、以下のようにmallocを使う。#include <stdlib.h>/* 10個のintの配列のためのメモリを確保 */int *ptr = malloc(sizeof(int) * 10);if (NULL == ptr) { exit(EXIT_FAILURE); /* メモリを確保できなかったので終了 */} else { /* 確保成功 */ /* ここでその配列を使った処理を行う */ /* 処理が完了し、使わなくなったメモリブロックを解放する */ free(ptr); /* 解放したメモリにアクセスしてはならないことを示すため、NULLを代入しておく */ ptr = NULL; }
一般的なエラー

mallocおよび関連するC言語の関数の使用は、以下のような理由でバグの発生源になりやすい。
確保エラー

mallocは必ず成功するとは限らない。利用可能な空きメモリ領域がないとき、プログラムが限界値を超えてメモリを使用しようとしたときなど、mallocはヌルポインタを返す。環境によって、このような状況の起きる可能性は異なる。もしmallocが失敗することを考慮していないプログラムで、mallocがヌルポインタを返してきたとき、プログラムはNULLに相当するアドレスにアクセスしてクラッシュするだろう。メモリ確保失敗をチェックすることは、ライブラリでは特に重要である。ライブラリはメモリ量が限られた状況でも使用される可能性がある。ライブラリ内でメモリ確保に失敗した場合、呼び出したアプリケーション側にエラーを通知して、アプリケーションプログラムに判断を委ねるのがよいとされる。

プロトタイピング目的で書かれたコードなどでは、メモリ確保失敗をチェックしないこともある。というのもメモリ確保に失敗するという状況は、画像処理などを除いた一般的な用途では珍しく、発生した場合には終了する以外にプログラミング上できることがないからでもある。ごく少量のメモリさえ確保に失敗するような状況では、メモリ確保失敗に対処したとしてもプログラムを正常に続行できる見込みがない。一方で、ライブラリ製品やアプリケーション製品では異常系すなわち例外処理への対処は重要であり、メモリ確保失敗への対処も例外ではない。
メモリリーク

mallocで確保したメモリブロックを使用しなくなってもfreeで解放せず、次々と新たなメモリブロックを確保していると空きメモリが少なくなってくる。これをメモリリークと呼ぶ。メモリリークによるメモリ消費が無視できない量に達するとページ置換アルゴリズムによってページアウトが発生し、システム性能が低下する。さらに仮想記憶の容量限界に達すると、システム内の他の全プロセスでメモリ確保が失敗してシステムがストールする。メモリリークは、利用のたびにプロセスの起動・終了が行われるプログラムにおいて、特に重要な問題を引き起こさないため、メモリリークが混入した状態で出荷される商用プログラムは多い。しかしながら、連続稼動が要求されるサーバコンピュータ上のプログラム(サービスデーモン)や、組み込みプログラム等の場合は、メモリリークは死活問題とされる。
解放後の使用

ポインタがfree関数に渡され、メモリが解放された後でその領域への参照を行っても、その内容は未定義であり利用できない。しかし、ポインタ自体が残っていると誤って使ってしまうことがある。次のコードはその例である。int *ptr = malloc(sizeof(*ptr)); /* メモリ領域を動的確保 */...free(ptr);/* ptr は解放済みの領域をまだ指したまま */*ptr = 0; /* 何が起きるかわからない! */


次ページ
記事の検索
おまかせリスト
▼オプションを表示
ブックマーク登録
mixiチェック!
Twitterに投稿
オプション/リンク一覧
話題のニュース
列車運行情報
暇つぶしWikipedia

Size:41 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)
担当:undef