C言語入門講座。関数、サンプル集を参考にして、 C言語をマスターしよう。初心者から上級者まで。

メモリの動的割り当てと開放を行う

2012.08.10

calloc関数とmalloc関数は、メモリ領域を確保します。calloc関数で確保したメモリ領域は0(全ビットが0のバイト)で初期化されているのに対して、malloc関数で確保したメモリ領域は初期化されません。

realloc関数は、calloc関数または、malloc関数で確保したメモリ領域の大きさを変更します。領域を大きくした場合は、元の領域の内容は変更されません。

free関数は、上記関数で確保したメモリ領域を解放します。

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

nmembは確保する要素の大きさをバイト単位で指定します。
sizeは、calloc関数の場合は要素の数を、malloc関数とrealloc関数の場合は、確保するメモリ領域の大きさをバイト単位で指定します。
*ptrは、realloc関数の場合はサイズを変更する領域のポインタを、free関数の場合は解放する領域のポインタを指定します。

戻り値として、calloc関数、malloc関数、realloc関数の場合は、確保したメモリ領域のポインタが返ります。失敗した場合はNULLが返ります。free関数の戻り値はありません。

次の例題プログラムは、ファイルの内容を構造体配列に読み込みますが、構造体配列を動的に確保(malloc関数使用)しています。また、確保した領域が余った場合は、縮小(realloc関数使用)しています。

プログラム 例

#include <stdio.h>
#include <stdlib.h>

/* メンバーの最大人数 */
#define MEMBER_MAX 20
/* メンバーの個人情報 */
struct member {
  int      number;         /* 番号 */
  char     name[20];       /* 名前 */
  double   height;         /* 身長 */
  double   weight;         /* 体重 */
  double   jump;           /* 最高到達点 */
};
/* qsort関数のソートキー比較関数 */
int SortComp(const void *, const void *);

int main()
{
  FILE             *fp;
  struct member    *member_ptr;   /* member構造体の配列 */
  struct member    *list_ptr;     /* member構造体の要素 */
  int              list_max;      /* member構造体の使用要素数 */
  int              list_cnt;

  if ((fp = fopen('beijing_2008.csv', 'r')) == NULL) {
    fprintf(stderr, 'ファイルのオープンに失敗しました\n');
    abort();
  }

  /* メンバー情報を登録するmember構造体の配列を確保 */
  if ((member_ptr =
       malloc(sizeof(struct member) * MEMBER_MAX)) == NULL) {
    fprintf(stderr, 'メモリの確保に失敗しました\n');
    abort();
  }

  list_max = 0;
  list_ptr = member_ptr;
  /* メンバー情報入力 */
  while(fscanf(fp, '%d,%[^,],%lf,%lf,%lf',
      &list_ptr->number, list_ptr->name, &list_ptr->height,
      &list_ptr->weight, &list_ptr->jump) != EOF) {
    ++list_ptr;
    ++list_max;

    if (list_max >= MEMBER_MAX) {
      break;
    }
  }
  fclose(fp);

  /* member構造体の配列に未使用な領域があったら、縮小 */
  if (list_max < MEMBER_MAX) {
    if ((member_ptr =
        realloc(member_ptr, sizeof(struct member) * list_max)) == NULL) {
      fprintf(stderr, 'メモリの縮小に失敗しました\n');
      abort();
    }
  }

  /* member_listを名前をキーにしてソート */
  qsort(member_ptr, list_max, sizeof(struct member), SortComp);

  list_ptr = member_ptr;
  printf('番号 名前                   身長   体重  最高到達点\n');
  /* ソート後のメンバー情報出力 */
  for (list_cnt = 0; list_cnt < list_max; ++list_cnt, ++list_ptr) {
    printf('%3d  %-20s %6.1f %6.1f %6.1f\n',
      list_ptr->number, list_ptr->name, list_ptr->height,
      list_ptr->weight, list_ptr->jump);
  }

  /* member構造体の配列を開放 */
  free(member_ptr);

  return 0;
}

/* qsort関数のソートキー比較関数 */
int SortComp(const void *p1, const void *p2)
{
  struct member *cmp1 = (struct member *)p1;
  struct member *cmp2 = (struct member *)p2;

  return strcmp(cmp1->name, cmp2->name);
}

例の実行結果

$ cat beijing_2008.csv
1,kurihara,186,69,305
2,tajimi,180,70,309
3,takesita,159,52,280
4,oomura,184,70,319
5,takahasi,170,65,290
6,sano,159,54,260
7,sugiyama,184,66,310
8,sakurai,167,63,290
9,kanou,174,65,298
11,araki,186,79,307
12,kimura,184,66,298
14,kawai,168,63,280
$
$ ./mem_alloc.exe
番号 名前                   身長   体重  最高到達点
 11  araki                 186.0   79.0  307.0
  9  kanou                 174.0   65.0  298.0
 14  kawai                 168.0   63.0  280.0
 12  kimura                184.0   66.0  298.0
  1  kurihara              186.0   69.0  305.0
  4  oomura                184.0   70.0  319.0
  8  sakurai               167.0   63.0  290.0
  6  sano                  159.0   54.0  260.0
  7  sugiyama              184.0   66.0  310.0
  2  tajimi                180.0   70.0  309.0
  5  takahasi              170.0   65.0  290.0
  3  takesita              159.0   52.0  280.0
$

関連記事