C++のポインタ一覧
ポインタの使い方とか場面とかをそれぞれ紹介する.
たまに迷うことはある.
C言語とほぼ一緒.
変数へのポインタ
int a = 5;
int *a_p = &a; // aのアドレスを代入
cout << "a :" << a << endl; // value
cout << "*a_p:" << *a_p << endl; // value
cout << "&a :" << &a << endl; // address
cout << " a_p:" << a_p << endl; // address
注意
int *a_p = &a; // *a_pに&aを代入しているのでは無い.
の部分は
main
// int *a_p = &a; // a_pに&aを代入している.
int *a_p;
a_p = &a;
と同じ. ここの理解を間違えているとポインタを理解できない.
int *a_p = &a; // このように書くことが私は多いが,
int* a_p = &a; // このように書いた方がいいのかもしれない
int* a_p, b_p; // b_pはint型になってしまう (o o)
配列へのポインタ
main
int array[] = {0, 1, 2, 3, 4, 5, 6};
int *arrPt = array;
cout << "array :" << array << endl; //address
cout << "arrPt :" << arrPt << endl; //address
cout << "array[0]:" << array[0] << endl; // value
cout << "*arrPt :" << *arrPt << endl; // value(== array[0])
cout << "arrPt[1]:" << arrPt[1] << endl; // value(== array[1])
// ポインタを加算したら何がおこる?
cout << "*(++arrPt) :" << *(++arrPt) << endl; // value(== array[1])
cout << "*arrPt :" << *arrPt << endl; // value(== array[1])
関数の引数
よくある配列要素のswap関数を例にする.
c++では参照渡しが使えるのでこちらも紹介
void swap1(int *a, int *b) {// ポインタ渡し
cout << "swap1" << endl;
cout << " a:" << a << endl; // address
cout << "*a:" << *a << endl; // value
int t = *a;
*a = *b;
*b = t;
}
void swap2(int &a, int &b) {// 参照渡し
cout << "swap2" << endl;
cout << &a << endl; // address
cout << a << endl; // value
int t = a;
a = b;
b = t;
}
main
int array[] = {0, 1, 2, 3, 4, 5, 6};
swap1(&array[0], &array[2]);
cout << array[0] << endl;
cout << array[2] << endl;
swap2(array[0], array[2]);
cout << array[0] << endl;
cout << array[2] << endl;
構造体へのポインタ
構造体をポインタとして宣言する時がある.
=> 構造体へのポインタを宣言・定義する時がある
例えば木構造のクラスを作った時に, ノードを構造体とした場合, 子への参照には構造体のポインタを使うだろう.
struct myStruct {
int cost;
int index;
myStruct *next; // 次の要素を構造体として定義
myStruct(int c, int i) : cost(c), index(i) {}
};
main
myStruct stu = myStruct(50, 0);
myStruct *stuPtr = new myStruct(100, 1); // newを使う
stuPtr->next = &stu; // ポインタでは要素の参照に -> を使う
stu.next = stuPtr; // でなければ . を使う
cout << stu.cost << endl; //50
cout << stuPtr->cost << endl; // 100
cout << stu.next->index << endl; //1
cout << stuPtr->next->index << endl; // 0
注意
ポインタで定義する時はnewを用いて, メモリの確保を動的に行う.
myStruct *stuPtr;
みたいに定義していると, コンパイルはできるけれど出力で以下のような文言がでる.
$ zsh: segmentation fault ./a.out
構造体をポインタっぽく扱う方法(追記)
2件目のコメントよりoperatorを用いた云々の話です。多分こういう事?をおっしゃっている.
struct Node {
int value;
Node(int v) : value(v) {
cout << "called constructor" << endl;
}
// ここ
Node *
operator->() {
cout << "called -> operator" << endl;
return this; // pointer
}
void show() {
cout << "value is " << value << endl;
}
};
main
Node node = Node(777);
node->show();
cout << node->value << endl;
コラム:そもそもnewって何なん?
int *x;
x = new int();
*x = 5;
cout << "x :" << x << endl;
cout << "*x:" << *x << endl;
newは指定した型へのメモリを動的に確保してくれる.
型っていうのはクラスとか構造体.
クラスのコンストラクタに引数いらないなら( )はいらん.
cout << "new int():" << new int() << endl; // address
cout << "new int :" << new int << endl; // address
最後に
他に何かポインタの使い方があったら書き加える. 気分がのれば
あ、全体のソースコードものせておく。この記事はこれの抜粋
pointerTest.cpp
#include <iostream>
using namespace std;
struct myStruct {
int cost;
int index;
myStruct *next;
myStruct(int c, int i) : cost(c), index(i) {}
};
struct Node {
int value;
Node(int v) : value(v) {
cout << "called constructor" << endl;
}
Node *
operator->() {
cout << "called -> operator" << endl;
return this; // pointer
}
void show() {
cout << "value is " << value << endl;
}
};
// ポインタ渡し
void swap1(int *a, int *b) {
cout << "swap1" << endl;
cout << " a:" << a << endl; // address
cout << "*a:" << *a << endl; // value
int t = *a;
*a = *b;
*b = t;
}
// 参照渡し
void swap2(int &a, int &b) {
cout << "swap2" << endl;
cout << "&a:" << &a << endl; // address
cout << " a:" << a << endl; // value
int t = a;
a = b;
b = t;
}
int main(void) {
cout << "Variable" << endl;
int a = 5;
int *a_p = &a;
cout << "a :" << a << endl; // value
cout << "*a_p:" << *a_p << endl; // value
cout << "&a :" << &a << endl; // address
cout << " a_p:" << a_p << endl; // address
cout << endl;
cout << "Array" << endl;
int array[] = {0, 1, 2, 3, 4, 5, 6};
int *arrPt = array;
cout << "array :" << array << endl; //address
cout << "arrPt :" << arrPt << endl; //address
cout << "array[0]:" << array[0] << endl; // value
cout << "*arrPt :" << *arrPt << endl; // value
cout << "arrPt[1]:" << arrPt[1] << endl; // value == array[1]
cout << "*(++arrPt) :" << *(++arrPt) << endl; // value
cout << "*arrPt :" << *arrPt << endl; // value
cout << endl;
cout << "Function" << endl;
swap1(&array[0], &array[2]);
cout << array[0] << endl;
cout << array[2] << endl;
swap2(array[0], array[2]);
cout << array[0] << endl;
cout << array[2] << endl;
cout << endl;
cout << "what's new <classT>" << endl;
int *x;
x = new int();
*x = 5;
cout << "int *x;" << endl;
cout << "x = new int();" << endl;
cout << "*x = 5;" << endl;
cout << "x :" << x << endl;
cout << "*x:" << *x << endl;
cout << "new int():" << new int() << endl;
cout << "new int :" << new int << endl;
cout << endl;
cout << "Struct Pointer " << endl;
myStruct stu = myStruct(50, 0);
myStruct *stuPtr = new myStruct(100, 1);
stuPtr->next = &stu;
stu.next = stuPtr;
cout << stu.cost << endl; //50
cout << stuPtr->cost << endl; // 100
cout << stu.next->index << endl; //1
cout << stuPtr->next->index << endl; // 0
Node node = Node(777);
node->show();
cout << node->value << endl;
return 0;
}