Menu
Coddy logo textTech

ポインタ vs 値

CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 9/61。

構造体を関数に渡すとき、Cには2つの選択肢があります。by value(構造体全体をcopyする)で渡すか、by pointer(addressだけをcopyする)で渡すかです。この選択はパフォーマンスに大きく影響します。

値渡しでは、スタック上に構造体の完全なコピーが作成されます。いくつかの整数を持つ小さな構造体なら、これは問題ありません。しかし、数百 bytes の構造体を想像してみてください。every function call で、そのすべてのデータが copies されます。

typedef struct {
    char name[100];
    int scores[50];
    double average;
} Student;

// 値渡し: 呼び出しごとに約308バイトをコピーする
void print_by_value(Student s) {
    printf("%s: %.2f\n", s.name, s.average);
}

// ポインタ渡し: 8バイトのみをコピーする(アドレス)
void print_by_pointer(const Student *s) {
    printf("%s: %.2f\n", s->name, s->average);
}

構文も異なります。値パラメータでは、ドット演算子(s.name)を使用します。ポインターでは、矢印演算子(s->name)を使用します。

pointer 版は、構造体のサイズにかかわらず通常 8 bytes であるメモリの address だけを渡すため、より効率的です。

これが、Cプログラマーがほぼ常に構造体を pointer として渡す理由です。function がデータを変更すべきでない場合は const を使用し、変更すべき場合は通常の pointer を使用します。効率性と意図の明確さの両方を得られます。

challenge icon

チャレンジ

簡単

Productモジュールを作成して、構造体を値渡しする場合とポインター渡しする場合の違いを示しましょう。2つの表示関数を作成します。1つは構造体全体をコピーとして受け取り、もう1つは構造体へのポインターだけを受け取ります。

3つのファイルを作成します。

  • product.h:3つのメンバー、char name[50]double priceint quantityを持つProduct構造体をDeclareします。また、次の2つの関数をDeclareします。
    • display_by_valueProductを値渡しで受け取り、その情報を表示します
    • display_by_pointerconst Product *を受け取り、同じ情報を表示します
    シンボルPRODUCT_Hを使用してインクルードガードを設定します。
  • product.c:両方の関数をImplementします。構文の違いに注目してください。値渡しのバージョンではドット演算子(p.name)を使用し、ポインターバージョンではアロー演算子(p->name)を使用します。両方の関数は同じformatで表示する必要があります。
  • main.c:Productを作成し、両方の表示関数をCallして、異なるパラメーター形式を使用しているにもかかわらず、同一の出力になることを確認します。

3つのinputsを受け取ります。product name(文字列)、price(double)、quantity(整数)です。

mainファイルで、これらの値を使用してProductをinitializeし、その後display_by_value、続けてdisplay_by_pointerをCallします。

両方の関数は次のformatで表示する必要があります。

Product: {name}, Price: {price}, Qty: {quantity}

priceには%.2fを使用して、小数点以下2桁まで表示します。

たとえば、inputsがLaptop999.995の場合、出力は次のようになります。

Product: Laptop, Price: 999.99, Qty: 5
Product: Laptop, Price: 999.99, Qty: 5

自分で試してみよう

#include <stdio.h>
#include <string.h>
#include "product.h"

int main() {
    char name[50];
    double price;
    int quantity;
    
    // 入力を読み取る
    scanf("%s", name);
    scanf("%lf", &price);
    scanf("%d", &quantity);
    
    // TODO: Product変数を作成し、入力値で初期化する
    // Hint: strcpyを使ってnameを構造体のnameフィールドにコピーする
    
    // TODO: Productを渡してdisplay_by_valueを呼び出す
    
    // TODO: Productへのポインタを渡してdisplay_by_pointerを呼び出す
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Cオンラインコンパイラ