• ベストアンサー

C言語で2次元配列の引数定義やコピーの仕方など

2次元配列の引数の定義や渡し方や ある変換する関数で、すべて' '(スペース)にしたり[memmoveなど1命令で]や、 それぞれ一つ違う値 A->B, O->Pに置き変える関数しようとしているのですが、 C言語のデータ操作に非常に疎く、どのようにすれば良いかわかりません。 どのようにすれば良いのでしょうか? 環境はWindowsで VisualC++6.0です。 GCCもソースを変えずに同じように出来るのでしょうか? #include <stdio.h> char lesson[7][6] = { {'A', 'B', 'C', 'D', 'E', 'F'}, // MON {'G', 'H', 'I', 'J', 'K', 'L'}, // TUE {'M', 'N', 'O', 'P', 'Q', 'R'}, // WED {'S', 'T', 'U', 'V', 'W', 'X'}, // THU {'Y', 'Z', 'a', 'b', 'c', 'd'}, // FRI {'e', 'f', 'g', 'h', 'i', 'j'}, // SAT {'k', 'l', 'm', 'n', 'o', 'p'}, // SUN }; // --- 多次元配列の引数の渡し方がわからないのでvoid --- void print_data(void) { for(int i=0; i < 7; i++){ for(int j=0; j < 6; j++){ printf("%c ", lesson[i][j]); } printf("\n"); } } // --- 問題の変換関数(引数定義と内容 --- int convert(????) { ???? } // --- メイン --- int main(boid){ print_data(); conver(???); // <--- どのように引数に渡すのか? print_data(); return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • ency
  • ベストアンサー率39% (93/238)
回答No.3

ggaogg さんの回答に補足します。 まず、配列は式の中では、コンパイラによってポインタに読み替えられます。 # 一部例外はありますが。 そして、この読替えは再帰的には行われません。 つまり、配列の配列 (2次元配列) は、配列のポインタには読み替えられますが、ポインタのポインタにはなりません。 この法則を適用すると、配列の配列は次のように読み替えられることになります。 char lesson[7][6]; → char (*lesson)[6]; つまり、「要素数 6 の配列へのポインタ」となってしまうのです。 ということで、引数に渡す場合には、次のようにすれば良いことになります。 void convert( char (*array)[6], int size ) # 配列サイズが消えてしまうので、一緒に引数に渡してあげると良いと # 思います。 # バッファオーバーフローの保険としてですけどね。 そして、この場合には、convert() は次のようにコールすれば良いことになります。 convert( lesson, 7 ); なぜ、こんなことをする必要があるのかというと、C が配列をまともに扱えない言語だからなんです。 配列を扱えない代表として、配列の代入ができないことがあります。 # 代入する場合は、for 文でグルグル回すことが多いですよね。 ちなみに、構造体は代入したり引数に渡したりできますよね。 # 構造体の実体を渡すことに対する賛否は別の話としてですけど。。。 【参考】 配列の宣言、定義については、一般にはポインタの宣言、定義との互換性はありません。 次の2つが別の定義になるのは明らかですよね? -------------------------------------------------- char hoge[8]; ⇒ char型のサイズ (1Byte) の領域を、連続して8個確保する。  sizeof( hoge ) は 8 を返します。  # hoge がポインタに読み替えられない例外のひとつ。 char *hoge; ⇒ char型へのポインタのサイズ (32bit マシンでは 4Byte) の領域を確保する。  sizeof( hoge ) は 4 を返します (最近の 32bit マシンの場合)。 -------------------------------------------------- ただし、関数の引数の宣言 (仮引数宣言) に限って、これらは同じ意味になります。 void convert( char (*array)[6] ); void convert( char array[][6] ); ⇒いずれも、char型の6個分の配列へのポインタを引数としてとる関数になります。 …あ、もし混乱してしまったようでしたら、この参考は無視して下さい。 すべては、C の妙な (?) 文法によるものなのですけどね。。。

その他の回答 (2)

  • ggaogg
  • ベストアンサー率43% (38/88)
回答No.2

#1です。 まず、配列は、連続したポインタなので、引数にはアドレスを渡せばいいわけです。 次に、受け取る側では、配列をどのように要素に取り入れればいいかを教えてやる必要があります。 引数がchar array[][6]となっているのはそのためで、6つの要素ずつに分けて受け取るわけです。 つまり ABCDEFGHIJKLMNOPQRSTUVWXYZ(以下省略) の先頭のAのアドレスを受け取ったら、それを6つずつの配列に分解させて ABCDEF GHIJKL MNOPQR STUVWX YZ(以下省略) というふうに分解するんだよという情報が必要なので。 で、わたってるのがアドレスなので、convert関数で変更すると、おおもとであるmainの配列内容も変更されるわけです。 ・・・まあこれだけでは多分わからないと思うので、一応URLを。 http://cai.cs.shinshu-u.ac.jp/sugsi/Lecture/c2/e_05-01-06.html (今ぐぐったやつですが・・) 'A'はASCIIコードでは65です。 つまり65をchar型で表示するとAになるわけで、それに1を足してやると66、つまり'B'になるわけです。 これはコードがAから順に1ずつ増加していく性質を利用したものです。 なんだか説明べたなせいか、文章がまとまってないので、「配列」と「ポインタ」でぐぐってください。。 このへんの情報ならたくさんでてくると思いますので。

  • ggaogg
  • ベストアンサー率43% (38/88)
回答No.1

まずソースを示します。 見難そうなので、解説は分けます #include <stdio.h> void print_data(char array[][6]){ int i,j; for(i=0; i < 7; i++){ for(j=0; j < 6; j++){ printf("%c ", array[i][j]); } printf("\n"); } } void convert(char array[][6]){ int i,j; for(i=0; i<7; i++){ for(j=0; j<6; j++){ array[i][j] += 1; } } } // --- メイン --- int main(boid){ char lesson[7][6] = { {'A', 'B', 'C', 'D', 'E', 'F'}, // MON {'G', 'H', 'I', 'J', 'K', 'L'}, // TUE {'M', 'N', 'O', 'P', 'Q', 'R'}, // WED {'S', 'T', 'U', 'V', 'W', 'X'}, // THU {'Y', 'Z', 'a', 'b', 'c', 'd'}, // FRI {'e', 'f', 'g', 'h', 'i', 'j'}, // SAT {'k', 'l', 'm', 'n', 'o', 'p'}, // SUN }; print_data(lesson); printf("\n"); convert(lesson); // <--- どのように引数に渡すのか? printf("\n"); print_data(lesson); return 0; }