マビノギ知識王

二次元配列をポインタで参照するにはどうしたら><;
文芽 07/09/18 23:00

タイトルに書いたとおりで、
 
C言語で二次元配列に格納した値を、
ポインタを使いユーザ関数で
 
参照するにはどういう文にしたらいいのか?
 
解かる方いましたら
教えていただきたいのですが・・・。
T.T

赤い射手矢 >と言っても、重要なのは以下の3点のみ。

4点でした(笑
あとで追加したのがバレバレだ…
09/04/11 16:52
弐破於 様の答え
弐破於 07/09/19 01:26

C言語 二次元配列 ポインタ ユーザー関数 でググってみては?
それらしいのがありそうですよw

答えの出所 ねっと
赤い射手矢 様の答え
赤い射手矢 09/04/11 16:39

[1. 文字制限のため、分割して投稿する。読みにくいが我慢してくれ。]

例題プログラムを適当に書いてやった。
数分で書いたため最低限の美しさしか求めてないから、頑張って読んでくれ。


説明は、二次元配列のアドレス操作についての質問ということで、一次元の配列とポインタについては理解しているという前提で書くよ?
と言っても、重要なのは以下の3点のみ。

1. &識別子[インデックス1][インデックス2] で 識別子[インデックス1][インデックス2] のアドレスを取得できる
(識別子は参照したい二次元配列のもの)
(これは通常の変数と同じ扱いであることに注意すればすぐに理解できるだろう)

2. 全ての配列は識別子のみを指定すれば、その配列の先頭要素のアドレスを返す

3. ポインタに加算、減算を行うということは、それぞれポインタを次の要素へ進める、前の要素へ戻すということと同意
(内部的には型毎に大きさが異なるため、ポインタが次の要素を指す為には型毎に異なる値を加えなければならないが、C言語などの高級言語ではそれを自動で行ってくれる
そのため、ポインタに対し+1することで、次の要素を示すことができる)

4. C言語において、静的に確保された二次元以上の多次元配列も、アドレス空間内では一次元配列と同様に一列に確保される
(ただし、動的に確保された多次元配列についてはこの限りではないため注意すべき)

単純に利用できれば良いというレベルならこれくらいで十分(?)。
真に理解したければ、マシン語レベルから学習し、各オブジェクト(変数などを含む)がアドレス空間内でどのように確保されるかを知るべき。
そこまで知りたければ、
「電子計算機工学 中川裕志」
「コンピュータの構成と設計(第3版) パターソン&ヘネシー」
でも読むと良い。

答えの出所 頭の中
赤い射手矢 様の答え
赤い射手矢 09/04/11 16:44

[2. 文字制限のため、分割して投稿する。読みにくいが我慢してくれ。]

//---ソース(前半)-----
#include <stdio.h>

#define ROW 2
#define COL 3

//引数に与えられたアドレスが示す先に格納されたint型の値を出力する
void printIntegerWithPointer(const int* pointer) {
printf("%d", *pointer);
}

int main(void) {
//多次元配列の作成
int multiArray[ROW][COL] = {
{0, 1, 2},
{3, 4, 5}
};
int i,j;
int* pointer2multiArray = multiArray;

//multiArrayの中身を確認(ポインタを使わない通常の配列参照)
puts("[print multiArray]");
for(i=0; i<ROW; i++) {
for(j=0; j<COL; j++) {
printf(" %d", multiArray[i][j]);
}
putchar('\n');
}
putchar('\n');



/*
* 各要素毎にアドレスを取得し、
* それらのアドレスを呼び出し先の関数内で参照
*/
puts("[print multiArray with pointer to the each element]");
for(i=0; i<ROW; i++) {
for(j=0; j<COL; j++) {
putchar(' ');
printIntegerWithPointer(&multiArray[i][j]);
}
putchar('\n');
}
putchar('\n');

答えの出所 自宅の本棚(文中(1.)の本などなど)
赤い射手矢 様の答え
赤い射手矢 09/04/11 16:49

[3. 文字制限のため、分割して投稿する。読みにくいが我慢してくれ。]

//--ソース(後半)------

/*
* 初めに多次元配列multiArrayのアドレスを取得、
* ポインタpointer2multiArrayに格納し、
* pointer2multiArrayの参照先を1つずつずらしていくことで、
* multiArrayの要素を順に参照する
*/
pointer2multiArray = multiArray;
puts("[print multiArray with pointer to the first element]");
for(i=0; i<ROW; i++) {
for(j=0; j<COL; j++) {
putchar(' ');
printIntegerWithPointer(pointer2multiArray++);
}
putchar('\n');
}

return 0;
}

//--実行結果-----

[print multiArray]
0 1 2
3 4 5

[print multiArray with pointer to the each element]
0 1 2
3 4 5

[print multiArray with pointer to the first element]
0 1 2
3 4 5


これで終わり!
いや…インデントとかも消えてしまって非常に読みにくいな(泣)
まぁ、頑張って読んでよ。(読む気があれば(笑

答えの出所 バイト
阿咲佳 様の答え
阿咲佳 09/12/02 15:56

とりあえず、
int a[5][3];
みたいに確保したパターンと思って回答してみます。

//-------------------------------------------
// アドレスの増減で行ったバージョン。
// 読みにくいんであんまり好きじゃない。
//-------------------------------------------
int* Func1(int* array,int row,int col,int rowMax)
{
for(i=0;i<row+rowMax*col;array++,i++);
return array;
}

//-------------------------------------------
// インデックス指定で行ったバージョン。
// 個人的にはこちらのほうが好み。
//-------------------------------------------
int* Func2(int* array,int row,int col,int rowMax,int colMax)
{
if(row >= rowMax) { return NULL; }
if(col >= colMax) { return NULL; }
return &array[col][row];
}

ぱっと思いついたのはこんなところ。
面白い回答パターンってなかなか思いつきませんね。

また赤い射手矢様がおっしゃっている通り、メモリの確保方法しだいでは使えませんのでご注意を・・・

答えの出所 作業