C言語編 目次

 関数設計

 

・関数名の命名規則
・プログラミングに出る!英単語

 ポインタ

 

・データ型とポインタ

 データ型

 

・char *とconst char *は違う
・符号付きと符号なし

 演算子

 

・三項演算子とデータ型の問題

 制御構文

 

・条件式で代入する
・三項演算子を使ったswitch

 構造体

 

・構造体のサイズとアライメント
・構造体メンバのサイズを知る

 配列

 

・配列使用時の注意
・配列の要素数を知る

 メモリ管理

 

・メモリスタック
・動的メモリ確保とメモリリーク

 モジュール設計

 

・モジュール分割
・汎用モジュールとアプリ依存モジュール

 パフォーマンス
  徹底チューニング

 


・どんな処理に時間がかかるのか
・ファイル入出力の効率化
・アルゴリズムを考える1
・アルゴリズムを考える2

 プリプロセッサの便利機能


・2重インクルード防止

 


トップページへ戻る

メモリスタック

 メモリスタックまたはスタックメモリという言葉を聞いたことはありますか?ある程度大きなプログラムを作る場合はこの辺の知識が必要になってきます。

 Cのプログラムでメモリを使う場合、大きく分けて、

・ローカル変数(Auto変数)
・グローバル変数
・動的に確保するメモリ領域(mallocなどで確保するメモリ)

の3種類があります。

 このうち、ローカル変数がスタックメモリに置かれます。ではスタックメモリとは何でしょうか。その前に関数について考えてみましょう。Cの関数は、呼び出されると、関数スタックというメモリ領域に関数ポインタが置かれます。関数が終了すると関数スタックから削除されます。

 Cのプログラムはmain関数から別の関数を呼んで、またその関数の中から別の関数を呼んで…というような流れでプログラムが実行されていきます。関数スタックというのは関数の呼び出し履歴みたいなものですね。

 たとえばAという関数からBという関数を呼んで、BからCという関数が呼ばれるとすると、関数スタックは、Aを追加 -> Bを追加 -> Cを追加 -> Cを削除 -> Bを削除 -> Aを削除という順番に処理が行われます。ここでひとつの特徴があることがわかりますか?最初に追加したものは最後に削除されて、最後に追加したものは最初に削除されるということです。このように「先入れ後出し(FILO)」のアルゴリズムのことを「スタック」と言います。

 さて、ローカル変数というのは、その関数が呼び出されると確保されて、関数が終了すると自動的に開放されます。これは関数スタックの追加/削除のタイミングと一緒なので、ローカル変数もまた、確保/開放のアルゴリズムがスタック構造になっています。

 では本題に入りましょう。このスタックメモリというものは通常、動的に確保するメモリに比べて非常にサイズが小さいです。固定サイズなので当然ですね。使わないのに何ギガもあったらメモリの無駄遣いですよね。VCでは、このサイズはデフォルトで1MBです。

 プログラムを書くときの基本方針として「スタックメモリの使用は必要最小限にする」ということを心がけましょう。ちなみにスタックオーバーフローすると、プログラムが強制終了します。

 たとえば、文字列用のバッファを次のように確保する人がよくいます。

int main(int argc, char *argv[])
{
    char    str[256];

    // メイン処理...

    return  0;
}

 これはあまりよくありません。Windowsならまだいいですが、メモリ量の少ないモバイル機器などではまずこのような確保の仕方はしないほうがいいでしょう。Windowsであっても、この関数が4000回、再帰処理で呼び出されるとスタックオーバーフローします。

 この場合は、動的に確保するかグローバル変数を使うようにします。(C++では動的な文字列クラスを使うようにしましょう)

 また、構造体をローカル変数にとる時は、構造体のサイズに注意しましょう。構造体1つで1MBもサイズがあったら、それだけでスタックを使い果たしますので^^;。