【基礎から学ぶプログラミング言語】 C言語/ポインタで配列になりすます方法

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

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

今回は、「C言語/ポインタで配列になりすます方法」についての説明です。

1.初めに

ポインタとは何かになりすますものだという説明を前々回の記事辺りから説明してきました。
この“何か”にはこれまで他の変数を割り当てていましたが、配列に関してもポインタを使ってなりすますことが可能になっています

ということで、今回はポインタを使用して配列を表現する例について見ていこうと思います。

2.数字の配列とポインタ

以下のようなプログラムについて見ていきます。

#include<stdio.h>

#define HAIRETSU 4

void main() {
int sample1[HAIRETSU];
int x;
int* p1 = NULL;
for (x = 0; x < HAIRETSU; x++) {
sample1[x] = x;
}
p1 = &sample1[0];
for (x = 0; x < HAIRETSU; x++) {
printf(“sample1[%d] = %d “, x, sample1[x]);
printf(“*(p1+%d) = %d \n”, x, *(p1+x));
}
}

図1

配列やfor文は一度解説してから間が開いているので、簡単に補足説明をしながらどんなプログラムなのかを解説していきますね。

まず、3行目でマクロを使って『HAIRETSUという文字列は数字の4だと定義(define)しますよ』と宣言しています。
今回は何度もこのHAIRETSUを使用することになり、数字の4と記述すると他の数字と混ざってややこしいことになってくるので、マクロを使用しています。

次に6行目の【int sample1[HAIRETSU];】という記述ですが、これが配列です
[]の中の数字のことを添え字と呼び、添え字の分だけ連番で変数が定義される仕組みになっています。
添え字はHAIRETSU…つまり4なので、4つの変数が定義されています。
具体的には、sample1[0]・sample1[1]・sample1[2]・sample1[3]という4つのint型の変数が定義されます。

7行目はint型の変数xを定義し、8行目はポインタp1を定義しているだけです。

9~11行目はfor文を使用しています。
復習ですが、for文の中身は以下のような構成になっています。

for (① ; ② ; ③) {④}

① 変数の初期化をする。
② ここに入力した条件を満たしている限り、④を繰り返す。
③ 繰り返し処理を行う際に実行する処理を入力する。【a++】というのは【a = a + 1】のこと。【++a】でも同じ意味になる。また、【a- -】なら【a = a -1】になる。
④ 実行する内容を入力する。

なので、変数xが0(初期化状態)の時は変数sample1[0]=0、変数xが1の時は変数sample1[1]=1、変数xが2の時は変数sample1[2]=2、変数xが3の時は変数sample1[3]=3になるようにプログラムが繰り返されます。
変数xが4になると②の【x < HAIRETSU】を満たさなくなるので、sample1[0]=0、sample1[1]=1、sample1[2]=2、sample1[3]=3という結果がこのfor文により得られます

ここまではおさらいで、ここからが新しい試みです。

図1(リピート)

12行目では、ポインタp1にsample1[0]のアドレスを代入しています
sample1[0]なので、配列の一番最初の変数のアドレスを与えているわけですね。
こうすることで何が起きるのかは、13~16行目のfor文で確認できます。

13行目は9行目と全く同じ記述なので、変数xが0,1,2,3の時にそれぞれ14行目と15行目の処理が行われることになります。
14行目はsample1[0]~[3]の値をそれぞれ表示しているだけなのですが、15行目は*(p1+x)という見覚えが無いものの数値を出力しています。
まずは、どんな結果が表示されるのかを見てみましょう。

図2

左側は14行目の処理で、配列のそれぞれの数値がprintfで表示された結果です。
それに対して右側は、15行目の処理で*(p1+x)の数値をprintfで表示させた結果です。
sample1[x]=*(p1+x)の関係が成り立っているのがわかるでしょうか?

つまり、12行目のように配列の一番最初の変数のアドレスをポインタに与えると、ポインタが配列になりすますようになるのです
その結果、sample1[0]の数値は*(p1+0)、sample1[1]の数値は*(p1+1)、sample1[2]の数値は*(p1+2)、sample1[3]の数値は*(p1+3)という形でポインタで表されるようになっているのです。

3.文字の配列とポインタ

数字の配列にポインタでなりすませたので、同じように文字の配列にもなりすますことが可能です。

#include<stdio.h>

#define HAIRETSU 4

void main() {
char sample2[HAIRETSU];
int x;
char* p2 = NULL;
for (x = 0; x < HAIRETSU; x++) {
sample2[x] = ‘A’ + x;
}
p2 = &sample2[0];
for (x = 0; x < HAIRETSU; x++) {
printf(“sample2[%d] = %c “, x, sample2[x]);
printf(“*(p2+%d) = %c \n”, x, *(p2 + x));
}
}

図3

先程動作を説明した数字の配列とポインタのプログラムとほとんど同じ構成です。
文字なのでint型をchar型に変化させ、変換指定子を%cに変化させている箇所があります。

大きな変化点は、10行目の【sample2[x] = ‘A’ + x;】という記述です。
なんか【’A’ + x】とか書かれていますね。
こうすることで、「’A’+0=A」、「’A’+1=B」「’A’+2=C」という具合に、アルファベット順に文字が切り替わっていくようになります

何故そんなことになるのかは、デバッグを起動して値を確認してみるとわかります。

図4

デバッグで9~11行目のfor文を繰り返してみると、sample2[0]~[3]の値が入力されます。
すると、文字Aは値だと65、文字Bは値だと66、文字Cは値だと67、文字Dは値だと68に対応していることがわかります。
だから、数値が1大きくなるごとにアルファベットが進んで行ったんですね。

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

図5

結局のところ、ポインタはアドレスを参照するものなので、数字だろうが文字だろうがなりすまして表現することが可能なのです。

機能自体は理解するのは難しくないですが、配列変数sample1[0]の数値がポインタでは*(p1+0)という形で表現されるという点は覚える必要があります。

4.補足説明

ポインタに配列の一番最初の変数のアドレスを与えるとその配列になりすますことができることがわかりましたが、何故それでなりすましができたんでしょうね?
その部分のちょっとした補足説明です。

文字列の配列になりすますプログラムをデバッグで動作させ、ポインタに配列の一番最初の変数のアドレスを与える12行目まで実行してみます。

図6

この時の各値を確認してみてください。
&sample2[0]のアドレスに含まれる値がABCDになっているんですよね。
だからこのアドレスを読み取ることで、配列のデータになりすますことができたんです。

その理論で行くと、同じアドレスになっている&sample2をp2のアドレスに指定しても同様に配列になりすますことができそうですよね。
実際、その通りです。
それでも可能です。

図7

ちなみに、試しに&sample2[1]のアドレスを読み取ってみるとBCDという配列が読み取られる為、実行結果がズレます。

図8
図9 プログラム実行結果

以上、C言語/ポインタで配列になりすます方法についての説明でした。