メモリの動的確保

メモリの動的確保


サイト全体の目次

稿


稿

(untitled)

(untitled)

データ数が増えてくると困るのが、メモリ管理です。例えば「複数のデータを扱うのに配列を用意したいが、使うたびにデータの個数が違う。」なんて時には、どんな時にも対応できるよう、限りなく大きな配列を用意しておくのも1つの手です。しかし、1000個分の配列を用意したのに実際のデータは10個しかなかった、なんて時には残り990個分はメモリの無駄遣いになってしまいます。そんな時に便利なのがこの章で紹介するメモリの動的確保です。

なお、今回使う「malloc」「free」関数は「stdlib.h」に定義されています。

動的確保

このセクションのソース

/*01*/ #include <stdio.h>
/*02*/ #include <stdlib.h>
/*03*/ 
/*04*/ main()
/*05*/ {
/*06*/   int *p;
/*07*/ 
/*08*/   p = (int *)malloc(sizeof(int));
/*09*/   printf("何か整数を入力してください。 -> ");
/*10*/   scanf("%d", p);
/*11*/   printf("その数の自乗は %d です。\n", (*p)*(*p));
/*12*/ 
/*13*/   free(p);
/*14*/   return 0;
/*15*/ }
/*16*/ 

list-7.3.1-06

まず、扱うデータの型のポインタを用意しておきます。

list-7.3.1-08

malloc関数は、引数に書かれた分のバイトを持つ領域を、メモリ上に確保します。そして、その領域のアドレスを戻り値として返してくるので、適当なポインタ変数に代入してやりましょう。しかしこの時、malloc 関数では、「どんな型」の領域かという事までは判断しませんので、ポインタの型に合わせて型キャストします。

ポインタ = (型キャスト)malloc(バイト数);
例:
p = (int *)malloc(4);
    /*型キャストの際、ポインタを示す「*」記号を忘れないで下さい*/

これでメモリ上には4バイト、すなわち int 型分の領域が確保され、p にはそのアドレスが入りました。しかし、「それぞれの型が何バイトかなんて知らない。」という場合もあるでしょう。そんな時に便利なのが上の例でも使われているsizeof演算子です。これは、指定された型や変数などのサイズをバイト数で返します。特に機種依存の int 型などでは有効でしょう。
sizeof(int);    /*「4」を返す*/
sizeof(x);    /*x が int 型の変数なら「4」を返す*/

また、メモリ不足などで充分な領域が確保できなかった場合、malloc 関数は「NULL」を返すので、これを使ってエラー時の処理を制御するといいでしょう。

if((p = (int *)malloc(sizeof(int))) == NULL){
    printf("メモリ確保に失敗しました。終了します。\n");
    return 0;
}

list-7.3.1-13

最後に、malloc 関数を使って自分で確保した領域は、自分で開放してやらなければなりません(必須:開放を忘れると、プログラム終了後もメモリが無駄に使われつづけます)。方法は、free 関数を使って、その引数にポインタを書いてやるだけです。しかし、この関数を書き忘れてもコンパイラはエラーを出してくれないので注意してください。また、自分で確保したもの以外(つまり普通に宣言された変数など)を、この関数を使って勝手に開放してしまうのはとんでもないエラーなので、しないで下さい。

変数を利用した確保

このセクションのソース

次の例は、最初にデータの個数を入力して、その分だけメモリを確保するものです。注意する点は1箇所だけです。

/*01*/ #include <stdio.h>
/*02*/ #include <stdlib.h>
/*03*/ 
/*04*/ main()
/*05*/ {
/*06*/   int *data, *s;
/*07*/   float ave = 0;
/*08*/   int i, n;
/*09*/ 
/*10*/   printf("平均を求めます。\n");
/*11*/   printf("何人分のデータを入力しますか? -> ");
/*12*/   scanf("%d", &n);
/*13*/   if((data = (int *)malloc(n*sizeof(int))) == NULL){
/*14*/     printf("メモリ確保に失敗しました。終了します。\n");
/*15*/     return 0;
/*16*/   }
/*17*/ 
/*18*/   s = data;
/*19*/   printf("得点を入力してください。\n");
/*20*/   for(i = 0; i < n; i++){
/*21*/     printf("%d 人目 -> ", i + 1);
/*22*/     scanf("%d", s);
/*23*/     s++;
/*24*/   }
/*25*/ 
/*26*/   s = data;
/*27*/   printf("入力されたデータは、\n");
/*28*/   for(i = 0; i < n; i++){
/*29*/     printf("%d 人目 -> %d\n", i + 1, *s);
/*30*/     ave += *s;
/*31*/     s++;
/*32*/   }
/*33*/   ave /= n;
/*34*/   printf("平均は %.2f です。\n", ave);
/*35*/ 
/*36*/   free(data);
/*37*/   return 0;
/*38*/ }

list-7.3.2-13

今回、malloc 関数で確保するバイト数は「(データの個数) * (型のサイズ)」です。この例で、入力されたデータの個数が5個ならば、「5*sizeof(int)」、すなわち32ビット環境であれば int は4バイトなので「20」バイトの領域がメモリ上に確保されます。そして、その領域は型キャストで int 型に直され、つまり int 型の領域 5個になって、その先頭アドレスがポインタ data に入ります。

後はこれまでどおりの操作ですね。(data は先頭アドレスを保持しておくため、実際にはポインタ s で操作します。)

構造体の例

このセクションのソース

では、構造体の場合はどうでしょうか?sizeof に構造体の型を書いてそのサイズを求め、その構造体に型キャストするだけです。特に難しい点はありませんので、今回は例となるソースを載せるだけとしておきます。

/*01*/ #include <stdio.h>
/*02*/ #include <stdlib.h>
/*03*/ 
/*04*/ struct score{
/*05*/   char name[32];
/*06*/   int math;
/*07*/   int english;
/*08*/   int kei;
/*09*/ };
/*10*/ 
/*11*/ main()
/*12*/ {
/*13*/   struct score *a, *p;
/*14*/   int i, n;
/*15*/ 
/*16*/   printf("何人分のデータを入力しますか? -> ");
/*17*/   scanf("%d", &n);
/*18*/   if((a = (struct score *)malloc(n*sizeof(struct score))) == NULL){
/*19*/     printf("メモリ確保に失敗しました。終了します。\n");
/*20*/     return 0;
/*21*/   }
/*22*/ 
/*23*/   p = a;
/*24*/   printf("名前 英語の点 数学の点 を入力してください。\n");
/*25*/   for(i = 0; i < n; i++){
/*26*/     scanf("%s%d%d", p->name, &p->math, &p->english);
/*27*/     p->kei = p->math + p->english;
/*28*/     p++;
/*29*/   }
/*30*/ 
/*31*/   p = a;
/*32*/   putchar('\n');
/*33*/   for(i = 0; i < n; i++){
/*34*/     printf("%s の合計点は %d です。\n", p->name, p->kei);
/*35*/     p++;
/*36*/   }
/*37*/ 
/*38*/   free(a);
/*39*/   return 0;
/*40*/ }

もちろん、struct score を typedef して使用してもかまいません。


読み込み中・・・
10秒待っても表示が変わらない場合、次の理由が考えられます。
・Javascript が無効になっています。
・検索エンジンのキャッシュを見ています。
サイトホームへ / 上位ページへ / ページトップへ / PAROFトレンドショッピングへ
Copyright (C) 2010 totobon all right reserved.