C言語をやっていくうえで、避けて通れないのに、一番ややこしいのがポインタではないでしょうか?
ポインタとは、変数のアドレスを格納している変数のことを言います。
アドレスとは、各変数に割り当てられたメモリの番地です。
と言ってもイメージできないですよね。私もC言語を始めた当初は何のこっちゃ
さっぱりわかりませんでした。少なくとも学生時代は理解できていませんでした。
今はいいと思いますよ。できているプログラムをコピペして、実際に動作をさせてみて、その流れを把握していくようにすれば、イメージできて来るとはずです。
私自身もとにかく、コピペして、デバッガで動かしてみたり、printf文とかで目に見える形で表示させてみたりして、そのプログラムがどう動いているかを確認しながら、少しずつ触ってみて、わかるようになりました。
したがって、あなたも徐々にわかるようになればいいのです。始めから、何でもできる人は天才以外に存在しません。
今はとにかく、次に解説することだけを最低限、覚えてもらえれば、それなりにプログラムが組めるようになります。
ポインタ変数の宣言の仕方
まずは、ポインタ宣言の仕方ですね。これがわからないと、どうしようもないですからね。
宣言の仕方は簡単です。通常の変数宣言は
short a;
という感じで宣言しますよね。これがポインタ変数の場合は
short *a;
となります。変数名の前に「*」(アスタリスク)をつけるとその変数はポインタ変数になるわけです。
宣言そのものは非常に簡単ですよね?
しかし、「*」があるかないかで、同じ変数aでも全く異なるものですので、そこは注意してください。
例えば、100という数値を代入した場合、aという変数には100が入りますが、意味が異なります。
通常の宣言の場合は数値の100として扱われますが、ポインタの場合はアドレス100番地として扱われることになります。
通常の変数宣言されたaもまた、どこかのアドレスに割り付けられており、そのアドレスに100という数値が格納されているのです。
通常の変数宣言されたaのアドレスも取得することができます。それは、変数の前に「&」をつけるだけです。
したがって、
short a;
short *b;
b = &a;
とすることができるのです。ポインタ変数bは変数aのアドレスを格納しているということになります。
ポインタ変数の使い方
ポインタ変数の使い方について解説していきます。
まず、
short a;
short *b;
a = 100;
b = &a;
というプログラムがあったとします。
このときポインタ変数bに格納されているアドレスのデータを取り出して、表示させる場合は、
printf(“ポインタ変数bに格納されているアドレスのデータ:%d\n”, *b);
とすればいいです。「*」をつければ、bに格納されているアドレスのデータを取り出すことができます。
この例の場合ですと、bに格納されているアドレスはaのアドレスですので、*bは100になります。なぜなら、aに100を代入しているからです。
aはメモリのどこかのアドレスに割り付けられており、そのアドレスに100を代入しています。したがって、aのアドレスを格納しているbから100という数値を取り出すことができるのです。
実際にプログラムを記述して、出力してみましょう。
#include <stdio.h> void main(void) { short a; short *b; a = 100; b = &a; printf("変数aのデータ:%d\n", a); printf("ポインタ変数bに格納されているアドレスのデータ:%d\n", *b); }
結果はどちらも100となるはずです。
関数の引数でのポインタの扱い
配列を関数に渡したい場合、配列を渡すことはできないですよね。
しかし、ポインタを使えば、関数で配列のデータを使用することが可能です。
具体的に見ていきましょう。
#include <stdio.h> short proc_sum(short* data, short num) { short i; short sum; if ((data == NULL) || (num < 0)) { return -32767; } sum = 0; for (i = 0; i < num; i++) { sum = sum + *(data + i); } return sum; } void main(void) { short dat[5] = {100, 50, 23, -18, 33}; short num; short sum_data; /* 配列の要素数を求める */ num = sizeof(dat) / sizeof(short); /* 配列の要素のデータの和を求める */ sum_data = proc_sum(dat, num); printf("合計:%d\n", sum_data); }
配列の要素の合計を計算して返す関数を作ってみました。
とりあえず、引数のチェックだけ入れました。本来なら、合計値を代入するsumの範囲チェックもするべきでしょう。short型の取りうる範囲外になってしまう可能性がありますので、完ぺきを求めるなら、範囲チェックを行うか、戻り値をlongにしておくとよいでしょう。
*(data + i) のところですが、ポインタにiだけ足しこんで、そのアドレスのデータを取得しています。ここで、ポインタの進み方ですが、dataはshort型のポインタなので、data + 1とすると、short型は2byteのデータなので、アドレスは2進みます。
これがポインタ変数の特徴です。データの型分だけ増えていくので、次のデータのアドレスが容易に求められるのです。
また、カッコ()のつけ方ですが、この場合はアドレスを進めてから、そのデータ取得するので、「*」をカッコ()の前にしておく必要があります。カッコ()の中に入れてしまうと全然意味が異なってしまうので、ここは注意が必要です。
もし、(*data + i)としたら、どうなるかわかりますか?
dataに格納されているアドレスのデータにiが足されるということになります。
したがって、この例で言うと、100 + 101 + 102 + 103 + 104という計算になってしまいます。
ところで、main関数からproc_sum関数を呼び出していますが、その第1引数は配列名datになっていることに気づいたでしょうか?
配列の[]を省略すると、配列の先頭アドレスのポインタになります。
datは&dat[0]と記述したのと同じです。
もし、dat[1]からのデータを渡したければ、proc_sum(&dat[1], 4)とすればいいです。
おわかりいただけたでしょうか?
例では配列を引き渡すやり方を解説しましたが、配列でなくても同じようにできます。また、戻り値が2つ以上欲しい場合にも、ポインタを引数に使うことで実現が可能です。
まとめ
ポインタを使わなくても作れますが、やはり、ポインタを使うほうが、便利な
場面が多いです。
まずは、ポインタの宣言の仕方と関数での使い方をマスターして、ポインタの扱いに慣れていきましょう。ポインタのポインタとか、構造体のポインタなど、いろいろありますが、まずは変数のポインタを扱えるようになりましょう。