404 Not Found

404 Not Found


nginx

関数の引数

第10課では、関数が引数を受け取ることができることを学びました。

しかし、パラメータは具体的にどのように渡されるのでしょうか?関数がパラメータを変更した場合、元の変数も変更されるのでしょうか?

今回のレッスンで取り上げるのは、まさにそのパラメータの渡し方です。


1. 値渡し

(1) 1.1 基本的な使い方

値渡しはC++のデフォルトの渡し方であり、引数の値がパラメータにコピーされます。

CPP
#include iostream

void modifyValue(int x) { // x is a copy
 x = 100; // Modifying the copy — original is unaffected
 std::cout << "Inside function: x = " << x << std::endl;
}

int main() {
 int a = 5;
 modifyValue(a); // Pass by value: a is copied to x
 std::cout << "Inside main: a = " << a << std::endl; // a is still 5
 return 0;
}

出力:

TEXT
Inside function: x = 100
Inside main: a = 5
💡 重要なポイント: 値渡しの場合、関数内でパラメータを変更しても、元の引数には影響しません

(2) 1.2 メリットとデメリット

メリット デメリット
安全(関数が元のデータを変更できない) 大きなオブジェクトのコピーにはコストがかかる(大きな配列、大きな構造体)
シンプルでわかりやすい 1つの関数から複数の値を「返す」ことはできない


2. ポインタ渡し

関数が元の変数を変更するようにしたい場合は、そのアドレス(ポインタ)を渡すことができます。

(1) 2.1 基本的な使い方

CPP
#include iostream

void modifyValue(int* x) { // x is a pointer
 *x = 100; // Dereference: modify the value the pointer points to
 std::cout << "Inside function: *x = " << *x << std::endl;
}

int main() {
 int a = 5;
 modifyValue(&a); // Pass the address of a
 std::cout << "Inside main: a = " << a << std::endl; // a is now 100
 return 0;
}

出力:

TEXT
Inside function: *x = 100
Inside main: a = 100
💡 要点: ポインタ渡しの場合、関数はポインタを介して元の変数を変更できる

(2) 2.2 なぜ変更できるのか?

手順 説明
1 int a = 5;a 用のメモリを割り当て、5 を格納
2 modifyValue(&a);aのアドレスを関数に渡す
3 int* x は、a のメモリを指すアドレスを受け取る
4 *x = 100; — ポインタを介して a の値を変更する


3. 参照渡し

C++では、ポインタよりも安全で便利な変数の別名である参照が導入されました。

(1) 3.1 基本的な使い方

CPP
#include iostream

void modifyValue(int& x) { // x is a reference (alias)
 x = 100; // Modifying x modifies the original variable
 std::cout << "Inside function: x = " << x << std::endl;
}

int main() {
 int a = 5;
 modifyValue(a); // Pass by reference — looks like pass-by-value
 std::cout << "Inside main: a = " << a << std::endl; // a is now 100
 return 0;
}

出力:

TEXT
Inside function: x = 100
Inside main: a = 100
💡 要点: 参照渡しでは、パラメータは引数の別名となります。パラメータを変更すると、元の値も変更されます。

(2) 3.2 参照とポインタ

比較 参照 ポインタ
構文 int& x = a; int* x = &a;
null になることはありますか? ❌ いいえ(初期化する必要があります) ✅ はい(nullptr になる可能性があります)
参照解除が必要ですか? ❌ いいえ(直接使用) ✅ はい(*x を使用)
再割り当ては可能ですか? ❌ いいえ(一度だけバインドされる) ✅ はい(別の場所を指すようにできる)
推奨 ⭐⭐⭐⭐⭐(推奨) ⭐⭐⭐(必要な場合)


4. 3つのパッシング手法の比較

(1) ▶ サンプル:1:2つの変数の入れ替え(難易度 ⭐⭐)

方法 1:値渡し(失敗)

CPP
#include iostream

void swapFailed(int a, int b) { // ❌ Pass by value: modifies copies
 int temp = a;
 a = b;
 b = temp;
}

int main() {
 int x = 3, y = 5;
 swapFailed(x, y);
 std::cout << "x = " << x << ", y = " << y << std::endl; // x=3, y=5 (no swap)
 return 0;
}
▶ 試してみよう

方法 2:ポインタ渡し(動作確認済み)

CPP
#include iostream

void swapPointer(int* a, int* b) { // ✅ Pass by pointer
 int temp = *a;
 *a = *b;
 *b = temp;
}

int main() {
 int x = 3, y = 5;
 swapPointer(&x, &y);
 std::cout << "x = " << x << ", y = " << y << std::endl; // x=5, y=3 (swapped)
 return 0;
}

方法 3:参照渡し(動作確認済み、推奨)

CPP
#include iostream

void swapReference(int& a, int& b) { // ✅ Pass by reference (recommended)
 int temp = a;
 a = b;
 b = temp;
}

int main() {
 int x = 3, y = 5;
 swapReference(x, y); // Looks like pass-by-value but is pass-by-reference
 std::cout << "x = " << x << ", y = " << y << std::endl; // x=5, y=3 (swapped)
 return 0;
}


5. どちらをいつ使うべきか?

シナリオ 推奨 理由
関数は変更する必要がない 値渡し または const 参照 安全で明確
関数を修正する必要がある 参照渡し 構文を整理し、安全にする
複数の値を「返す」必要がある 参照渡し 複数の参照パラメータを変更する
大きなオブジェクト(配列、構造体) const参照による渡し コピーのオーバーヘッドを回避
「なし」(例:見つかりませんでした)を表現する必要がある ポインタ渡し ポインタは nullptr である場合がある
💡 黄金律: 参照渡しを優先し、必要な場合にのみポインタ渡しを使用し、値渡しは小さなオブジェクトにのみ使用すること。



6. 定数への参照

関数がパラメータを変更しないようにしつつ、コピーも避けたい場合は、const 参照を使用してください。

CPP
#include iostream
#include string

void printName(const std::string& name) { // Const ref: can't modify name
 std::cout << "Name: " << name << std::endl;
 // name = "Alice"; // ❌ Error: can't modify a const reference
}

int main() {
 std::string myName = "MOTO";
 printName(myName); // No copy — efficient
 return 0;
}
💡 ポイント: const reference は C++ において 最も一般的なパラメータ型のひとつ です。安全性と効率性の両方を兼ね備えています。



7. 引数としての配列

配列を関数に渡すと、それはポインタに変換される(これについては後で詳しく説明します)。

CPP
#include iostream

// Array parameter: need to pass the length separately
void printArray(int arr, int length) {
 for (int i = 0; i < length; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
}

int main() {
 int myArray[5] = {1, 2, 3, 4, 5};
 printArray(myArray, 5); // Pass array name (which is the address)
 return 0;
}
💡 ヒント: 配列をパラメータとして渡す場合、関数はその長さを認識しません。そのため、サイズを別途指定する必要があります。



8. 演習:複数の戻り値

(1) ▶ サンプル:2:商と余りを求める(難易度 ⭐⭐)

CPP
#include iostream

// Use reference parameters to "return" multiple values
void divide(int a, int b, int& quotient, int& remainder) {
 quotient = a / b;
 remainder = a % b;
}

int main() {
 int a = 17, b = 5;
 int q, r;
 
 divide(a, b, q, r); // q and r will be modified
 
 std::cout << a << " / " << b << " = " << q << " ... " << r << std::endl;
 // Output: 17 / 5 = 3 ... 2
 
 return 0;
}
▶ 試してみよう

▶ サンプル 1: function parametersデモ (難易度 ⭐)

CPP
#include <iostream>

int main() {
 // function parametersの
 std::cout << "function parametersをびましょう!" << std::endl;
 return 0;
}
▶ 試してみよう

❓ よくある質問

Q: 参照とポインタの本当の違いは何ですか? A: 参照は変数の別名であり、ポインタはアドレスを格納する変数です。参照は初期化する必要があり、nullにはできず、再代入もできません。「何もない」ことを表現する必要がある場合を除き、参照を使用することをお勧めします(その場合はポインタを使用してください)。Q: 配列をパラメータとして渡す際、なぜ長さを指定する必要がないのですか? A: 配列はポインタに展開されるためです。void foo(int arr)void foo(int* arr) と同等です。arr パラメータは実際には配列ではなく、ポインタです。 Q: 値渡し、参照渡し、ポインタ渡しのうち、どれが最も効率的ですか?A: 小さなオブジェクト(intなど)の場合、値渡し(コピーコストが小さい)が最も効率的です。大きなオブジェクト(大きな配列、大きな構造体)の場合、定数参照渡し(コピーが発生しない)が最適です。パラメータを変更する必要がある場合は、参照渡し(構文が簡潔で、コピーが発生しない)が最も効率的です。


Q:function parametersについて最も重要なことは何ですか? A:まず核心概念を理解し、その後実践的な例で練習することが重要です。

Q:function parametersを効果的に練習するにはどうすればよいですか? A:簡単な例から始め、徐々に複雑さを増やし、常にコードをテストしてください。

📖 まとめ


📝 練習問題

  1. 初心者(難易度 ⭐): 渡された変数に10を加算する関数 void addTen(int& x) を作成してください。main() でテストしてください。

  2. 中級(難易度 ⭐⭐): 配列の最小値と最大値を求める関数 void minMax(int arr, int length, int& min, int& max) を作成してください(参照パラメータを使用してそれらを「返す」ようにしてください)。

  3. 上級(難易度 ⭐⭐⭐): 3つの数値を並べ替えるプログラムを作成してください。それらを昇順で並べ替える関数 void sortThree(int& a, int& b, int& c) を作成してください。ユーザーに3つの数値を入力してもらい、sortThree を呼び出し、並べ替えられた結果を表示してください。



9. 🚀 次は

パラメータの渡し方について理解できたところで、次は再帰(第12課)について学びましょう。これは、関数が自分自身を呼び出すという驚くべきテクニックです!

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%