二次元構造体配列を関数に渡す方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
k_takahiro_1503
記事: 7
登録日時: 7年前

二次元構造体配列を関数に渡す方法

#1

投稿記事 by k_takahiro_1503 » 7年前

初めての利用です。投稿場所を間違っていたら申し訳ありません。
現在練習としてあるプログラムを作成しているのですが、その中で二次元の構造体配列のメンバを関数へ渡す必要が出てきました。
しかし、"warning C4047:関節参照のレベルが~"などのエラーを吐いてしまい、うまくいきません。
以下のプログラムは構造体teststr[10][15]のメンバb[5]に0~4を代入してすべて合計するテストプログラムです。
コンパイル時にエラー「error C2088: '[' : struct に対して正しくありません。」が出力されます。
sum関数へ構造体のデータを渡す方法がまずいのでしょうか?
それとも二次元の構造体配列という仕様自体を見なおした方が良いですか?
ご教授願います。
コンパイラはVisual Studio 2013を使用しています。

コード:

#include <stdio.h>

int test(struct test *a);

struct test
{
	int a;
	int b[5];
};

int main(void)
{
	struct test teststr[10][15];
	
	int i,j,k;
	
	//0~4を代入
	for(i=0;i<10;i++)
	{
		for(k=0;k<15;k++)
		{
			for(j=0;j<5;j++)
			{
				teststr[i][k].b[j]=j;
			}
		}
	}
	
	//代入確認用のprintf
	for(i=0;i<10;i++)
	{
		for(k=0;k<15;k++)
		{
			for(j=0;j<5;j++)
			{
				printf("teststr[%d][%d].b[%d]=%d\n",i,k,j,teststr[i][k].b[j]);
			}
		}
	}
	
	printf("%d",sum(teststr));
	
	return 0;
}

int sum(struct test *a)
{
	int i,j,k;
	int X=0;
	
	for(i=0;i<10;i++)
	{
		for(k=0;k<15;k++)
		{
			for(j=0;j<5;j++)
			{
				X=X+a[i][k].b[j];
			}
		}
	}
	
	return X;
}

k_takahiro_1503
記事: 7
登録日時: 7年前

Re: 二次元構造体配列を関数に渡す方法

#2

投稿記事 by k_takahiro_1503 » 7年前

つかみどころのない文章となってしまったのですが、お聞きしたいのは
・二次元構造体配列を関数へ渡す方法
・二次元構造体配列を使用することはプログラム的にどうなのか?
ということです。
よろしくお願いします。

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

Re: 二次元構造体配列を関数に渡す方法

#3

投稿記事 by box » 7年前

合計を求める関数の引数を、「要素数15の配列へのポインター」にする。
構造体定義をプロトタイプ宣言の前に移動させる。
プロトタイプ宣言での関数名と実際の関数名を一致させる。

コード:

#include <stdio.h>

struct test
{
    int a;
    int b[5];
};

int sum(struct test (*a)[15]);

int main(void)
{
    struct test teststr[10][15];

    int i,j,k;

    //0~4を代入
    for(i=0;i<10;i++)
    {
        for(k=0;k<15;k++)
        {
            for(j=0;j<5;j++)
            {
                teststr[i][k].b[j]=j;
            }
        }
    }

    //代入確認用のprintf
    for(i=0;i<10;i++)
    {
        for(k=0;k<15;k++)
        {
            for(j=0;j<5;j++)
            {
                printf("teststr[%d][%d].b[%d]=%d\n",i,k,j,teststr[i][k].b[j]);
            }
        }
    }

    printf("%d\n",sum(teststr));

    return 0;
}

int sum(struct test (*a)[15])
{
    int i,j,k;
    int X=0;

    for(i=0;i<10;i++)
    {
        for(k=0;k<15;k++)
        {
            for(j=0;j<5;j++)
            {
                X=X+a[i][k].b[j];
            }
        }
    }

    return X;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

k_takahiro_1503
記事: 7
登録日時: 7年前

Re: 二次元構造体配列を関数に渡す方法

#4

投稿記事 by k_takahiro_1503 » 7年前

アドバイスありがとうございます。
確かに正しく動くようになりました。
ただ、いくつか追加で質問があります。
このプログラムでのteststrは二次元配列なので、sumに渡す引数は(*a)[10][15]となると考えてしまいます。
実際にこうすると動作を停止してしまうのですが、(*a)[15]とするのはなぜなのか教えていただけませんか?
もうひとつ、構造体の宣言をしたあとにプロトタイプ宣言をする、というのはC言語の決まりなのでしょうか?

プロトタイプ宣言と名前が食い違っている、というのを見落としたというのがとても恥ずかしいところです。
申し訳ないです。

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

Re: 二次元構造体配列を関数に渡す方法

#5

投稿記事 by box » 7年前

k_takahiro_1503 さんが書きました: このプログラムでのteststrは二次元配列なので、sumに渡す引数は(*a)[10][15]となると考えてしまいます。
実際にこうすると動作を停止してしまうのですが、(*a)[15]とするのはなぜなのか教えていただけませんか?
(*a)[10][15]
と書くと、「要素数15の配列を要素とする要素数10の配列へのポインター」という意味になります。
いわゆる3次元配列を使うのであれば、それでよいかもしれません。今回は違うので、そうは書けません。
どうしても[10][15]を書きたければ、
a[10][15]
と書けばよいでしょう。
また、いちばん左の要素数(今回は10)は省略できるので、
a[][15]
と書いてもいいです。実は、これが、
(*a)[15]
と同じ意味を持ちます。なお、こう書いたとき、*aの前後のカッコは省略できません。
*a[15]
と書くと、「要素数15のポインターの配列」となり、「要素数15の配列へのポインター」ではなくなってしまいます。
k_takahiro_1503 さんが書きました: もうひとつ、構造体の宣言をしたあとにプロトタイプ宣言をする、というのはC言語の決まりなのでしょうか?
だって、プロトタイプ宣言を先に書いちゃうと、「その時点では定義しておらず、何者かもわからない構造体」を使っていることになりますよ。
ソースコードの前の方で定義したものを、後の方で使うことができる、という原則を忘れないでください。
ゆえに、sum関数の定義をmain関数の定義「より前」に書けば、プロトタイプ宣言は省略できます。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

Re: 二次元構造体配列を関数に渡す方法

#6

投稿記事 by box » 7年前

自分だったら、例えばこんな風に書いたりします。
main関数は全体の司令塔に徹するという方針です。

コード:

#include <stdio.h>

#define I (10)
#define J (15)
#define K (5)

typedef struct {
    int a;
    int b[K];
} DATA;

void input(DATA (*arr)[J])
{
    int i, j, k;

    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            for (k = 0; k < K; k++) {
                arr[i][j].b[k] = k;
            }
        }
    }
}

void print(DATA (*arr)[J])
{
    int i, j, k;

    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            for (k = 0; k < K; k++) {
                printf("teststr[%d][%d].b[%d]=%d\n", i, j, k, arr[i][j].b[k]);
            }
        }
    }
}

int sum(DATA (*arr)[J]) {
    int total, i, j, k;

    for(total = i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            for (k = 0 ; k < K; k++) {
                total += arr[i][j].b[k];
            }
        }
    }
    return total;
}

int main(void)
{
    DATA teststr[I][J];

    input(teststr);
    print(teststr);
    printf("%d\n", sum(teststr));
    return 0;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

k_takahiro_1503
記事: 7
登録日時: 7年前

Re: 二次元構造体配列を関数に渡す方法

#7

投稿記事 by k_takahiro_1503 » 7年前

すべて納得しました。
コードまで書いてもらってありがとうございます。
とても参考になります。
また質問することがあればその時はよろしくお願いします。

閉鎖

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