ページ 11

3次元配列のポインタ

Posted: 2011年6月02日(木) 21:09
by
3次元配列に対するポインタはどうやって作ればいいのでしょうか?
例えば
char A[5][7][9] ={0};
に対するポインタはどう表記して、どのように値を格納すればいいのでしょうか?
分かる方いたら教えてください

Re: 3次元配列のポインタ

Posted: 2011年6月02日(木) 21:41
by setton
すみません、今規約を読んできました。
どうやら最悪な聞き方をしていたようで…

[1] 質問文
 [1.1] 自分が今行いたい事は何か
 三次元配列に対するポインタを造りたい。
 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
 code
#include <stdio.h>
int main(void){
int *pass[406];
int D[201][201][4];
pass = D;
return 0;
}
/code
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
a.c: In function `main';
a.c:5: error: incompatible types in assignment
 [1.4] 今何がわからないのか、知りたいのか
どうしたらエラーが出なくなり正常に動くのか
[2] 環境  
 [2.1] OS : Windows, Linux等々
 Windouws XPです
 [2.2] コンパイラ名 : VC++ 2008EE, Borand C++, gcc等々
  gccです
[3] その他
 ・どの程度C言語を理解しているか
 ・ライブラリを使っている場合は何を使っているか
C言語については、自力で情報オリンピックの予選の5番程度が入力データの半分までは答えが出せるくらいです

Re: 3次元配列のポインタ

Posted: 2011年6月02日(木) 21:44
by setton
タグの付け方を間違えました
すみません

コード:

 #include <stdio.h>
int main(void){
     int *pass[406];
     int D[201][201][4];
     pass = D;
 return 0;
}

Re: 3次元配列のポインタ

Posted: 2011年6月02日(木) 22:09
by a5ua
コードからは、目的が読み取れないので、いくつか候補を挙げてみました。

コード:

int main(void)
{
	int D[201][201][4];

	// CASE 1:D(int [201][201][4]型)へのポインタ
	int (*p1)[201][201][4] = &D;

	// CASE 2:Dの先頭要素(int [201][4])へのポインタ
	int (*p2)[201][4] = D;	//int (*p2)[201][4] = &D[0];としても同じ

	// CASE 3:Dを1次元配列として考えたときの先頭要素へのアドレス
	int *p3 = &D[0][0][0];

	return 0;
}
3次元配列(配列の配列の配列)に対するポインタを字面通りに解釈するとCASE 1なのですが、
settonさんのコードを見ると、やりたいことはCASE 2でしょうか?

Re: 3次元配列のポインタ

Posted: 2011年6月02日(木) 22:53
by setton
返信ありがとうございます。
恥ずかしながら、どれがどう違うのかが分かりません…
僕としては、ポインタから全ての値が参照できればどのような書き方であってもかまわないのですが…
出来たら、格納だけでなく参照の方法も記してくれるとありがたいです。
教えて下さったのでやってみたのですが、警告が出てしまいどこがどう違うのか分かりません…
警告は移植性のないポインタ変換というもので、値表示をためしにさせてみると、「問題が発生したため無題1.exeを終了します。 エラーを送信する しない」というよくあるエラー報告が出てきます。
すみませんがよろしくお願いします。

Re: 3次元配列のポインタ

Posted: 2011年6月02日(木) 23:00
by setton
すみません、先ほどファイルをいじっていたら、成功しました。
ありがとうございました。
後で見た方の為に成功したプログラムを置いときます。

コード:

#include <stdio.h>

int main(void){
	int D[201][201][4];
	int (*p1)[201][201][4] = &D; //ここで格納終了
	D[42][31][2]= 51;        //とりあえず試しにDに値を代入
	printf("%d",(*p1)[42][31][2]); //それをポインタの方から表示
	return 0;
}
最初はprintfの方を*p1[42][31][2]としておりまして、括弧でくくっておりませんでした。
そこを括弧を使って書いたところエラーも消え正常に動きました。
ありがとうございました。

Re: 3次元配列のポインタ

Posted: 2011年6月02日(木) 23:41
by setton
何度もすみません。
またエラーとなりました。
アドレスをグローバル変数で宣言しようと思い、以下のように書いたのですが5行目が移植性のないポインタ変換といわれてしまいました。

コード:

#include <stdio.h>
int (*p1)[201][201][4];
int main(void){
    int D[201][201][4];
    (*p1)[201][201][4] = &D;
    D[42][31][2]= 51;
    printf("%d",(*p1)[42][31][2]);
    return 0;
}
それは警告だけで済んだのですが、実行させるとまた途中で「問題が発生したため~」というウィンドウが出て強制終了されます。
また、問題を解いていて、Dの配列の方はどうしてもmain関数の外に出すことも、型を変えることもできません。
他の関数から使えるようにさえなればポインタでなくてもよいのですが、どなたか分かる方いたら教えてください

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 01:58
by (回答者)
int(*)[201][201][4] から int 型に変換しようとしているせいではないでしょうか?
やりたいことに全くそぐわない気はしますけど、(*p1)[201][201][4] = D[201][201][4];
ならとりあえずエラーは出なくなると思うのですが、なぜ三次元配列を使ってこのような事を行っているかの背景でもあればなるほどと思えるかもしれないのですが、もし宜しければその辺りの説明もあれば理解されやすいのではないかなと思いました。

それと、printf で表示しようとしている (*p1)[42][31][2] ですが、これを表示したいのでしょうか?
51 を入れた D[42][31][2] を表示したいのでしょうか?

また、D が初期化されておりませんがそれが原因でエラーが出て来たとかではないでしょうか?

それと、
> また、問題を解いていて、Dの配列の方はどうしてもmain関数の外に出すことも、型を変えることもできません。
> 他の関数から使えるようにさえなればポインタでなくてもよいのですが、どなたか分かる方いたら教えてください
どうして、関数外に出せず、型も変えられないのでしょうか?
これの意味もちょっと解らなかったのでもし宜しければ詳しく教えて頂けないでしょうか?

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 02:45
by かずま
setton さんが書きました:また、問題を解いていて、Dの配列の方はどうしてもmain関数の外に出すことも、型を変えることもできません。
他の関数から使えるようにさえなればポインタでなくてもよいのですが、どなたか分かる方いたら教えてください
次のコードは参考になりますか?

コード:

#include <stdio.h>

void set(int p[][3][4])
{
    int i, j, k;
    for (i = 0; i < 2; i++)
        for (j = 0; j < 3; j++)
            for (k = 0; k < 4; k++)
                p[i][j][k] = (i+1)*100 + (j+1)*10 + (k+1);
}

void put(int p[][3][4])
{
    int i, j, k;
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 3; j++) {
            for (k = 0; k < 4; k++)
                printf("%5d", p[i][j][k]);
            printf("\n");
        }
        printf("\n");
    }
}

int main(void)
{
    int D[2][3][4];
    set(D);
    put(D);
    return 0;
}

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 08:41
by box
setton さんが書きました:

コード:

int (*p1)[201][201][4];
ここで、p1はint型の[201][201][4]配列へのポインターであると言っているんですから、
setton さんが書きました:

コード:

    (*p1)[201][201][4] = &D;
これはおかしいです。
そもそも、配列の定義範囲外の領域に書き込もうとしてますしね。

コード:

    p1 = &D;
で十分。

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 08:44
by box
(回答者) さんが書きました: また、D が初期化されておりませんがそれが原因でエラーが出て来たとかではないでしょうか?
初期化してあろうがなかろうが、今回のエラーとは関係ありません。

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 08:56
by box
setton さんが書きました:

コード:

	int (*p1)[201][201][4] = &D; //ここで格納終了
これがなぜ正しかったかというと、

コード:

    int (*p1)[201][201][4];
    p1 = &D;
と同じことをいっぺんに書いているだけだから。

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 09:08
by non
これでは、いけませんか?

コード:

#include <stdio.h>
 
void set(int *p)
{
    int i, j, k;
    for (i = 0; i < 2; i++)
        for (j = 0; j < 3; j++)
            for (k = 0; k < 4; k++)
                *p++ = (i+1)*100 + (j+1)*10 + (k+1);
}
 
void put(int *p)
{
    int i, j, k;
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 3; j++) {
            for (k = 0; k < 4; k++)
                printf("%5d", *p++);
            printf("\n");
        }
        printf("\n");
    }
}
 
int main(void)
{
    int D[2][3][4];
    set((int *)D);
	put((int *)D);
    return 0;
}

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 16:00
by setton
いろいろご回答ありがとうございます
型や宣言場所が変えられないのは問題の指定のせいです。
最初からプログラムがある程度組んであって、削除、変更ができる場所が決まってるんです。
そしてD[201][201][4]の宣言場所がその範囲外なので、ここをいじることはできなかったんです。
p1= &Dでいけました。
ありがとうございました

Re: 3次元配列のポインタ

Posted: 2011年6月03日(金) 23:54
by かずま
int D[201][201][4]; と宣言された配列を、ポインタでアクセスするのに最も
適切な方法は、int (*p)[201][4]; と宣言したポインタ p に p = D; で値を
設定し、p[j][k] でアクセスすることです。

int (*p1)[201][201][4]; と宣言したポインタ p1 に p1 = &D; で値を設定し
(*p1)[j][k] でアクセスするのは、気持ち悪くて仕方がありません。

一次元配列で説明します。

int a[5]; という配列があった時、int *p; と宣言したポインタに p = a; で
値を設定し、p でアクセスするのが普通です。

もちろん、int (*p1)[5]; と宣言したポインタ p1 に p1 = &a; で値を設定し、
(*p1) アクセスできますが、そんなことは誰もしません。

C では、配列の先頭要素へのポインタを使って、配列の各要素をアクセスします。
そのため、p = &a[0] と書かなくても p = a と書くだけでよいように、a は暗黙のうち
に先頭要素へのポインタに変換されます。配列全体へのポインタにはなりません。

関数の引数で配列を渡される時も、void func(int *p) と書く代わりに
void func(int p[]) や void func(int p[5]) と書いてもよいようになっています。
書いてもよいだけで、実態は、void func(int *p) です。

三次元配列の場合も同様に、先頭要素である二次元配列へのポインタを使うべきです。

Re: 3次元配列のポインタ

Posted: 2011年6月04日(土) 18:37
by ISLe
かずま さんが書きました:三次元配列の場合も同様に、先頭要素である二次元配列へのポインタを使うべきです。
最初にa5uaさんが的確に指摘してたんですけどね。