ポインタ変数をconst指定したときの動きについて

ポインタ変数をconstで修飾する方法ですが、以下の2つがあります。

int i = 100;
const int *cp1 = &i;
int *const cp2 = &i;

この違いですが、cp1 は「const int」へのポインタであるため cp1 を使って cp1 が指す値を変更することはできません。上の例では「*cp1 = 300」とするのは間違いです。ですが、cp1 には他のポインタアドレスを代入することはできます。

cp2 はアドレスの変更ができません。cp2 は常に変数iのアドレスを指します。ですが、cp2 を使って変数iの値を変更することはできます。

これらの動きを試したソースコードを載せておきます。

コピペ用です。


#include <stdio.h>

int main( void )
{
	int i = 100;
	int j = 200;

	const int *cp1 = &i;
	int *const cp2 = &i;

	printf( "1: %d\n", *cp1);

	/* cp1を使ってiは変更できないのでcp2を使う */
	*cp2 = 300;
	printf( "2: %d\n", *cp1 );

	/* cp2のポインタの向き先は変えられないがcp1は変えられる */
	cp1 = &j;
	printf( "3: %d\n", *cp1 );

	return 0;
}

実行結果は以下となります。

$ ./a.out
1: 100
2: 300
3: 200

ちなみに文字配列にconstを使用した以下の例は、どうなるかわかるでしょうか?

const char a[ ] = “Apple”;
char *const p = “Orange”;

Appleという文字列は変更できなくなります。ポインタ p の向き先を変更することもできません。またOrengeという文字列を変更しようとすると不定になります。これについてはこの記事を見てみてください。

文字列をポインタで受け取るか配列で受け取るかの違い

C言語では文字列をcharの配列で扱います。文字列が関数のパラメータとなっているとき、呼び出される側の関数の引数定義はポインタでも良いし、配列でも良いです。どういうことかというと

main( ) {
 char s[ ] = “Hello”;
 :
 func( s );
 :
}

というプログラムがあった場合、呼び出される関数「func()」は以下のどちらで定義しても大丈夫です。

void func( char *p ) {・・}
void func( char a[ ] ) {・・}

ポインタで定義するか配列で定義するかでプログラム作成者の意図があるでしょうから、*p で扱うならポインタ位置の操作で、a[ ] で扱うなら添字を使っての操作を意図しているのだと思います。具体的な例を載せておきます。


#include <stdio.h>

void funcp( char *p );
void funca( char a[] );

int main( void )
{
	char s[] = "Hello";

	funcp( s );
	funca( s );

	return 0;
}

void funcp( char *p )
{
	while( *p )
		printf( "%c\n", *p++ ); 
}

void funca( char a[] )
{
	char i = 0;
	while( a[i] )
		printf( "%c\n", a[i++] ); 
}

funcp、funcaにあるwhile文ですが、簡略化して書いてしまったので補足しておきます。

while( *p )
 printf( “%c\n”, *p++ );

while( a[i] )
 printf( “%c\n”, a[i++] );

は、以下と同じです。

while( *p != NULL ) {
 printf( “%c\n”, *p );
 p++;
}

while( a[i] != NULL ) {
 printf( “%c\n”, a[i] );
 i++;
}

実行した結果です。

$ ./a.out
H
e
l
l
o
H
e
l
l
o

文字列をポインタで受け取るようにするか配列で受け取るようにするかは好みの問題かもしれませんが、では、ポインタで受け取っているのに配列で操作したりとか、配列で受け取っているのにポインタで操作したらどうなるか?をやってみました。ソースを以下のように書き換えています。


void funcp( char *p )
{
	char i = 0;
	while( p[i] )
		printf( "%c\n", p[i++] ); 
}

void funca( char a[] )
{
	while( *a )
		printf( "%c\n", *a++ ); 
}

実行した結果は、まったく同じでした(変わりませんでした)。なので、文字列をポインタで受け取っても配列で受け取っても同じように扱えるということのようです。「ようです」と書いているのは自分の中でどういうメカニズムなのかモヤモヤしているためなのですが。個人的にはポインタで受け取ったならポインタでの操作、配列で受け取ったなら添字での操作、という意図でソースを書いたほうが良いんじゃないかな、と思います。