【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード

char型の二次元配列の意味が分からないのです・・・。

char namae[5][10] = {

"a1",
"a2",
"a3",
"a4"

 };
printf("%s\n",namae[1]);

という文があったのですが、これは実行するとa2と表示されました。どうしてなのでしょう。

そもそもcharは文字1文字ですよね。char[5]という一次元配列に5文字の文字列を入れることができるというのは分かります。でもchar[5][10]ってどんな文字列を入れるのでしょうか。

どうして初期化で"a1"という二文字を順々と並べるのか、printfでどうしてnamae[1]なのかが意味不明です。二次元配列だからnamae[1][0]とかで指定するのではないのかと思うのですが。

とにかく混乱です(>_<)

ご存知の方、教えていただけませんか?

A 回答 (4件)

2次元配列は「1次元配列の1次元配列」だと考えてください。


char[5][10]は char[10]の配列が5つの配列です。

char namae[5][10] = {
"a1", ←これはnamae[0]にあるchar[10]の配列に入る
"a2", ←これはnamae[1]にあるchar[10]の配列に入る
"a3", ←これはnamae[2]にあるchar[10]の配列に入る
"a4" ←これはnamae[3]にあるchar[10]の配列に入る
 };

配列を使わなければ
char namae0[10] = "a1" ;
char namae1[10] = "a2" ;
char namae2[10] = "a3" ;
char namae3[10] = "a4" ;
char namae4[10] = "" ; /* 配列の大きさに満たない部分は0で初期化 */
という事です。namaeのあとの数字が配列の一つ目の添字に対応します。

>どうして初期化で"a1"という二文字を順々と並べるのか
2文字なのはたまたまで、9文字まで(\0が必要なので、10-1文字分)使えます。
並んでいるのは、上のように初期化するためです。

>printfでどうしてnamae[1]なのか
printfの%sに対応するのは「文字列」、つまり、charの配列か charへのポインタです。
char[][]は「charの配列の配列」なので、対応していません。
namae[1]は「charの配列」なので、%sで対応できます。
上の例にある namae1 だったら%sで表示できるのはわかるのではないでしょうか。

>二次元配列だからnamae[1][0]
これは、上の例でいえば namae1[0]です。つまり、ただのcharになります。文字列にはなりません。
    • good
    • 1
この回答へのお礼

ご回答ありがとうございます。

分かりやすくてだいぶ分かってきました!!

#include <stdio.h>

main()
{

char a[5][10] = {

"abcde",
"fghij",
""

};

printf("a[0][1]=%c\n",a[0][1]);
printf("a[0]=%s\n",a[0]);
printf("a[2]=%s\n",a[2]);
printf("a[2][0]=%d\n",a[2][0]);

}

こう書いてみたら、1番目のprintfで一文字だけ取り出せるし、2番目では文字列が出るし、3番目では文字列が入ってないし、4番目では数字の0がでます(^_^)

ただ、不思議なのはint型の配列だとint[5][10]とあったときint[10]の配列が5つって考えますか? 5行、10列の数値を入れるセルがあるって考えちゃうんです。

お礼日時:2010/05/06 22:24

回答はすでに出ていますが……。



実は、ポイントになるのは、「Cには2次元配列は存在しない」という事実です。(規格上はそうです)
じゃ、char namae[5][10] という表現は何かと言いますと、

char name[10] という「型」の、さらに、配列 です。

もちろん、name[1][1] は、name[][1] という要素の、[1] 番目 ということですから、事実上2次元配列のように扱えます。

この事実は、後々、いろんなところでいろいろな悪さをします。
たとえば、Cでは、初期化の際、「配列の要素数は省略できる」という決まりがあります。

たとえば、

char name[] = "abcdefg";

など。
ただし、上記の場合、
char name[][10] = {"....", "....", "..."};
とはできますが、
chae name[][] = ...
というのはできません。
[10] のほうは、(配列の要素数ではなくて)型の一部だからです。

これは、2次元配列のつもりで、malloc() なんかを使おうとした際にも、いろいろと、面倒を起こすことがあります。
    • good
    • 0
この回答へのお礼

ありがとうございます!! そうなんです。もうほぼ解決したのでそろそろ閉じようと思ってました(^_^;

char namae[5][10]というのはnamae[10]という型の配列なのですね。namae[10]が型なので、namae[5][10]の[10]の部分は要素数を表しているのではなく、省略できない。

char namae[]="abcde"; とかはよく使うので、混同しそうですね。配列の要素数と型の違いがわかってよかったです。頭がすっきりしました!!

malloc()はメモリの確保に使うんでしたっけ。まだ1,2回しか記述したことがありません(汗)。

お礼日時:2010/05/07 08:43

> ただ、不思議なのはint型の配列だとint[5][10]とあったときint[10]の配列が5つって考えますか? 5行、10列の数値を入れるセルがあるって考えちゃうんです。



これは、どう解釈するか、の違いです。

今回のは、「charの配列を『文字列』として解釈する」というCの仕様の関係で二次元配列にしたもので、仮に、string型という文字列専用の型があれば string[5]とするべきものでした。

また、char [5][10]も、「5行10列のchar型整数を入れるセルがある」と解釈することもできます。
実際、 8bitの画像データでそのように使い、 image[y][x]=100; 等とするケースもあります。
逆に int [5][10]でも、「10科目のテストの点を5人分」という場合は、int[10]の配列が5個、と考えた方がわかりやすいです。
    • good
    • 0
この回答へのお礼

ありがとうございます!!

charの配列を文字列として見れば、char a[5][10]は10文字のが5個。整数を入れるものだと考えれば5行10列あるとも見れるのですね。

int型の配列でも行列以外の見方があるとわかってよかったです。これからもCの勉強がんばります(^_^)

お礼日時:2010/05/07 08:32

> char namae[5][10]



これは char [10]の配列が5つ集まった配列になります。
つまり"a1","a2",……という文字列は、それぞれ、char [10]の配列空間に代入されていることになります。
配列の名前は配列の先頭データを指すポインタと同じなので、二次元配列は一次元配列のポインタの配列と同義になります。

仮に
char b1[10], b2[10], b3[10], b4[10], b5[10];
char *c[5];
とあったとき、

b1 = "a1";
b2 = "a2";
b3 = "a3";
b4 = "a4";
b5 = "a5";
c = {b1, b2, b3, b4, b5};
とするのと同じです。

そこで
>printf("%s\n",namae[1]);
としたとき、name[1]は、文字配列"a2"の先頭アドレスを指していることになるのです。

>二次元配列だからnamae[1][0]とかで指定するのではないのかと思うのですが。

文字列内の個々の文字要素にアクセスするときはそうなります。
例えば、
name[1][0]とすれば、それは'a'ですし、
name[1][1]とすれば、それは'2'になります。
name[1][2]なら、そこには文字列の末端を示す'\0'が入っています。

この回答への補足

すごいです!!

例えば、char a[5][10]のa[5]って5個のアドレスが配列になってるのですね!!

少なくともa[0]はa[0][10]のアドレスでした(^O^)

#include <stdio.h>

main()
{
int i;
char *pt;
char a[5][10] = {

"abcde",
"fghijk"

};

pt = a[0];

for(i=0; i<=4; i++){
printf("%c", (*pt+i));
}

puts("");
puts(a[1]);

}

補足日時:2010/05/06 23:33
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます!!

char namae[5][10]をchar[10]の配列が5つ集まった配列と考えるのはNo.1さまと同じですね。char型の二次元配列はそう理解すると良いのですね。

ポインタ配列を使った説明、なんとか理解できます。c[0]はb1[0]のアドレスを格納しているのですよね。そこにあるデータがa1で。

ただ、それと

>>printf("%s\n",namae[1]);
>としたとき、name[1]は、文字配列"a2"の先頭アドレスを指していることになるのです。

とのつながりが明確には理解できないのですが、char型の二次元配列はchar namae[5][10]だとすれば、

namae[0]がnamae[0][10]のアドレスだという理解でいいのですか? まるで普通のchar a[5]のaがアドレスであるのと同じということでしょうか。

お礼日時:2010/05/06 22:39

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!