404 Not Found

404 Not Found


nginx

ポインタ演算

[第]23[課では]ポインタ[算術の基本]について学びました(p + np - q)。

[しかし]ポインタ[の算術にはまだ多くの細かい点がある]――[例えば]ポインタ[で大小を比較できるのか]void* ポインタ[とは何か]?ポインタ[の]ポインタ[とはまた何か]?


1. ポインタ[比較]

(1) 1.1 ポインタ[大きさを比較できるのか]?

[可能]! [ただし、][同じ]配列[を指す]ポインタ[同士の比較にのみ意味がある]。

▶ サンプル 2: [基礎プログラミングの実践] (難易度 ⭐)

CPP
#include iostream

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p1 = &arr[0];
 int* p2 = &arr[3];
 
 if (p1 < p2) { // ✅ p1 's p2
 std::cout << "p1 p2" << std::endl;
 }
 
 if (p2 - p1 == 3) { // ✅ pointer 3
 std::cout << "p1 p2 3" << std::endl;
 }
 
 return 0;
}
▶ 試してみよう

💡 [要点]: ポインタ[が比較するのは]アドレス[の値]([つまり、要素が]配列[内の位置])です。


(2) 1.2 ポインタ[等価比較]

CPP
#include iostream

int main() {
 int x = 5;
 int* p1 = &x;
 int* p2 = &x;
 
 if (p1 == p2) { // ✅ pointer
 std::cout << "p1 p2" << std::endl;
 }
 
 int y = 10;
 int* p3 = &x;
 int* p4 = &y;
 
 if (p3 != p4) { // ✅ pointer's
 std::cout << "p3 p4" << std::endl;
 }
 
 return 0;
}


2. void* ポインタ

(1) 2.1 void* ポインタとは何か?

void* [はい][汎用]ポインタ——[任意の]型の[データ]を[指すことができる]。

CPP
#include iostream

int main() {
 int x = 5;
 double y = 3.14;
 char c = 'A';
 
 void* p1 = &x; // ✅ void* int
 void* p2 = &y; // ✅ void* double
 void* p3 = &c; // ✅ void* char
 
 return 0;
}

💡 [特徴]:


(2) 2.2 void* [の用途]

[用途1]:[汎用]関数([後で学ぶ] std::memcpy [つまり] void*

CPP
#include iostream
#include cstring

int main() {
 int arr1[5] = {1, 2, 3, 4, 5};
 int arr2[5];
 
 // std::memcpy Using void* 'spointer
 std::memcpy(arr2, arr1, 5 * sizeof(int));
 
 for (int i = 0; i < 5; i++) {
 std::cout << arr2[i] << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

[用途2]:動的メモリ[割り当て]([後述] malloc [戻る] void*


(3) 2.3 void* [の変換]

[使用する] void* [が指す]値は、[必ず具体的な]型[の]ポインタに変換する必要があります。

CPP
#include iostream

int main() {
 int x = 5;
 void* p = &x; // void* int
 
 // ❌:reference void*
 // std::cout << *p << std::endl;
 
 // ✅: int*
 int* intPtr = static_cast<int*>(p);
 std::cout << *intPtr << std::endl; // output 5
 
 return 0;
}

💡 [ヒント]: static_cast [は] C++ [の] 型[変換]演算子([後で学ぶ])であり、C [言語の] (int*)p よりも [安全] です。



3. [多重]ポインタ(ポインタ[の]ポインタ)

(1) 3.1 ポインタとは何か?

ポインタ[の]ポインタ[とは][ポインタアドレスを]格納[する]ポインタ([マトリョーシカ])。

CPP
#include iostream

int main() {
 int x = 5;
 int* p = &x; // p x
 int** pp = &p; // pp p(pointer'spointer)
 
 std::cout << "x = " << x << std::endl;
 std::cout << "*p = " << *p << std::endl; //: x
 std::cout << "pp = " &lt;&lt; pp << std::endl; //: x
 
 return 0;
}

出力:

TEXT
x = 5
*p = 5
**pp = 5

(2) 3.2 [多階層]ポインタ[の]宣言

[声明] [意味]
int x; x [はい] int
int* p; p [はい] int*[指向] int [的]pointer
int** pp; pp [はい] int**[指向] int* [的]pointer
int*** ppp; ppp [はい] int*[指向] int [的]pointer

💡 [読み方]: [右から左へ読む]。


(3) 3.3 [多階層]ポインタ[の用途]

[用途1]:[動的]2次元配列([後述])

CPP
// points 3×4
int** matrix = new int*[3]; // matrix pointer'spointer
for (int i = 0; i < 3; i++) {
 matrix[i] = new int[4];
}

[用途2]:function[修正が必要]pointer([あまり見られない]、[知っておけばよい])

CPP
#include iostream

void allocateInt(int** ptr) {
 *ptr = new int(5); // *ptr()
}

int main() {
 int* p = nullptr;
 allocateInt(&p); // ...
 std::cout << *p << std::endl; // output 5
 delete p; // ...
 return 0;
}


4. ポインタ[と] const [の組み合わせ]

(1) 4.1 [4つの組み合わせ]

[宣言] [意味] [変更可能か]ポインタ [参照先を変更可能か]値
int* p; [普通]ポインタ ✅ [可能] ✅ [可能]
const int* p; [指向] const int [の]ポインタ ✅ [可能] ❌ [不可能]
int* const p = &x; const ポインタ([初期化必須]) ❌ [不可] ✅ [可]
const int* const p = &x; [指向] const [の] const ポインタ ❌ [できない] ❌ [できない]

💡 [記憶のコツ]: [右から左へ読む]。


(2) 4.2 例:const int*([常用])

CPP
#include iostream

void printArray(const int* arr, int size) {
 for (int i = 0; i < size; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
 
 // ❌ modify:arr[i] = 0; // ...
}

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 printArray(arr, 5);
 return 0;
}

💡 [要点]: const int* arr [は][最もよく使われる]関数の[引数]型——[「読み取り専用」で、[変更しない]ことを示す]。



5. 演習:[使用]ポインタ[実装]文字列[コピー]

▶ サンプル 1: [手書き] strcpy (難易度 ⭐⭐)

CPP
#include iostream

void myStrcpy(char* dest, const char* src) {
 while (*src != '\0') {
 *dest = *src; // ...
 dest++; // ...
 src++;
 }
 *dest = '\0'; // ...
}

int main() {
 char src = "Hello";
 char dest[20];
 
 myStrcpy(dest, src);
 std::cout << "src = " << src << std::endl;
 std::cout << "dest = " << dest << std::endl;
 
 return 0;
}
▶ 試してみよう

出力:

TEXT
src = Hello
dest = Hello

💡 [ヒント]: [この]プログラム[では]ポインタ[演算][と][参照の解除]が[使われており]、[ポインタを]理解するための[絶好の練習]となります。


❓ よくある質問

Q:[なぜ] void [は参照にできない]のか?* A:[なぜなら] void [はサイズのない]型であり、コンパイラは[1] [バイト]、4 [バイト]、[あるいは] 8 [バイト]のどれを読み取るべきか[分からない]からである。

[具体的な]型[の]ポインタ([例:] int*double*)に変換しなければ、コンパイラは[ストライドを]認識できません。

Q:[多階層]ポインタ[にはどのような用途がある]? A:[実際の]プロジェクト[において]、int [最もよく見られるのは]: > 1. [動的な]2次元配列([例] new int*[3]) > 2. 関数で[ポインタ]自体を[変更する必要がある]場合([例] void foo(int p) pが[どこを指しているか]を[変更できる])

[2段階以上ある]ポインタ(int*** [など])[推奨されません]——[理解するのが難しすぎる]。

Q:const int [と] int const [は同じですか]? A:[同じです]![以下の2つの記述は同等です]: > > const int p; // [推奨] > int const p; // [同等]ですが、[あまり使われません] > > > [しかし] int* const p [同じではない]——[これは] const ポインタ([参照先を変更できない])である。


📖 まとめ


📝 練習問題

  1. 初心者(難易度 ⭐): [1つ宣言] int 変数 x = 5、[さらに1つ宣言] int* ポインタ p [が指す先] x、[さらに1つ宣言] int ポインタ pp [が] p [を指す]。出力 x*ppp、[それらが等しいことを検証する]。

  2. 中級(難易度 ⭐⭐): [1つの]関数 void swap(int a, int b) を書き、[2つの]ポインタ[の指す先を]入れ替える。

x,p2 y
swap(&p1, &p2):p1 y,p2 x
  1. 上級(難易度 ⭐⭐⭐): [用] void* [和]ポインタ[算術],[手書きで] myMemcpy 関数:

6. 🚀 次は

[ポインタ[の中級編]を学びました]。[次は] 参照(Reference)([第]25[課])を学びます――ポインタの「[安全なバージョン]」、C++の[重要な機能]です!

Web-Tutorial.com

Web-Tutorial 技術チーム

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

100%