C 言語で malloc を使った構造体メモリの割り当て

胡金庫 2023年10月12日
  1. mallocsizeof 演算子を用いて C 言語で構造体メモリを割り当てる
  2. for ループを使って構造体の配列にメモリを割り当てる
C 言語で malloc を使った構造体メモリの割り当て

この記事では、C 言語で malloc を使って構造体メモリを割り当てる方法をいくつか説明します。

mallocsizeof 演算子を用いて C 言語で構造体メモリを割り当てる

malloc は C 言語の動的メモリ割り当ての中核をなす関数であり、割り当てたいバイト数を表す整数を 1つ引数にとる。定義されたカスタム struct オブジェクトのメモリを割り当てるには、sizeof 演算子を呼び出してオブジェクトが格納する必要のあるメモリ量を取得する必要があります。

引数として sizeof(MyObject) 式を直接 malloc 呼び出しに渡すことができることに注意してください。malloc の注意点の一つは、割り当てに成功したメモリは初期化されないということです。この問題に対処するために、C ライブラリにはもう一つの便利な関数 calloc が用意されており、メモリ領域を自動的にゼロで初期化してくれます。次の例は、単一の MyObject 構造体に対するメモリ割り当てを示しています。

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

enum VALID { FALSE, TRUE };

typedef struct {
  int valid;
  int *data;
  size_t size;
} MyObject;

int main() {
  int *tmp = NULL;
  MyObject *my1 = malloc(sizeof(MyObject));

  my1->valid = TRUE;
  my1->data = tmp;
  my1->size = sizeof tmp;

  free(my1);
  exit(EXIT_SUCCESS);
}

for ループを使って構造体の配列にメモリを割り当てる

構造体の配列を宣言すると便利なことが多く、スタック上で利用可能なメモリ領域よりも大きなメモリ領域を必要とすることがあります。そのため、動的メモリとして配列を確保する必要があります。以下のコード例は、MyObject 構造体への 100 個のポインタの配列をスタック上で宣言し、個々の MyObject オブジェクトをダイナミックメモリ(ヒープ)に確保した場合を示しています。

また、テストのためだけに MyObject の各メンバを初期化するために initMyObject 関数を実装したことにも注意してください。この関数はポインタが null の場合は -1 を返し、for ループの中に if 文を入れて、対応するエラーメッセージが表示されるようにしています。

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

#define MAX 100

enum VALID { FALSE, TRUE };

typedef struct {
  int valid;
  int *data;
  size_t size;
} MyObject;

int initMyObject(MyObject *obj, int val, int *dat, size_t siz) {
  if (!obj) return -1;
  obj->valid = val;
  obj->data = dat;
  obj->size = siz;
  return 0;
}

int main() {
  int *tmp = NULL;

  MyObject *arr[MAX];
  for (int i = 0; i < MAX; ++i) {
    arr[i] = malloc(sizeof(MyObject));
    if (initMyObject(arr[i], TRUE, tmp, sizeof(tmp)) == -1) {
      fprintf(stderr, "[ERROR] initMyObject() failed\n");
      break;
    }
  }

  printf("finished\n");

  exit(EXIT_SUCCESS);
}

ただし、先ほどのプログラムには、どんなプロダクションコードでも許されないような誤った部分があります。ループ内で動的に割り当てられたメモリ領域を解放せずにプログラムを終了します。割り当てと同様に、配列の個々の要素を解放しなければならないことに注意してください。そこで、以下のコードサンプルでは、free の反復呼び出しを実行するために、deallocMyObjectArray という別の関数を実装しました。

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

#define MAX 100

enum VALID { FALSE, TRUE };

typedef struct {
  int valid;
  int *data;
  size_t size;
} MyObject;

int initMyObject(MyObject *obj, int val, int *dat, size_t siz) {
  if (!obj) return -1;
  obj->valid = val;
  obj->data = dat;
  obj->size = siz;
  return 0;
}

int deallocMyObjectArray(MyObject *arr[], size_t len) {
  if (!arr) return -1;
  for (int i = 0; i < len; ++i) free(arr[i]);
  return 0;
}

int main() {
  int *tmp = NULL;

  MyObject *arr[MAX];
  for (int i = 0; i < MAX; ++i) {
    arr[i] = malloc(sizeof(MyObject));
    if (initMyObject(arr[i], TRUE, tmp, sizeof(tmp)) == -1) {
      fprintf(stderr, "[ERROR] initMyObject() failed\n");
      break;
    }
  }

  deallocMyObjectArray(arr, MAX);
  printf("finished\n");

  exit(EXIT_SUCCESS);
}
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C Struct