• ベストアンサー

free()について

free()について int *x; x = malloc(4*3); *x = 1; *(x+1) = 10; *(x+2) = 100; free(x); としたとき free(x)ではどうして確保した分のメモリを開放できるのですか? 引数xから最初の4バイト分はわかりますが、ぴったり確保した分を開放できるのが理解できません

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

malloc(4*3)というのは、4×3=12バイトのメモリブロックを確保し、その先頭場所を返すというものです。決して「4バイトを3つ」ではありません。で、xは、上記の「先頭場所」に対してラベルを貼るイメージです。 *(x+1) = 10; にて、「xというラベルが指し示している場所から4バイト(int 1個分)後ろの場所にintで10という値を設定する」という処理をしたとしても、xがメモリブロックの先頭を指している事には変わりません。 *(x+2) = 100; も同様です。 上の2つを、 *x++ = 10; *x++ = 100; などとしてはいけません。x(というラベルが指し示す場所)自体が変化してしまうからです。 xがmallocで確保したメモリブロックの先頭位置をずっと指し示しているから、free(x)でそのメモリブロックを開放できるのです。freeはintを開放するのではなく、あくまでmallocでガスっと一括確保された12バイトのメモリブロックを開放する事を理解してください。

cern5100
質問者

お礼

回答ありがとうございます。 mallocで確保していることを覚えていてそれを開放するんですね。 引数のxの情報から全て判断しているのかと思ってました。 イメージがわきました。

その他の回答 (5)

  • orfenok
  • ベストアンサー率0% (0/1)
回答No.6

僭越ながら実装レベルで回答させて頂きます。 アドレスとサイズのペアを内部でテーブルとして持っているからだと思います。 C言語で実装してみると、容易に実現できると思います。 // memory.cpp typedef struct { char* pAddress; // mallocで返すアドレス size_t uSize;  // mallocで指定されたサイズ } MEM; static MEM s_table[SIZE_MAX]; // メモリ管理テーブル static int s_num; // テーブルの要素数 void* malloc( size_t uSize ) {  void* pAddress = 空いているヒープを探す();  // 管理テーブルに記録  s_table[ s_num ] = pAddress;  s_table[ s_num ] = uSize;  s_num++;  return pAddress; } void free( void* pAddress ) {  int i;  for ( i=0; i < s_num; i++ ) {   // テーブルと一致するアドレスを探す   if ( pAddress == s_table[i].pAddress ) {    size_t uSize = s_table[i].uSize; // ★これが開放すべきサイズ★    ヒープ開放();    break:   }  } } ※実際にはテーブルは配列ではなく双方向リストなどで実装し、開放の際前後の空き領域とマージして断片化を考慮していると思います。

cern5100
質問者

お礼

回答ありがとうございます。 難しくて理解するのが大変ですが考えてみます。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.5

malloc時に確保した領域の「先頭アドレス」と「確保量」のデータを何かしらの手段(OSによって異なる)で持っているためです。 なので、free()には「先頭アドレス」を正しく渡さなければいけません。 また、freeが利用するのは先頭アドレスだけで型情報は使っていない、というのは既出の通りです。

cern5100
質問者

お礼

回答ありがとうございます。 そこのところを大きく誤解していました。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

> 引数xから最初の4バイト分はわかります xがint *だから、int分の4バイト分、と考えたのでしょうが、freeの引数はvoid *型です。解放したい領域のポインタ(≒先頭アドレス)を受け取るだけです。 C++だと、引数の型によって処理を分ける機能がありますが、Cにはありません。 そのポインタが何型へのポインタ(int *なのか、char *なのか、double *なのか)はわかりません。 したがって > 引数xから最初の4バイト分はわかります というのは「誤解」です。 ついでに言うと、intが4バイトというのも環境依存です。2バイトだったり8バイトだったりするかもしれません。 mallocに「4」と決めつけて使うのではなく、sizeofを使いましょう。

cern5100
質問者

お礼

回答ありがとうございます。 誤解していました。 ポインタの中身はint *もchar *もまったく同じなんですか? それで引数として渡されてしまったあとはもう単なるアドレスだけしかわからなくなって しまうのですか?

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.3

>引数xから最初の4バイト分はわかります わかる理由は何ですか? >ぴったり確保した分を開放できるのが理解できません 理解できない理由がわかりません。

cern5100
質問者

お礼

回答ありがとうございます。 >>引数xから最初の4バイト分はわかります > わかる理由は何ですか? ポインタにもint 型のポインタなど型があるので そこで開発環境orコンパイラorなんらかのシステム?が判断して 先頭のバイトのアドレスさえわかれば4バイト分把握できると勝手に思い込んでいたのですが その解釈は間違ってましたか? 良かったらそこのあたりも教えていただけたらと思います。 つまり int a; int *p; p = &a; としたときどうして*pによってaの値を参照できるかということなど >>ぴったり確保した分を開放できるのが理解できません >理解できない理由がわかりません。 確保した領域の先頭アドレス”だけ”から何バイト確保したかなぜわかるのかが わかりませんでした。

cern5100
質問者

補足

すみません誤解してたようです。 下から読んでいたので次の回答読んでませんでした。

回答No.2

システムの管理上は、 (1)malloc(4*3)で確保された領域に関する情報を別途持っている。 (2)malloc(4*3)で確保された領域の-4バイトのところにサイズ情報を持っている。 等が考えられます。 おそらく(1)がシステム的には一般的です。 この情報から解放された領域(アドレス、サイズ、属性等)をもっと大きな(ユーザ空間の)管理エリアに戻すことになると考えられます。 要するにできる仕組みが組み込まれているのです。

cern5100
質問者

お礼

回答ありがとうございます。 まだ詳しくは理解できませんが、一番わからなかったところと だいたいの管理イメージは理解わかりました。 自分のイメージでは引数に重みを置きすぎていました。

関連するQ&A