第52章 realloc()

 あまり良いアイデアとは思えませんが、配列の長さを変えたいという時もあるでしょう。

 realloc() は一度割り当て済みのヒープ領域のサイズを変更してくれる関数です。

#include <stdlib.h>
void *realloc(void *ptr, size_t size);

 ptr は元になるヒープ領域のアドレスとなり、size は新たなサイズです。

 realloc() は調整後のヒープ領域のアドレスを指す void ポインターを返します。

 だとすると ptr ってどうなっちゃうの?

 てな疑問が出てくるでしょうが、これはコードを見ながら検証するほうが早いので、早速のサンプルコードです。

main.c. 

  1 #include <stdlib.h>
  2 #include <stdio.h>
  3
  4 int main()
  5 {
  6   int *old_ptr;
  7   int *new_ptr;
  8   int i;
  9
 10   old_ptr = malloc(sizeof(int)*3);
 11   for(i = 0; i < 3; i++)
 12     old_ptr[i] = i;
 13   new_ptr = realloc(old_ptr,sizeof(int)*4);
 14   *(new_ptr+3) = 3;
 15   for(i = 0; i < 4; i++)
 16     printf("%d\n",new_ptr[i]);
 17   free(new_ptr);
 18   return 0;
 19 }

ビルドと実行結果. 

$ gcc main.c
$ ./a.out
0
1
2
3

 このコードがやってるのは要素 3 個の整数型配列を、要素 4 個の整数型配列に調整しているところです。

 10   old_ptr = malloc(sizeof(int)*3);
 11   for(i = 0; i < 3; i++)
 12     old_ptr[i] = i;

 old_ptr は要素 3 個の配列で (0,1,2) の値が代入されます。

 13   new_ptr = realloc(old_ptr,sizeof(int)*4);
 14   *(new_ptr+3) = 3;

 new_ptr には realloc() によってアドレスが整数型 4 個分に変更されます。

 値が (0,1,2,3) の順序配列となります

 15   for(i = 0; i < 4; i++)
 16     printf("%d\n",new_ptr[i]);
 17   free(new_ptr);

 最後に新たに割り当てた new_ptr の中身をチェックしてから free() で解放します。

 ちなみに old_ptr は解放済みと考えるようにしてください。

 つまり free(old_ptr) は既に行われたと考えてください。

 次のコードでは realloc() のメモリー管理の理解を少し深めるために realloc() で元のポインターのアドレスがどうなるかのチェックしています。

main.c. 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int main()
  5 {
  6   int *old_foo;
  7   int *new_foo;
  8   int *ptr;
  9
 10   old_foo = malloc(sizeof(int)*2);
 11   printf("old_foo: 0x%lx\n",(unsigned long)old_foo);
 12   new_foo = realloc(old_foo,sizeof(int)*100);
 13   printf("new_foo: 0x%lx\n",(unsigned long)new_foo);
 14   ptr = malloc(sizeof(int));
 15   printf("ptr:     0x%lx\n",(unsigned long)ptr);
 16   free(new_foo);
 17   free(ptr);
 18
 19   return 0;
 20 }

ビルドと実行結果. 

$ gcc main.c
$ ./a.out
old_foo: 0x55db9b550260
new_foo: 0x55db9b550690
ptr:     0x55db9b550260

 このコードは 2 個の要素を保持する整数型の配列を 100 個の要素に拡張しています。

 10   old_foo = malloc(sizeof(int)*2);
 11   printf("old_foo: 0x%lx\n",(unsigned long)old_foo);

 old_foo は元の配列ですね。

 「 0x55db9b550260 」が old_foo のアドレスになります。

 12   new_foo = realloc(old_foo,sizeof(int)*100);
 13   printf("new_foo: 0x%lx\n",(unsigned long)new_foo);

 old_foo を realloc() で拡張したものを new_foo に代入します。

 new_foo のアドレスは「 0x55db9b550690 」となるので、old_foo とは異なる新たな領域に new_foo が割り当てられたことがわかります。

 14   ptr = malloc(sizeof(int));
 15   printf("ptr:     0x%lx\n",(unsigned long)ptr);

 最後に ptr という新たな整数を malloc() でヒープ領域に確保します。

 アドレスは「 0x55db9b550260 」となりますが、このアドレスは old_foo で使用済みのアドレスとなります。

 つまり realloc で不要となった古いアドレスは再利用されているということですね。

Copyright 2018-2019, by Masaki Komatsu