読者です 読者をやめる 読者になる 読者になる

ichirin2501's diary

いっちりーん。

realloc関数怖い

最近は完全に引篭もり状態です。
フリーターになったときの生活費を考えたり云々。


以前、大学の課題でrealloc関数を使った時に悲惨なバグに遭遇してから
「 realloc関数こええ、使わないほうがいい 」なんて思った。
以下検証コード

#include<stdio.h>
#include<stdlib.h>
#define N 3
main()
{
   int i,j;
   int *k;
   int *a;
   
   k = (int*)malloc( sizeof(int)*N );
   a = (int*)malloc( sizeof(int)*N );

   for(i=0; i<N; i++){
      k[i] = i;
      printf("&k[%d]:%p , k[%d]=%d\n",i,&k[i],i,k[i]);
   }
   for(i=0; i<N; i++)
      printf("&a[%d]:%p\n",i,&a[i]);
      
   int *tmp = (int*)realloc(k,(N+1)*sizeof(int));
   if( tmp!=NULL ){
      k = tmp;
      puts("________realloc(k)_________");
      for(i=0; i<N+1; i++){
         printf("&k[%d]:%p , k[%d]=%d\n",i,&k[i],i,k[i]);
      }
   }
   free(k);
   free(a);
   return 0;
}



実行結果


&k[0]:0xd90190 , k[0]=0
&k[1]:0xd90194 , k[1]=1
&k[2]:0xd90198 , k[2]=2
&a[0]:0xd901a0
&a[1]:0xd901a4
&a[2]:0xd901a8
________realloc(k)_________
&k[0]:0xda01b8 , k[0]=0
&k[1]:0xda01bc , k[1]=1
&k[2]:0xda01c0 , k[2]=2
&k[3]:0xda01c4 , k[3]=0


kのアドレスを見て欲しい。
realloc関数は第一引数で渡したポインタのアドレス位置から拡張できない場合は新しい場所にメモリ確保を行う。
結果として、内容は保持されるがアドレスが変わる場合がある。
reallocで拡張される配列に対してポインタ処理を行うプログラムはすごく危険です。
アドレスが変わる再確保を何度もすると、メモリ空間に隙間がたくさん出来る?
具体的にどのような影響が出るか分からないけど、メモリ足りねーよって言われるのかな。
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/malloc.3.htmlによると、
拡張された場所は初期化が保証されてない。
試しに、大量にreallocで拡張してみたが、0で初期化されてた…。


・ポインタのアドレス位置から拡張できる     --> そのポインタが返る
・ポインタのアドレス位置から拡張できない  --> 新しく確保されたポインタが返り、第一引数のポインタはfreeされる
・メモリの再確保ができない                     --> NULLが返る、第一引数のポインタに対して何も処理されない


NULLが返ってきた場合を考えます。
k = (int*)realloc( k, sizeof(int)*N );
みたいな記述で、NULLが返ってきた場合は k が指すアドレス情報を失ってしまい、
mallocなどで動的確保された箇所に対してfreeを行うことができなくなるので注意が必要です。


ふぅ…。
ポインタとかアドレスとか、定義もろくに知らないのに書き殴ったので間違いが多々あるかもしれない。
realloc怖いお。