ポインタの考え方は、プログラミングを始める方にとって、イメージすることが難しいかもしれません。
しかし、ポインタを理解することができると他の言語もスムーズに習得することができます。
また、ポインタと一緒に使用する場合が多い配列についても説明していこうと思います。
それでは、C言語のポインタと配列について解説していきます。
1.ポインタとは
ポインタとは、ある変数のメモリアドレスを指している変数のことを言います。
メモリアドレスとは、OSがRAM上に割り当てたアドレス番号のことです。
プログラム上でポインタを宣言する場合は、こんな感じです。
#include <stdio.h>
int main() {
int a = 8;
int *pI; // ①
pI = &a; // ②
printf("\naのアドレス = %p\n", &a); // ③
printf("ポインタ変数pIのアドレス = %p\n\n", pI); // ④
printf("aの値 = %d\n", a); // ⑤
printf("ポインタ変数pIの値を表示 = %d\n\n", *pI); // ⑥
}
上記プログラムの実行結果が下図です。
①は、int型のポインタ変数を宣言しています。この宣言時の状態では、どのデータも指していません。
②で、int型変数aのアドレス値をポインタ変数pIに設定しています。
②の設定後、③、④で表示で、変数aとポインタ変数pIのアドレス値が同じになっていることがわかります。
更に⑥で、ポインタ変数の値を表示してみると、⑤で表示した変数aの値と同じになっています。
ここで重要なことは、&と*の使い方です。
・変数に&をつけると、その変数の値ではなくアドレス値を指すことになります。
・ポインタ変数に、*をつけるとポインタ変数が指しているアドレスの中身をさすこと
になります。
ポインタの使用方法は、あるデータ(例えば、変数や文字配列や関数、構造体など)のアドレスをポインタに設定し、
そのポインタを用いて変数や文字配列の操作、構造体のメンバにアクセスするなどに使用します。
また、ポインタのアドレス値は、特に意識する必要はありません。
理由は、そのアドレス値を直接使用する代わりにポインタ変数として使用するからです。
ポインタは、全ての変数型で使用することができます。
具体的なポインタの使用方法については、4項で配列を例に解説にします。
2.配列とは
配列は、複数の値を1つの変数名でまとめてデータ管理することができるものです。
文字列や複数の数値などを配列に格納して置くことで、データ処理がやりやすくなります。
先ほどのポインタのプログラムでも登場しましたが、実際のプログラムでは、
このような感じで書きます。
char mojiretu[7]; //char型の配列
int data[7]; //int型の配列
char型の配列に値を入れる場合には、下記のように配列の要素番号に、入れたい値を指定します。
#include <stdio.h>
main() {
char mojiretu[7];
mojiretu[0] = "h";
mojiretu[1] = "a";
mojiretu[2] = "i";
mojiretu[3] = "r";
mojiretu[4] = "e";
mojiretu[5] = "t";
mojiretu[6] = "u";
printf("5番目の文字を表示:%c\n", mojiretu[4]); // ①
printf("文字列の表示:%s\n", mojiretu); // ②
}
ここで注意することは、「配列の番号は、0から始まる」ということです。
次に、配列の表示のやり方として、
①のprintf()文は、%cを使用して5番目の文字を表示しています。
②のprintf()文は、%sを使用して配列名mojiretuに格納されている全文字を一度に表示することができます。
また、配列の初期化として、以下のように配列の宣言と同時に値を入れておくことができます。
char mojiretu[7]="hairetu";
int data[7]={0,1,2,3,4,5,6};
配列は、char型以外にも、int型やbool型などいろいろな型も同じように配列にすることができます。
3.2次元配列
先ほど説明した配列は、1次元の配列でしたが、2次元の配列も良く使用します。
例えば、こんな感じです。
#include <stdio.h>
main() {
char cMojiretu2[3][5]={"one","two","three"};
printf("文字列の表示=%s\n", cMojiretu2[0]);
printf("文字列の表示=%s\n", cMojiretu2[1]);
printf("文字列の表示=%s\n", cMojiretu2[2]);
}
main()関数の1行目は、cMojiretu2という3x5の2次元配列に、文字を入れて初期化しています。
ここでの3x5というのは、3つの文字列を持つことができ、その文字数が5文字までという意味です。
2次元配列の他にも3次元配列やそれ以上のものもありますが、あまりそれらは使用しません。
何故なら自分以外の方がそのプログラムを理解するために、かなり時間がかかるからです。
プログラムというものは、読み手に簡単に理解できるように簡素にわかりやすく書くべきです。
ただし、データ上、どうしても3次元配列以上で管理したい場合など読み手よりも、
データ管理を優先した方が良い場合もありますので、状況に応じて設計してください。
4.ポインタと配列の関係
ポインタの用途は、構造体のメンバアクセスや関数ポインタなどさまざまありますが、
ここでは、配列にポインタを使用した下記のプログラムで説明していきます。
#include <stdio.h>
main() {
char cMojiretu[7]="hairetu";
char *pC;
pC = cMojiretu; // ①
printf("cMojiretuのアドレス = %p\n", cMojiretu); // ②
printf("pCのアドレス = %p\n", pC); // ③
printf("pCの文字列を表示 = %s\n", pC); // ④
pC++; // ⑤
printf("cMojiretuのアドレス = %p\n", cMojiretu); // ⑥
printf("pCのアドレス = %p\n", pC); // ⑦
printf("pCで文字列を表示 = %s\n", pC); // ⑧
}
上記プログラムの実行結果が下図です。
①で、ポインタ変数pCに、配列cMojiretuの先頭アドレスを設定しています。
①の設定直後に、②③で各々の変数のアドレスを表示してみると、
この2つの変数のアドレスが同一になっていることがわかります。
アドレス値自体は、プログラムを実行する度に異なる場合がありますが、
メモリが空いている場所に格納しているだけですので、特に意識する必要はありません。
⑤で、ポインタ変数pCをインクリメントすると、次のアドレスを指すようになります。
どういうことかというと配列cMojiretuの2文字目のアドレスを指すようになります。
⑥のアドレス値は変化しませんが、⑦のアドレス値が変化します。
なので、⑧では、pCが一つ進んでいるので、配列cMojiretu変数の2文字目から表示されます。
そして、その状態からデクリメントすると、1文字目のアドレスを指すようになります。
このように、ポインタ操作で配列のデータを操作することができます。
また、配列の場合、配列の変数名がその配列の先頭アドレスを指すポインタになっています。
ただ、ポインタのようにインクリメントやデクリメントはできません。
配列の変数名は、その配列の先頭アドレス固定になっています。
5.最後に
ポインタが苦手だと感じる方は、プログラムを読んだり書いたりして、慣れていくしか無いと思います。
C言語だけでなくC++やJavaなどのオブジェクト指向言語では、
クラスのインスタンス生成やウィジェットクラスのアクセスにポインタを必ず使用しますので、
ここで、ポインタを理解してイメージできておくと、他の言語も理解が早くなります。
<関連・おすすめ記事>
Linux勉強用の中古パソコンおすすめショップランキング - 水瓶座列車
C言語の始め方と基本構造、コンパイルから実行までを解説 - 水瓶座列車
C言語の繰り返し構文( while, do while, for )の解説と応用 - 水瓶座列車
プログラミングを独学で勉強するためのLinuxパソコン準備手順 - 水瓶座列車