【基礎から学ぶプログラミング言語】 C言語/ユーザー定義関数でポインタ変数を使う方法

IT
スポンサーリンク
スポンサーリンク
スポンサーリンク

私たちは日常生活で何気なくパソコンやスマートフォンというコンピュータを使用しています。
これらのコンピュータが普通に動作しているのは、そのようにプログラミング言語が記述されているからです。
本記事は、そんなプログラミング言語について実際に学びながら要点をまとめていったメモという位置付けになります。
私は専攻が電気でプログラムに関しては全くの初心者ですので、同様に初心者の方には理解しやすくなっているかと思います。

今回は、「C言語/ユーザー定義関数でポインタ変数を使う方法」についての説明です。

1.初めに

前回、ポインタとはどんなものなのかを解説しました。
今回はその応用例として、ユーザー定義関数でポインタ変数を使用する方法について記述していこうと思います。

2.プロトタイプ宣言部分の記述

使用例に入る前に、ポインタ変数をプロトタイプ宣言部分に適用する記述方法から見ていきます。

例えば、以下のようなプロトタイプ宣言をされていたとします。

【void abc(int*, int*)】;

これまでの知識から考えると、“abc”というユーザー定義関数のプロトタイプ宣言をしようとしていることはわかるかと思います。
ただ、intの後ろに“*(アスタリスク)”なんて付いていませんでしたよね?
実は、このように“*”を付けることで「int型のポイント変数を入力する」という意味合いになります。
“*”を付けることがポインタ型の変数を定義するためのルールでしたので、ここでもそのルールがくっついてくるというわけですね。

3.ユーザー定義関数でポインタを使用する

では、上記の事柄を前提に、ユーザー定義関数でポインタを使用してみます。

#include<stdio.h>

void change(int*, int*);

void main() {
int a = 10;
int b = 20;
printf(“a = %d。b = %d。\n”, a, b);
change(&a, &b);
printf(“a = %d。b = %d。\n”, a, b);
}

void change(int* c, int* d) {
int z = *c;
*c = *d;
*d = z;
}

図1

3行目では先程述べたようにプロトタイプ宣言を行っています。
int型のポインタ変数を2つ入力するchangeというユーザー定義関数の宣言です。

changeというユーザー定義関数の中身は、13~17行目に書かれていますので、まずはその中身から見ていきましょう。

13行目では、ユーザー定義関数changeの入力形式を表しています。
ポインタ変数c及びポインタ変数dが引数になっています。

14行目では、新たに整数zを用意しています。
そして、そのzにポインタ変数cの値を代入しています
なので、この時点では「*c、*d、z(=*c)」という値の関係になっています。

15行目では、ポインタ変数cにポインタ変数dの値を代入しています
なので、「*c(=*d)、*d、z(=*c)」という値の関係になっています。

16行目では、ポインタ変数dにzの値を代入しています
なので、「*c(=*d)、*d(=*c)、z(=*c)」という値の関係になっています。

つまり、結果的にポインタ変数cの数値が*d、ポインタ変数dの数値が*cに置き換わります。
これがユーザー定義関数changeで実現させた機能です。

やっていることは、zという入れ物にcの値をコピーして、cという入れ物にdの値をコピーして、dという入れ物にzの値をコピーして…という具合にデータを移動させているだけですけど、最終的に戻り値を複数持たせることを可能にしています。
通常の変数は1つの戻り値しか設定できませんが、ポインタ変数を使用すると実質的に複数の戻り値を持たせたり引数を戻り値として扱うことができたりと、できることの幅が広がるのです
これはポインタ変数を使用する大きな利点と言えます。

ユーザー定義関数changeの機能はわかったので、本筋のプログラムである5~11行目について見ていきます。

まず、6~7行目で変数a=10、変数b=20だと定義し、その値を8行目のprintfで出力しています。

9行目では機能を説明したユーザー定義関数changeが出てきます。
【change(int* c, int* d);】となるように入力すればcとdの値が入れ替わります。
最初に“*”を付けることで「int型のポイント変数を入力する」という意味になると述べましたよね?
このルールに則って、ここではaのアドレスである【&a】と、bのアドレスである【&b】を入力しています
なので、9行目の処理でaとbの数値が入れ替わります。

後は、10行目でその数値が入れ替わった結果をprintfで出力しているというわけです。

実際にプログラムを実行すると、以下のようになります。

図2

aとbの数値が入れ替わっているでしょう?

4.ウォッチの使い方

ユーザー定義関数でポインタ変数を使用した例について説明したので、より動きを理解するためにウォッチという機能についても記述しておこうと思います。

今動作確認をしたプログラムにブレークポイントを設けて、値の変遷を見たかったとします。

試しに9行目にブレークポイントを用意し、デバッグを起動した結果は以下のようになります。

図3

この図では最初から&a(aのアドレス)、&b(bのアドレス)、a、bの値がそれぞれ表示されていますので、ステップを進めていけばどのように数値が変動しているのかが見てとれます。
ですが、実行環境によっては&aや&bの値が表示されていないことってあるんですよ。
そんな時に活躍するのがウォッチなのです。

アドレスや数値が表示されている領域の下の方を見ると、今表示されているタブは「自動」になっていることがわかります。
そこの候補にウォッチがあります。

図4

ウォッチを選択すると、以下のように「項目をウォッチに追加する」と出てきます。

図5

この「名前」の部分にa、&aなどと入力してEnterキーを押すと、その入力した名称の値を見ることができます。
要するに、どの数値を見るのかを自分でカスタマイズできるのです。
デバッグ作業時に自動にしていると勝手に表示される名称が切り替わって見づらいということは多々ありますので、ここで設定ができるのだと覚えておきましょう。

せっかくなので、ここで説明したプログラムの動作をウォッチを使って詳しく見てみます。

9行目にブレークポイントを設けた状態でデバッグを開始し、今回関係してくる変数とそのアドレスを全表示させてみました。

図6

この時点では8行目まで実行されているだけなので、c、d、zの値は定義すらされていないので何も表示されていませんね。
では、ステップインしてchange関数を実行していきます。

13行目を実行すると、以下のように変化します。

図7

9行目で【change(&a, &b);】と記述している為、ポインタ変数cはa、ポインタ変数dはbになりすまします。
なので、&cという入れ物/アドレスの中の数値はa(10)になり、&dという入れ物/アドレスの中の数値はb(20)と認識されています。

14行目を実行すると、以下のように変化します。

図8

14行目はzの数値をcの数値と同じにする処理なので、zが10に切り替わります。

15行目を実行すると、以下のように変化します。

図9

15行目はcの数値をdの数値と同じにする処理なので、cが10から20に切り替わります。

16行目を実行すると、以下のように変化します。

図10

16行目はdの数値をzの数値と同じにする処理なので、dが20から10に切り替わります。

このように変化点のみ橙色で表示されるようになるので、ウォッチをうまく使用すればどの行の処理で何をされているのかが一目でわかりやすくなります。

以上、C言語/ユーザー定義関数でポインタ変数を使う方法についての説明でした。