構造体の動的確保
CoddyのCジャーニー「Logic & Flow」セクションの一部 — レッスン 48/63。
これまで、スタック上に構造体を作成する方法を学んできました。それらは宣言されたスコープ内に存在し、そのスコープが終了すると自動的にクリーンアップされます。しかし、元のスコープを超えて構造体を存続させる必要がある場合や、コンパイル時に必要な構造体の数がわからない場合はどうすればよいでしょうか?
ここで動的メモリ確保が登場します。他のデータ型と同じように、malloc() を使用してヒープ上に構造体を作成できます。主な違いは、動的に割り当てられた構造体は、free() で明示的に解放するまでメモリ内に残り続けるという点です。
構造体を動的にメモリ割り当てする構文は以下の通りです。
struct Point *ptr = malloc(sizeof(struct Point));これは、1つの Point 構造体を保持するために十分なメモリをヒープ上に割り当て、そのメモリへのポインタを返します。その後、アロー演算子を使用して構造体のメンバにアクセスし、変更することができます:
ptr->x = 10;
ptr->y = 20;malloc() が成功したか(non-NULL を返したか)を常に確認し、メモリリークを防ぐために struct の使用が終わったら free(ptr) を呼び出すことを忘れないでください。このテクニックは、実行時にデータ構造を作成および管理できる柔軟なプログラムを構築するために不可欠です。
チャレンジ
簡単malloc() を使用して構造体の動的割り当てを行う C 言語のプログラムを作成してください。プログラムは以下の要件を満たす必要があります。
- 以下のメンバを持つ
Carという名前のstructを定義します。- 製造年を格納する整数型の
year - 車のブランドを格納するサイズ 20 の文字配列
brand - 車のモデルを格納するサイズ 25 の文字配列
model - 車の価格を格納する浮動小数点型の
price - 車の走行距離を格納する整数型の
mileage
- 製造年を格納する整数型の
- main 関数内で、
carPtrという名前のCar構造体へのポインタを宣言します。 malloc()を使用して 1 つのCar構造体に対してメモリを動的に割り当て、返されたアドレスをcarPtrに代入します。- メモリ割り当てが成功したかどうかを確認します。
carPtrがNULLの場合は、Memory allocation failedと出力してプログラムを終了します。- 割り当てに成功した場合は、
Memory allocation successfulと出力します。
- 以下の入力値を読み取り、アロー演算子を使用して構造体のメンバに代入します。
- 製造年の整数を読み取り、
carPtr->yearを使用して代入します。 - ブランドの文字列を読み取り、
carPtr->brandを使用して代入します。 - モデルの文字列を読み取り、
carPtr->modelを使用して代入します。 - 価格の浮動小数点数を読み取り、
carPtr->priceを使用して代入します。 - 走行距離の整数を読み取り、
carPtr->mileageを使用して代入します。
- 製造年の整数を読み取り、
- すべての値を読み取った後、アロー演算子を使用して以下の計算を行います。
- 2024 から製造年を引いて車の車齢を計算します:
int age = 2024 - carPtr->year; - 車齢に基づいて減価償却率を計算します:車齢が 10 より大きい場合は減価償却率を 0.6 に設定し、そうでない場合は 0.8 に設定します。
- 現在の価値を計算します:
carPtr->price * depreciation
- 2024 から製造年を引いて車の車齢を計算します:
- アロー演算子を使用して、以下の正確な形式で車の情報を出力します。
Car Information:Year: [year]Brand: [brand]Model: [model]Original Price: [price]Mileage: [mileage]Age: [age] yearsCurrent Value: [current_value]
free(carPtr)を使用して、動的に割り当てられたメモリを解放します。Memory freed successfullyと出力します。
このチャレンジでは、malloc() を使用した構造体の動的割り当て、割り当て失敗のチェック、アロー演算子を使用したポインタ経由の構造体メンバへのアクセス、および free() による割り当て済みメモリの適切な解放についての理解をテストします。構造体を用いた動的メモリ管理の完全なライフサイクルを練習します。
チートシート
malloc() を使用して、ヒープ上に構造体を動的に割り当てます:
struct Point *ptr = malloc(sizeof(struct Point));アロー演算子を使用して、ポインタ経由で構造体のメンバにアクセスします:
ptr->x = 10;
ptr->y = 20;常に malloc() が成功したかどうかを確認し、終了時にはメモリを解放してください:
if (ptr == NULL) {
// 割り当て失敗の処理
}
// 構造体を使用...
free(ptr);自分で試してみよう
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// TODO: ここでCar構造体を定義します
int main() {
// TODO: carPtrという名前のCar構造体へのポインタを宣言します
// TODO: malloc()を使用して1つのCar構造体用のメモリを割り当てます
// TODO: メモリ割り当てが成功したか確認します
// 入力値を読み取ります
int year, mileage;
char brand[20], model[25];
float price;
scanf("%d", &year);
scanf("%s", brand);
scanf("%s", model);
scanf("%f", &price);
scanf("%d", &mileage);
// TODO: アロー演算子を使用して入力値を構造体のメンバに代入します
// TODO: 年数、減価償却、および現在の価値を計算します
// TODO: 必要な形式で車の情報を出力します
// TODO: 割り当てられたメモリを解放し、成功メッセージを出力します
return 0;
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。