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]とかで指定するのではないのかと思うのですが。
とにかく混乱です(>_<)
ご存知の方、教えていただけませんか?
No.1ベストアンサー
- 回答日時:
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になります。文字列にはなりません。
ご回答ありがとうございます。
分かりやすくてだいぶ分かってきました!!
#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列の数値を入れるセルがあるって考えちゃうんです。
No.4
- 回答日時:
回答はすでに出ていますが……。
実は、ポイントになるのは、「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() なんかを使おうとした際にも、いろいろと、面倒を起こすことがあります。
ありがとうございます!! そうなんです。もうほぼ解決したのでそろそろ閉じようと思ってました(^_^;
char namae[5][10]というのはnamae[10]という型の配列なのですね。namae[10]が型なので、namae[5][10]の[10]の部分は要素数を表しているのではなく、省略できない。
char namae[]="abcde"; とかはよく使うので、混同しそうですね。配列の要素数と型の違いがわかってよかったです。頭がすっきりしました!!
malloc()はメモリの確保に使うんでしたっけ。まだ1,2回しか記述したことがありません(汗)。
No.3
- 回答日時:
> ただ、不思議なのは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個、と考えた方がわかりやすいです。
ありがとうございます!!
charの配列を文字列として見れば、char a[5][10]は10文字のが5個。整数を入れるものだと考えれば5行10列あるとも見れるのですね。
int型の配列でも行列以外の見方があるとわかってよかったです。これからもCの勉強がんばります(^_^)
No.2
- 回答日時:
> 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]);
}
ご回答ありがとうございます!!
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がアドレスであるのと同じということでしょうか。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・集中するためにやっていること
- ・テレビやラジオに出たことがある人、いますか?
- ・【お題】斜め上を行くスキー場にありがちなこと
- ・人生でいちばんスベッた瞬間
- ・コーピングについて教えてください
- ・あなたの「プチ贅沢」はなんですか?
- ・コンビニでおにぎりを買うときのスタメンはどの具?
- ・おすすめの美術館・博物館、教えてください!
- ・ことしの初夢、何だった?
- ・【お題】大変な警告
- ・【大喜利】【投稿~1/20】 追い込まれた犯人が咄嗟に言った一言とは?
- ・洋服何着持ってますか?
- ・みんなの【マイ・ベスト積読2024】を教えてください。
- ・「これいらなくない?」という慣習、教えてください
- ・今から楽しみな予定はありますか?
- ・AIツールの活用方法を教えて
- ・【お題】逆襲の桃太郎
- ・自分独自の健康法はある?
- ・最強の防寒、あったか術を教えてください!
- ・【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
- ・歳とったな〜〜と思ったことは?
- ・モテ期を経験した方いらっしゃいますか?
- ・好きな人を振り向かせるためにしたこと
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語 配列の長さの上限
-
C言語で特定列だけを抽出して配...
-
配列を使わずに、変数名を動的...
-
配列を含む構造体の初期値について
-
【C言語】配列の中に配列を入れ...
-
配列で格納したものをmsgboxで...
-
【速いブラインドタッチ】手を...
-
Functionの戻り値を2次元配列...
-
unsigned char配列への入力の仕方
-
Redimした動的配列はEraseする...
-
テキストファイルから文字列を...
-
C# 配列の変数宣言について。
-
複数の選択範囲の行番号を個別...
-
C# Listを使わずに2次元配列の...
-
VBAで配列からbmp画像を出力す...
-
配列内の文字間を排他的論理和...
-
mallocの確保要素数の限界は?
-
配列の参照渡しで型が一致しま...
-
VB.netでRadioButtonを配列にし...
-
char型の二次元配列の意味が分...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語 配列の長さの上限
-
配列を使わずに、変数名を動的...
-
C# Listを使わずに2次元配列の...
-
配列で格納したものをmsgboxで...
-
先頭アドレスとは何ですか?
-
C言語で特定列だけを抽出して配...
-
複数の選択範囲の行番号を個別...
-
配列の参照渡しで型が一致しま...
-
テキストファイルから文字列を...
-
【速いブラインドタッチ】手を...
-
C# 配列の変数宣言について。
-
unsigned char配列への入力の仕方
-
【C言語】配列の中に配列を入れ...
-
VBで構造体の配列を関数に渡す...
-
配列を含む構造体の初期値について
-
C++ vectorに配列をプッシュしたい
-
ExcelVBAで質問です。離れた二...
-
配列をEraseしてもメモリが開放...
-
Functionの戻り値を2次元配列...
-
VB.NET 構造体の配列の検索機能...
おすすめ情報