Index |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
C++の基礎知識()【ポインタ篇】
| ●宣言と代入 | ●ポインタと配列 | ●ポインタの計算 | ●関数ポインタ |
sasaraan programming ![]() Exposition ●宣言と代入
通常の変数はデータの値を保持しますが、ポインタは値がある場所(アドレス)を保持します。ポインタを表現する演算子には以下の二つが用意されています。なお、データ値とアドレスとは代入し合うことはできません。
* ・・・ アドレスにある値を示す
void main() { /* ポインタの操作例 */
int n = 99; // 変数の宣言
int *p; // ポインタの宣言 (アドレス未確定のため、ここでの値の代入は危険)
p = &n; // ポインタにアドレスを指定(必須) : *p=99, n=99 (同じアドレスを参照)
*p = 123; // ポインタに値を代入 : *p=123, n=123 (nの値も変わる)
n = 88; // 変数に値を代入 : *p=88, n=88 (*pの値も変わる)
n = *p; // 変数にポインタが示す値を代入 : *p=88, n=88 (すでに同じアドレス)
}
ポインタのポインタを宣言することもできます。これはあるポインタの配置されている場所(アドレス)を格納する時に利用されます。
void main() { /* ポインタのポインタの例 */
int s1[3] = {33, 44, 55} ; // 配列の宣言
int s2[3] = {77, 88, 99} ; // 配列の宣言
int *p[2] = {s1, s2} ; // ポインタの配列の宣言
int **t; // "ポインタのポインタ" の宣言
t = p; // "ポインタのポインタ" に "ポインタの配列のアドレス" を代入
}
●ポインタと配列
配列は解釈上はポインタと同じです。下記で宣言した配列 a[4] は、*a と同様の解釈をすることができます。
void main() {
int a[4] = {33, 44, 55, 66} ; // 通常の配列の宣言
int *p = a ; // a (配列名)は配列の先頭要素のアドレスを指す
int i;
for (i=0; i<4; i++) printf("%p, %d, %d, %d\n", p+i, a[i], *(p+i), p[i]); // 出力
}
この時、配列 a とポインタ *p との関係は次のようになります。
void main() {
char s[6] = "HELLO" ; // 通常の文字列の宣言
char *p = "HELLO" ; // 文字列のポインタは初期化可(定数扱い)
int i;
for (i=0; i<6; i++) printf("%p, %c, %c, %c\n", p+i, s[i], *(p+i), p[i]); // 出力
}
この時、文字列 s とポインタ *p との関係は次のようになります。
●ポインタの計算
ポインタは計算が可能です。ただし、加算(+)、減算(-)、インクリメント(++)、デクリメント(--)の四種類に限られます。
void main() {
int n[4] = {50, 60, 70, 80} ; // int型の配列(32ビット環境時では、1要素は4バイト)
int *p ;
p = n ;
printf("%d\n", *p); // = 50 : n[0]の値
printf("%d\n", *p+1); // = 51 : "*pの値" + 1
printf("%d\n", *(p+1)); // = 60 : p + "1要素"のアドレスを参照 (n[1] を参照)
printf("%d\n", (*p)++); // = 50 : 計算後に "*pの値" + 1 (n[0]=51 に変更)
printf("%d\n", *p++); // = 51 : 計算後に p + "1要素" のアドレス (n[1] に移動)
printf("%d\n", ++(*p)); // = 61 : = ++(*p) : "*pの値" + 1 (n[1]=61 に変更)
printf("%d\n", *++p); // = 70 : = *(++p) : p + "1要素" のアドレス(n[2] に移動)
}
●関数ポインタ
関数にもポインタを利用することができます。()を含まない関数名は、その関数があるアドレスを指しますので、関数ポインタの宣言後は関数名を代入して使用します。。この時、引数を囲む()は、* よりも優先度が高いので宣言時は関数名を()で囲む必要があります。
void func_A(int m) ; // 関数func_Aのプロトタイプ宣言(実体定義は略)
void func_B(int m) ; // 関数func_Bのプロトタイプ宣言(実体定義は略)
void (*funt_temp)(int m) ; // 関数ポインタの宣言
void main() {
int n = 100 ;
func_temp = func_A ; // func_Aのアドレスを格納
func_temp(n); // func_A の実行
func_temp = func_B ; // func_Bのアドレスを格納
func_temp(n); // func_B の実行
}
また、関数ポインタの配列を宣言することもできます。それぞれの要素には、同じ引数を持つ異なる関数のアドレスを格納することになります。
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
www.sasaraan.net |
(c) morijoh |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||