メモリの動的確保

malloc関数/calloc関数

プログラム実行時にメモリを確保する。

#include <stdlib.h>

void *malloc(size_t size);
void *calloc(size_t number, size_t size);

malloc関数は引数に指定したバイト数(size)のメモリ領域の確保を試み、 成功したらその先頭アドレスを返す。calloc関数はsizeバイト×number個 ぶんの領域確保を試みる。callocは確保された領域をゼロクリアする。 いずれもメモリ確保に失敗した場合は NULL が返される。

使用が終わったメモリ領域はfree関数で解放する。 解放し忘れと2重解放が起こらないように注意する。

1次元配列の場合:

calloc-1.c

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

int main(int argc, char *argv[])
{
  char buf[10];
  int *dim1, i, len;
  if (!argv[1] || 0 == (len=atoi(argv[1]))) {
    fprintf(stderr, "Usage: %s LENGTH\n(eg. %s 500)\n", argv[0], argv[0]);
    exit(0);
  }
  if (NULL  == (dim1=calloc(len, sizeof (int)))) {
    perror("memory ran out2\n");
    exit(1);
  }
  for (i=0; i<len; i++) {
    *(dim1+i) = i;
    printf("%d\r", dim1[i]);
  }
  puts("");
  if (NULL != dim1) {           /* 解放 */
    free(dim1); dim1 = NULL;
  }
}

2次元配列の場合:

calloc-2.c

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

void dispmatrix(int **m, int x, int y)
{
  int i, j;
  for (i=0; i<y; i++) {
    for (j=0; j<x; j++) {
      printf("%2d ", *(*(m+i)+j));
    }
    puts("");
  }
}

int main(int argc, char *argv[])
{
  int **dim2, i, j, row=0, column=0;
  if (NULL==argv[1] || 2>sscanf(argv[1], "%d%*[^0-9]%d", &column, &row)) {
    fprintf(stderr, "Usage: %s COLxROW\n(eg. %s 500x400)\n", argv[0], argv[0]);
    exit(0);
  }
  fprintf(stderr, "%d x row=%d\n", column, row);
  /* 行数分の int* ポインタを確保 */
  if (NULL == (dim2=(int**)calloc(row, sizeof (int*)))) {
    perror("Memory ran out(1)\n");
    exit(1);
  }
  for (i=0; i<row; i++) {
    /* すべての行に対して 列数分の int 領域を確保 */
    if (NULL  == (*(dim2+i)=(int*)calloc(column, sizeof (int)))) {
      perror("memory ran out2\n");
      exit(2);
    }
  }
  for (i=0; i<row; i++) {
    for (j=0; j<column; j++) {
      *(*(dim2+i)+j) = i+j;     /* dim2[i][j] でも可 */
    }
    puts("");
  }
  dispmatrix(dim2, column, row);
  for (i=0; i<row; i++) {
    if (NULL != *(dim2+i)) {    /* 必ず解放する */
      free(*(dim2+i));
      *(dim2+i) = NULL;         /* 解放したら必ずNULLにする */
    }
  }
  return 0;
}

realloc関数

mallocで既に割り当てられている連続領域の大きさを変える。 割り当てに失敗した場合はNULLが返る。既存のデータは(領域の大きさを 超えない範囲で)保存される。

ptrが既に割り当てられたポインタ、 sizeがその大きさを持っている変数だとすると、 以下のようにして使う。

newsize = size + 50;
if ((p2 = realloc(ptr, newsize)) == NULL) {
        if (ptr)
                free(ptr);
        ptr = NULL;
        return NULL;
}
ptr = p2;
size = newsize;

このように、割り当てが成功しなかったら元のアドレスをfreeしてエラーを 返し、成功した場合のみポインタと大きさを持つ変数を更新するよう注意する。

realloc関数の第1引数にNULLを指定すると、mallocと同じ働きをする。


目次