まふゆちゃんの技術ブログ。

情報系の高校生・高専生・大学生を全力で応援するブログです。

【C言語】ポインタと配列の関係。(後編)

f:id:Mafuyu7se:20181111085643p:plain
こんばんは・:*+.\( °ω° )/.:+
バーチャル高専女子の七瀬真冬です。

今日の記事は"ポインタと配列の関係"後編になります。
前編はこっちだよ。
mafuyu7se.hatenablog.com

今回は前編の内容を理解している人向けの記事になるから、まだ読んでない人は目を通しておいてね。

■ 本記事の対象読者

・ポインタ=アドレスだってことは理解できてるよ!
・配列名=配列の先頭アドレス(ポインタ)ってことは知ってるよ!
・関数に配列を渡すときは、"配列の先頭アドレスを渡す必要がある"ことを知っているよ!

上記3点を見て「なんじゃそりゃ?」ってなった人は、もう一度前編を読んでみよう!

■ コードの実行環境

・OS:Windows 10
・開発環境:Visual Studio 2017

いつも通りだね!!

■ 注意!!

わかりやすさを重視しているので、ちょっぴり正確性に欠ける内容があるかも!
ポインタに関する正確な情報の提供は他のサイトに任せるよ!!

あと、スマホ版のレイアウトでは若干ソースコードの表示が崩れるから、
PC版での閲覧を推奨します!


スポンサーリンク



■ ポインタの値を操作してみよう!!

ポインタは、"アドレス"を示すものであることはもう知ってるよね。
正確には、"アドレスを格納する変数"です。
つまり、変数なので値(アドレス)を書き換えることが可能なんだよ。

#include <stdio.h>

int main(void)
{
	char charArray[] = "Mafuyu\0"; // char型の配列だよ。
	char *ptr;                     // char型のポインタだよ。
	int i;

	// ptrに配列の先頭アドレスを代入!
	ptr = charArray; // (1)

	// 文字数分(7回)ループするよ。
	for (i = 0; i < 7; i++)
	{
		printf("-------------------[%d回目のループ]-------------------\n", i);
		printf("ptrが指しているアドレスは %d だよ!\n", ptr);
		printf("ptrのアドレスに存在するデータは %c だよ!\n\n", *ptr);

		//ここでポインタの値を書き換える!
		ptr++; // (2)
	}

	return 0;
}

まず見てほしいのはコード内の(1)。
ptrはchar型のポインタ、すなわちアドレスを格納する変数です。
ここに、charArrayの先頭アドレスを入れています。
(配列名=配列の先頭アドレスだって、前回何度も言ったよね。)
つまり、文字列"Mafuyu"の"M"が存在する番地をptrに代入しているわけだね。

そして、for文のループ内で
・現在のループ回数
・現在のptrが指しているアドレス
・現在のptrが指しているアドレスに存在するデータ
を表示しています。
これを文字数分(7回)繰り返します。

そして、ループ内の(2)。
これがかなり重要なポイントです!!
ここで、char型のポインタであるptrの値をインクリメント(1増やす)しているよね。
すなわち、ptrに入っている"アドレスの値をインクリメント"しているわけです。
これ、実行するとどうなると思う?

実行結果はこちら。
f:id:Mafuyu7se:20181120204343p:plain

ループの回数が1進むごとに、アドレスが1バイトずつ増えているよね。
これは、コード内の(2)でptrの値(アドレス)をインクリメントしたからだよ。
つまり、ptrが指している場所が"配列の要素1つ分ずつ"移動しているわけです。
char型配列の場合はインクリメント1回で1バイト移動、
int型配列の場合はインクリメント1回で4バイト移動…といった具合だね。
(注:処理系によってサイズは変わることがあるよ。)
そして、インクリメントされたアドレスに存在するデータ(文字)もしっかり順番に出力できています。

メモリの内部を図で示すとこんな感じ。
f:id:Mafuyu7se:20181120225217p:plain

ポインタをうまく使うと、こんなふうにメモリ上のアドレスを指定して値を参照することができます。指定したアドレスに存在するデータを書き換えることもできます。

C言語で書かれたプログラムは一般的に処理速度が速いと言われているんだけど、その理由は
ポインタを使ってメモリ上のアドレスを直接指定することで、高速な処理を行うことができるからなんだよ。
他の言語では基本的にこういった処理はできないんです。
これは、C言語(C++)だけに許された特権みたいなもので、C言語の最大の強みといえます。

■ ポインタを使わなくても同じことはできます。でも…

さっきのコードですが、ポインタを使わなくても同じ処理を行うことができます。
ポインタを操作するんじゃなく、配列の要素番号を使うよ。
charArray[0], charArray[1], charArray[2]... といった感じで、順番に表示していきます。

#include <stdio.h>

int main(void)
{
	char charArray[] = "Mafuyu\0"; // char型の配列だよ。
	int i;

	// 文字数分(7回)ループするよ。
	for (i = 0; i < 7; i++)
	{
		printf("-------------------[%d回目のループ]-------------------\n", i);
		printf("charArray[%d]が存在するアドレスは %d だよ!\n", i, &charArray[i]);
		printf("charArray[%d]に入っているデータは %c だよ!\n\n", i, charArray[i]);
	}

	return 0;
}

実行結果はこちら。

f:id:Mafuyu7se:20181121203442p:plain

さっきと同じように表示できてるね。

コード自体は、ポインタを使った方法よりも、要素番号を使った方がシンプルで読みやすいよね。
だけど、ポインタを使った方が処理速度は速いです

なぜ処理速度に違いがあるのかというと、コンピュータさんにかかる仕事の負担が違うからです。
以下の図を見ればわかりやすいと思います。
f:id:Mafuyu7se:20181121220457p:plain
f:id:Mafuyu7se:20181121220506p:plain

今回みたいに規模が小さい配列の場合は全くといっていいほど処理速度に差はないんだけど、何千、何万といった大きい要素数を持つ配列を扱う場合は、速度の違いが結構出てきます
速度が要求されるならポインタを、そうでない場合は配列の要素番号を使うといいんじゃないかな。

ちなみに、こういう場面でポインタを使った処理が書ける人は、先生や上司から「おっ、コイツはなかなかデキる奴だな…」と一目置かれるかもしれません。


スポンサーリンク



■ char型以外の配列は??

今までずっと、char型の配列(文字列)を扱ってポインタと配列の関係を説明してきたよね。
実はchar型だろうとint型だろうとdouble型だろうと、配列とポインタの関係は変わりません

int型で例を示します。
関数ptintThreeSize()に、3つの要素を持つint型の配列を渡して、配列の要素をすべて表示する処理だよ。

#include <stdio.h>

void ptintThreeSize(int *threeSize);

int main(void)
{
	// まふゆさんのスリーサイズ。
	int threeSize[3] = { 82, 58, 84 }; 

	// 配列名(先頭アドレス)を渡します。
	ptintThreeSize( threeSize );

	return 0;
}

// 引数はアドレス(int型のポインタ)なので、*をつけるよ。
void ptintThreeSize(int *threeSize)
{
	int i;
	int *ptr;

	// 配列の先頭アドレスをptrにセット。
	ptr = threeSize;

	printf("まふゆちゃんのスリーサイズは、上から\n");

	// 要素数分(3回)ループするよ。
	for (i = 0; i < 3; i++)
	{
		printf("%d\n", *ptr);
		ptr++;
	}

	printf("です!!\n");
}

実行結果はこちら。
f:id:Mafuyu7se:20181121222729p:plain

要するに、
・配列名は先頭アドレス(ポインタ)を示す。
・関数に配列を渡したいときは、先頭アドレス(ポインタ)を渡す。
・ポインタのインクリメント1回につき、配列要素1つ分のアドレス移動ができる。

っていうのは、どの型の配列/ポインタでも同じなんだよってことです。

■ まとめ

・ポインタは変数なので、値を書き換えることができるよ!
・配列のデータを連続して参照するときは、要素番号よりもポインタを使ったほうが高速だよ!
・C言語で書かれたプログラムの処理速度が速い理由は、ポインタを使ってメモリ上のデータに直接アクセスできるからだよ!
・どの型でも、配列とポインタの関係は変わらないよ!

ひとまず、初心者向けのポインタ解説はこれで一区切りにします!!
おつかれさまでした・:*+.\( °ω° )/.:+
ここまでの内容を理解できた人は、きっと開発現場でポインタを使いこなせるよ!!

さて、次の記事ネタ探さなきゃ…

にほんブログ村 IT技術ブログへにほんブログ村
にほんブログ村 IT技術ブログ C/C++へにほんブログ村