ページ 11

引数として2次元配列を関数に渡したい

Posted: 2007年7月15日(日) 18:41
by Bose
C言語の初心者です.
2次元配列を引数に持つ関数を作成したいです.
具体的には以下のようなプログラムを作成しました.
#include<stdio.h>

void TCMap();
void EngineMap();
int Search_i(double map[/url][/url],int j,int i_mim,int i_max,double x);

double enginemap[18][2];
double tcmap[15][3];

int main(void){

int i_now,i_now2;

TCMap();//配列に値を代入
EngineMap();//配列に値を代入

i_now = Search_i(enginemap[/url][/url],0,0,17,1850);//i_now = 10のはず
i_now2 = Search_i(tcmap[/url][/url],3,0,14,500);//i_now2 = 9のはず

printf("%f,%f\n",i_now,i_now2);

return 0;
}

int Seacrh_i(double map[/url][/url],int j,int i_min,int i_max,double x){
	int i;
	if(map[i_min][j]<map[i_max][j]){//単調増加のとき
		for(i=0;i<i_max+1;i++){
			if(x<map[i_min][j]){//最小値以下ならi=i_min;
				i = i_min;
				break;
			}
			else if(x>map[i_max][j]){//最大値以上ならi=i_max
				i = i_max;
				break;
			}
			else if(x<map[j]){//
				i = i;
				break;
			}
		}
	}
	else if(map[i_min][j]>map[i_max][j]){//単調減少の時
		for(i=0;i<i_max+1;i++){
			if(x>map[i_min][j]){//最大値以上ならi=i_min
				i = i_min;
				break;
			}
			else if(x<map[i_max][j]){//最小値以下ならi=i_max;
				i = i_max;
				break;
			}
			else if(x>map[j]){
				i = i;
				break;
			}
		}
	}
	return(i);
}

void TCMap(){
	int i,j;
	FILE *file;
	double a;
	printf("トルコン領域マップ\n");
	file = fopen("TCOutputTorque.csv","r");	
	for(i=0;i<15;i++){							
		for(j=0;j<3;j++){						
		fscanf(file,"%lf,",&a);
		tcmap[j] = a;
		printf("tcmap[%d][%d] = %4.1f,",i,j,tcmap[j]);	
		}														
		printf("\n");
	}
	fclose(file);
}

void EngineMap(){
	int i,j;
	FILE *file;
	double a;
	printf("エンジン特性マップ\n");
	file = fopen("TCInputTorque.csv","r");		
	for(i=0;i<18;i++){							
		for(j=0;j<2;j++){						
		fscanf(file,"%lf,",&a);
		enginemap[j] = a;
		printf("enginemap[%d][%d] = %4.1f,",i,j,enginemap[j]);	
		}
		printf("\n");
	}
	fclose(file);
}

ここでSearch_i(...)に要素数の異なる配列enginemap[/url][/url]とtcmap[/url][/url]の両方を引数として渡したいのです.
しかしエラーが出てしまい,引数として要素数の異なる2次元配列を渡せません.
少し調べたのですが,
int f(double[/url][5],...)
のように配列の第2要素の個数を指定する方法しかわかりませんでした.
これではenginemap[18][2]とtcmap[15][3]の第2要素の個数が(2個,3個と)異なっているので困ります.
どのように修正すべきでしょうか?

Re:引数として2次元配列を関数に渡したい

Posted: 2007年7月16日(月) 00:50
by box
配列のかわりに動的メモリ確保を使ってみた例です。
TCMap()とEngineMap()のロジックが同等でしたので、1つにまとめてみました。

コンパイルは通っていますが、データファイルが手元にないので
実行は試せていません。


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

#define LEN (80)

typedef struct param {
	int param1;
	int param2;
} Param;

typedef struct kind {
	char filename[LEN];
	char message[LEN];
	Param param;
} Kind;

void mapFunction(Kind kind, double ***map);
int Search_i(double **map, int j, int i_min, int i_max, double x);

int main(void)
{
	double **map[2];
	Kind kind[2] = {
		{ "TCOutputTorque.csv", "トルコン領域マップ", { 15, 3 }, },
		{ "TCInputTorque.csv",  "エンジン特性マップ", { 18, 2 }, },
	};
	int i_now, i_now2;
	int i, j;
	
	mapFunction(kind[0], &map[0]);
	mapFunction(kind[1], &map[1]);
	
	i_now  = Search_i(map[1], 0, 0, kind[1].param.param1-1, 1850);						//i_now = 10のはず
	i_now2 = Search_i(map[0], kind[0].param.param2-1, 0, kind[0].param.param1-1, 500);	//i_now2 = 9のはず
	printf("%d,%d\n", i_now, i_now2);
	
	for (i = 0; i < 2; i++) {
		for (j = 0; j < kind.param.param1; j++)
			free(map[j]);
		free(map);
	}
	return 0;
}

int Search_i(double **map, int j, int i_min, int i_max, double x)
{
	int i;
	
	if (map[i_min][j] < map[i_max][j]) {		//単調増加のとき
		for (i = 0; i < i_max+1; i++) {
			if (x < map[i_min][j]) {			//最小値以下ならi=i_min;
				i = i_min;
				break;
			}
			else if (x > map[i_max][j]) {		//最大値以上ならi=i_max
				i = i_max;
				break;
			}
			else if (x < map[j]) {
				break;
			}
		}
	}
	else if (map[i_min][j] > map[i_max][j]) {	//単調減少の時
		for (i = 0; i < i_max+1; i++) {
			if (x > map[i_min][j]) {			//最大値以上ならi=i_min
				i = i_min;
				break;
			}
			else if (x < map[i_max][j]) {		//最小値以下ならi=i_max;
				i = i_max;
				break;
			}
			else if (x > map[j]) {
				break;
			}
		}
	}
	return i;
}

void mapFunction(Kind kind, double ***map)
{
	int i, j;
	FILE *file;
	
	printf("%s\n", kind.message);
	file = fopen(kind.filename, "r");
	if (!file)
		fprintf(stderr, "%s open error\n"), exit(1);
	
	*map = (double **) malloc(sizeof(double *) * kind.param.param1);
	if (!*map)
		fprintf(stderr, "out of memory\n"), exit(1);
	for (i = 0; i < kind.param.param1; i++) {
		*map = (double *) malloc(sizeof(double) * kind.param.param2);
		if (!*map)
			fprintf(stderr, "out of memory\n"), exit(1);
		for (j = 0; j < kind.param.param2; j++) {
			fscanf(file, "%lf", map[j]);
			printf("map[%d][%d] = %4.1f,", i, j, *map[j]);
		}
		printf("\n");
	}
	fclose(file);
}

Re:引数として2次元配列を関数に渡したい

Posted: 2007年7月16日(月) 16:32
by bose
box さん,回答ありがとうございます.
無事目的が果たせました.

しかし動的メモリ確保ですか...そのようなものは知りませんでした.
勉強して使いこなしたいものです.

ありがとうございました.

Re:引数として2次元配列を関数に渡したい

Posted: 2007年7月16日(月) 22:13
by YuO
> ここでSearch_i(...)に要素数の異なる配列enginemap[/url][/url]とtcmap[/url][/url]の両方を引数として渡したいのです.
> しかしエラーが出てしまい,引数として要素数の異なる2次元配列を渡せません.
> 少し調べたのですが,
> int f(double[/url][5],...)
> のように配列の第2要素の個数を指定する方法しかわかりませんでした.
> これではenginemap[18][2]とtcmap[15][3]の第2要素の個数が(2個,3個と)異なっているので困ります.
> どのように修正すべきでしょうか?

環境にも依るのですが,標準Cの範囲内であれば,
int f (int m, double [/url][m], ...)
のようにすればよいと思いますが。
古いCではコンパイル通りませんけどね。
# 標準C = ISO/IEC 9899:1999,古いC = ISO以前のCおよびISO/IEC 9899:1990とかISO/IEC 9899/AMD 1:1995とか。

Re:引数として2次元配列を関数に渡したい

Posted: 2007年7月16日(月) 23:22
by Hermit
古い C では
int Search_i( m, map, j, i_min, i_max, x)
int m; /* YuO さんのと同じ使い方ね。 */
double map[/url];
int j;
int i_min;
int i_max;
double x;
{
   if (map[i_min * m + j] < map[i_max * m + j]) {


の様にしていました。
昔も今も、配列は連続で確保と決まっているので。

PS.
プロトタイプ宣言で、二次元配列と一次元配列の違いでエラーになったかどうか不安だったので
OLD C で書いてみましたが・・・基本的には同じなので。

Re:引数として2次元配列を関数に渡したい

Posted: 2007年7月17日(火) 23:20
by Boze
YuOさん,Hermitさんご回答ありがとうございます.
当初は box さんに回答頂いた動的メモリ確保の方法でもできるんですね.
まだまだ勉強不足の私にはこちらの方が合ってると思います.

できればboxさんに教えて頂いた方法も身につけたいものです.

丁寧な解説ありがとうございました.