C言語 ポインタの使い方でこれだけは知っておきたい3つのこと

  • このエントリーをはてなブックマークに追加
Pocket

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つ以上欲しい場合にも、ポインタを引数に使うことで実現が可能です。

まとめ

ポインタを使わなくても作れますが、やはり、ポインタを使うほうが、便利な
場面が多いです。

まずは、ポインタの宣言の仕方と関数での使い方をマスターして、ポインタの扱いに慣れていきましょう。ポインタのポインタとか、構造体のポインタなど、いろいろありますが、まずは変数のポインタを扱えるようになりましょう。

  • このエントリーをはてなブックマークに追加

コメントを残す

*