Index |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
C++の壺・ポインタ篇
C++の基本テクニックのTipsです。C/C++には、ポインタというメモリのアドレスを制御する便利な機能があります。ポインタ篇では、ポインタのしくみと、配列や関数などにおける基本的な使用方法を扱います。
sasaraan programming ![]() Exposition ●ポインタの基礎
通常の変数は値を保持しますが、ポインタは、値の置かれているメモリ上のアドレスを保持します。ただし、様々な値は、システムが自動的にアドレスを決めて配置しますので、アドレスの番号自体を気にする必要も、アドレスの番号を直接指定する必要もありません。通常は、以下のように、'*' や '&' のポインタ演算子を用いて間接的にアドレスを表現してやり取りをします。
なお、値は値同士、アドレスはアドレス同士でしか代入はできません。
ポインタには、まずアドレスを代入します。アドレスを指定しないうちに値を入れると、システムによっては、既存のデータを壊してしまいますので注意が必要です。
●ポインタと配列
要素なしの配列名は先頭要素へのアドレスを表します。このことから、ポインタに、要素なしの配列名を代入することができます。ただし、ポインタが保持するのは、アドレスひとつ分だけですから、各要素には加算/減算を行ってアクセスします。
#include <stdio.h> // printf使用
#include <conio.h> // getch使用
int main()
{
int a[5] = {33, 44, 55, 66, 77}; // 配列の宣言 ・ int型の要素5個で初期化
int *p = a; // ポインタを宣言 ・ 配列 a のアドレスで初期化
int i;
for (i=0; i<5; i++) {
printf("%p, %p, %p\n", &a[i], a+i, p+i); // アドレスの出力 (すべて同じアドレス)
printf("%d, %d, %d\n", a[i], p[i], *(p+i)); // 値の出力 (すべて同じ値)
}
if (getch()) return 0;
}
この時、各要素の値やアドレスは、次のように表すことができます。(アドレスは変動)
また、ポインタは、加減のほかに、インクリメント/デクリメントによる計算も可能です。ただし、アドレスを表すとき、ポインタは、p++, p--, とすることはできますが、配列の各要素は、アドレスを保持しているわけではないので、a++, a-- とすることはできません。 // ポインタの計算
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] に移動)
}
●ポインタと関数
【ポインタと引数】
関数の引数は通常は値渡しで行われます。これは、関数の引数に値がコピーされて渡されるシステムです。値渡しではもとの変数(または定数)の値を変更することはできません。一方、ポインタを引数にする(アドレス渡し)と、参照渡しと同じ効果が得られます。これは値の入っているアドレスを渡すことになるので、もとの値を変更することが可能です。
ポインタを関数の戻り値とすることも可能です。ただし、関数内の通常の変数は、関数終了時にアドレスは残っていない可能性があります。プログラム終了まで値を保持する静的変数を使うか、別途引数に格納領域を取る必要があります。
関数自体へのポインタも使用することができます。引数記述なしの関数名は、その関数があるアドレスを指しますので、関数ポインタの宣言後は関数名を代入して使用します。この時、引数を囲む () は、* よりも優先度が高いので宣言時は関数名を()で囲む必要があります。
●ポインタのポインタ
ポインタを指すポインタも使用することができます。この時、参照先のポインタのアドレスは、アドレス演算子& を用います。
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
www.sasaraan.net |
(c) morijoh |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||