二次元配列式ポインタのconst化

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

二次元配列式ポインタのconst化

#1

投稿記事 by みけCAT » 13年前

Windows Vista SP2 32ビットです。
Dev-C++4.9.9.2、gcc version 3.4.2 (mingw-special)です。
二次元配列式のポインタ(要はダブルポインタ)が示している内容を、ある関数の中で書き換えないという意味で、
const指定をつけたいのですが、コンパイルエラーや警告が出てしまいます。

コード:

#include <stdio.h>
#include <stdlib.h>

#define ENABLE_TEST1
//#define ENABLE_TEST2
//#define ENABLE_TEST3

double test(const double* a,int n) {
	double sum=0;
	int i;
	for(i=0;i<3;i++) {
		sum+=a[i];
	}
	return sum;
}

#ifdef ENABLE_TEST1
double test1(double** a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

#ifdef ENABLE_TEST2
double test2(const double** a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

#ifdef ENABLE_TEST3
double test3(const (double**) a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

int main(void) {
	double** zikken;
	int i,j;
	zikken=malloc(sizeof(double*)*3);
	if(!zikken)return 1;
	for(i=0;i<3;i++) {
		zikken[i]=malloc(sizeof(double)*3);
		if(!zikken[i]) {
			for(j=0;j<i;j++)free(zikken[j]);
			free(zikken);
			return 1;
		}
		for(j=0;j<3;j++) {
			zikken[i][j]=i+j;
		}
	}
	printf("%f\n",test(zikken[0],3));
#ifdef ENABLE_TEST1
	printf("%f\n",test1(zikken,3));
#endif
#ifdef ENABLE_TEST2
	printf("%f\n",test2(zikken,3));
#endif
#ifdef ENABLE_TEST3
	printf("%f\n",test3(zikken,3));
#endif
	for(i=0;i<3;i++)free(zikken[i]);
	return 0;
}
この状態でコンパイルすると、警告やエラーは出ずにコンパイルが通り、実行も正常にできます。
#define ENABLE_TEST2のコメントアウトを外すと、このような警告が出ます。
しかし、このプログラムでは誤動作は確認できません。

コード:

F:\C\constmattest\constmattest.c: In function `main':
F:\C\constmattest\constmattest.c:77: warning: passing arg 1 of `test2' from incompatible pointer type
さらに#define ENABLE_TEST3のコメントアウトを外すと、コンパイルエラーになります。

コード:

F:\C\constmattest\constmattest.c:44: error: syntax error before "a"

F:\C\constmattest\constmattest.c: In function `test3':
F:\C\constmattest\constmattest.c:47: error: `n' undeclared (first use in this function)
F:\C\constmattest\constmattest.c:47: error: (Each undeclared identifier is reported only once

F:\C\constmattest\constmattest.c:47: error: for each function it appears in.)
F:\C\constmattest\constmattest.c:49: error: `a' undeclared (first use in this function)
F:\C\constmattest\constmattest.c: In function `main':
F:\C\constmattest\constmattest.c:77: warning: passing arg 1 of `test2' from incompatible pointer type
ダブルポインタを、普通のポインタのように、
関数の中で値を書き換えないconst指定にするにはどのようにすれば良いのでしょうか?
教えていただければ幸いです。
よろしくお願いします。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

box
記事: 2002
登録日時: 14年前

Re: 二次元配列式ポインタのconst化

#2

投稿記事 by box » 13年前

みけCAT さんが書きました:

コード:

#ifdef ENABLE_TEST2
double test2(const double** a,int n) {

コード:

double test2(double** const a,int n) {
ではないか、と思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: 二次元配列式ポインタのconst化

#3

投稿記事 by beatle » 13年前

boxさんが仰っているのは、ポインタ値自体は書き換わらないけれど、指し示している先は書き換えてもいいというポインタの宣言ではないでしょうか。
指し示している先を変えてはいけないという意味の宣言は

コード:

double const * const * p;
とやります。

コード:

typedef const double * ConstDoublePtr;
ConstDoublePtr const * p1;
const ConstDoublePtr * p2;
のようにも書けます。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 二次元配列式ポインタのconst化

#4

投稿記事 by ISLe » 13年前

覚え方としては、constを書いたところより左にある型に対してconst、です。

double const * * p1;
double * const * p2;
double * * const p3;
p1はdouble型を指す**p1に対してconst。
p2はdouble*型を指す*p2に対してconst。
p3はdouble**型を指すp3に対してconst。

int const i;
ならint型に対してconstです。
左端にconst書いたときは被参照型に対してconstになります。

hoge

Re: 二次元配列式ポインタのconst化

#5

投稿記事 by hoge » 13年前

beatle さんが書きました:boxさんが仰っているのは、ポインタ値自体は書き換わらないけれど、指し示している先は書き換えてもいいというポインタの宣言ではないでしょうか。
指し示している先を変えてはいけないという意味の宣言は

コード:

double const * const * p;
とやります。
これはC++での書き方です。
Cでは、この書き方自体は出来ますが、
警告を消すことは明示的にキャストを行なうしかありません。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 二次元配列式ポインタのconst化

#6

投稿記事 by みけCAT » 13年前

とりあえずbeatleさんのやりかたで解決とさせていただきます。
ありがとうございました。

コード:

#include <stdio.h>
#include <stdlib.h>

#define ENABLE_TEST1
//#define ENABLE_TEST2
//#define ENABLE_TEST3
#define ENABLE_TEST4

double test(const double* a,int n) {
	double sum=0;
	int i;
	for(i=0;i<3;i++) {
		sum+=a[i];
	}
	return sum;
}

#ifdef ENABLE_TEST1
double test1(double** a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

#ifdef ENABLE_TEST2
double test2(const double** a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

#ifdef ENABLE_TEST3
double test3(const (double**) a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

#ifdef ENABLE_TEST4
typedef const double * ConstDoublePtr;
typedef ConstDoublePtr const * ConstDoublePtr2;
double test4(const ConstDoublePtr2 a,int n) {
	double sum=0;
	int i,j;
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++) {
			sum+=a[i][j];
		}
	}
	return sum;
}
#endif

int main(void) {
	double** zikken;
	int i,j;
	zikken=malloc(sizeof(double*)*3);
	if(!zikken)return 1;
	for(i=0;i<3;i++) {
		zikken[i]=malloc(sizeof(double)*3);
		if(!zikken[i]) {
			for(j=0;j<i;j++)free(zikken[j]);
			free(zikken);
			return 1;
		}
		for(j=0;j<3;j++) {
			zikken[i][j]=i+j;
		}
	}
	printf("%f\n",test(zikken[0],3));
#ifdef ENABLE_TEST1
	printf("%f\n",test1(zikken,3));
#endif
#ifdef ENABLE_TEST2
	printf("%f\n",test2(zikken,3));
#endif
#ifdef ENABLE_TEST3
	printf("%f\n",test3(zikken,3));
#endif
#ifdef ENABLE_TEST4
	printf("%f\n",test4((ConstDoublePtr2)zikken,3));
#endif
	for(i=0;i<3;i++)free(zikken[i]);
	free(zikken);
	return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 二次元配列式ポインタのconst化

#7

投稿記事 by ISLe » 13年前

いちおう、一発で宣言できます。
typedef double const * const * ConstDoubleConstPtrPtr;

あと、test関数のaは操作できますが、test4関数のaは操作できないという点で違いがあります。

閉鎖

“C言語何でも質問掲示板” へ戻る