確保領域の大きさを変更する

さて、動的にメモリを確保した後、その大きさを変更したい場合があります。この場合 realloc 関数を使います。
void *realloc(
              void *memblock,
              size_t size                                                                 
);
をインクルードする必要があります。
memblock は、すでに割当てられているメモリブロックへのポインタです。size には、新しいサイズをバイト単位で指定します。

ソースコード

源文件
  1|/* realloc01.c */
  2|
  3|#include <stdio.h>
  4|#include <string.h>
  5|#include <stdlib.h>
  6|                                                                                      
  7|int main(void)
  8|{
  9|  double *pd, *pd2, sum = 0;
 10|  int no = 0, i;
 11|  char szData[32];
 12|
 13|  pd = (double *)malloc(0);
 14|  if(pd == NULL){
 15|    perror("領域確保に失敗\n");
 16|    exit(-1);
 17|  }
 18|  while(1){
 19|    printf("数値を入力してきださい。(Eで終了):");
 20|    scanf("%s", szData);
 21|    if(strcmp(szData, "E") == 0 || 
 22|       strcmp(szData, "e") == 0){
 23|        printf("入力を終了します\n");
 24|        break;
 25|      }                                                                               
 26|    pd2 = (double *)realloc(pd, sizeof(double) * (no + 1));
 27|    if(pd2 == NULL){
 28|      perror("領域のサイズ変更に失敗しました\n");
 29|      free(pd); /* すでに確保してあるメモリを解放 */
 30|      exit(-2);
 31|    }
 32|    pd = pd2;
 33|    pd[no] = atof(szData);
 34|    sum += pd[no];
 35|    no++;
 36|  }
 37|  if(no){
 38|    for(i = 0; i < no; i++){
 39|      printf("[No.%d] %f\n", i + 1, pd[i]);
 40|    }
 41|    printf("合計\t%f\n", sum);
 42|    printf("平均\t%f\n", sum / no);
 43|  }
 44|  free(pd);
 45|  return 0;                                                                           
 46|}

実行結果

数値を入力してきださい。(Eで終了):3
数値を入力してきださい。(Eで終了):5
数値を入力してきださい。(Eで終了):12
数値を入力してきださい。(Eで終了):8
数値を入力してきださい。(Eで終了):e
入力を終了します
[No.1] 3.000000
[No.2] 5.000000
[No.3] 12.000000
[No.4] 8.000000
合計28.000000
平均7.000000


最初に malloc 関数で0バイトの領域を確保しておきます。失敗したら標準エラーにその旨表示して exit しています(「malloc(0)」が NULL を返す処理系では「malloc(1)」としてください)。

exit 関数

void exit(
          int status                                                                      
);
exit 関数は、プログラムを正常に終了させます。プログラム終了時に status がシステムに返されます。このとき、開いているファイルがあれば自動的に閉じられます。確保している領域も自動的に解放されます。

次に、whileループの中身をのぞいてみましょう。「数値を入力してください」と表示したあと、scanf 関数でユーザーの入力した文字列を取得しています。文字列が "E" または "e" であれば、break 文で while ループを抜けます。それ以外の場合は数値入力と考えて、realloc 関数で確保領域のサイズを変更します。realloc 関数が失敗したら exit するので、

pd = (double *)realloc(...);

としてもよいのですが、ここではあえて別のポインタを使用しています。というのも、万一 realloc 関数が失敗しあたら pd に NULL が入ってしまいます。そうすると、すでに確保ある領域に対して free 関数が無効になってしまうからです。

realloc 関数が成功したら「pd = pd2;」としていいます。そして、確保した領域に入力された文字列を数値に変換して代入します。「sum += pd[no];」で合計値も計算しています。これらの作業が終わったら no を1増やしてループの最初に戻ります。その後メモリ解放してプログラムを終了します。

Chapter10 @ C言語目録 @ HomeWork List @ 昭亮's Homepage