C言語

構造体と動的メモリ

関連する値を一つにまとめ、必要な量のメモリを実行時に確保する方法を学びます。

01

構造体で値をまとめる

商品データC
#include <stdio.h>
typedef struct {
    char name[32];
    int price;
    int stock;
} Product;
int main(void) {
    Product apple = {"りんご", 150, 8};
    printf("%s: %d円(在庫%d)\n", apple.name, apple.price, apple.stock);
    return 0;
}
実行結果OUTPUT
りんご: 150円(在庫8)

typedefによりstructを毎回書かず、Productという型名で利用できます。

02

構造体を関数へ渡す

大きな構造体はコピーせず、変更しないポインタとして渡せます。メンバーは->で参照します。

表示関数C
void print_product(const Product *product) {
    printf("%s: %d円\n", product->name, product->price);
}

前の例のappleprint_product(&apple)を実行すると「りんご: 150円」と表示されます。

03

必要なメモリを確保する

mallocは指定したバイト数を確保します。失敗時はNULLを返し、不要になったら必ずfreeします。

入力された個数の配列C
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    size_t count = 3;
    int *scores = malloc(count * sizeof *scores);
    if (scores == NULL) return 1;
    for (size_t i = 0; i < count; i++) scores[i] = (int)(i + 1) * 10;
    for (size_t i = 0; i < count; i++) printf("%d ", scores[i]);
    printf("\n");
    free(scores);
    scores = NULL;
    return 0;
}
実行結果OUTPUT
10 20 30
04

callocとrealloc

callocは要素数と各要素サイズを受け取り、全ビットを0で初期化します。reallocは確保済み領域の大きさを変更します。

配列を拡張C
int *values = calloc(2, sizeof *values);
if (values == NULL) return 1;
int *resized = realloc(values, 4 * sizeof *values);
if (resized == NULL) {
    free(values);
    return 1;
}
values = resized;
values[2] = 30;
values[3] = 40;
free(values);

一時ポインタresizedを使うと、失敗時に元の領域を見失いません。

05

メモリを安全に扱う

確認すること
  • 個数とサイズの乗算がオーバーフローしないか確認する
  • 確保結果がNULLでないか確認する
  • 確保した領域の範囲内だけを使う
  • 所有者を決め、一度だけfreeする
  • free後のポインタを参照しない
ゼロ初期化の意味 callocの全ビット0が、すべての型で必ず意味上のゼロ値になるとは限りません。ここでは整数配列に利用しています。
PRACTICE

ミニ課題:商品一覧

商品数に応じてProduct配列を動的確保し、合計在庫金額を計算してください。確保失敗と解放も実装します。