
C言語のことで質問があります。
char *name1[4]は
char *name1[4] = {"abcdefghi","jkl","l","mn"};
と宣言でき,ポインタを4つ確保した形となりました。
char name2[][4]は
char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"};
と4文字以内の文字列を初期化した数だけ確保した形となりました。
この結果からchar *name1[4]の意味は,char name2[][4]ではなくchar name2[4][]に近いと思いました。
しかし,char name2[4][]ではポインタを4つ確保した事にはならないみたいでコンパイルが通りません。
*name1[4]では4つのポインタを確保できるのに~と思ってしまいます。
ポインタと配列は別物と考えるべきなのでしょうか?
訳の分からない質問かもしれませんが,
何卒ご指導いただくようよろしくお願いします。
No.3ベストアンサー
- 回答日時:
ポインタと配列の違いというのは、変数と定数の違いのようなものです。
話を簡単にするために、一次元配列から考えましょう。
char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり、この場合のa1は、
変数ではなく、定数のようなものなのです。
複合的なケースについて見てみましょう。
char **q1; ポインタへのポインタ
q1,*q1,**q1,q1[0],*q1[0],q1[0][0] のいずれも変数として
扱うことができます。(値を代入することが文法的に許されます。
ただし、実行時にはアクセス違反になる場合もあります。)
char q2[4][4]; 二次元配列
q2,q2[0]は変数として扱うことができません。q2[0][0]のように
して、初めて変数として扱えるようになります。
char *q3[4]; ポインタの配列
q3は変数として扱うことができませんが、q3[0],*q3[0],q3[0][0]
はいずれも変数として扱うことができます。
なお、この定義は char *(q3[4]); とした場合と全く同じ意味です。
char (*q4)[4]; 配列へのポインタ
q4,(*q4)[0],q4[0][0]はいずれも変数として扱うことができます。
しかし、*q4,q4[0]は変数として扱うことができません。
char *name1[4]; と char name2[4][]; は確かに似ています。しかし
違うところもあります。それは、name1[0] が変数として扱えるのに
対し、name2[0] には値を代入できないという点です。(データの
具体的な構造については、inthefloiさんが書いておられる通りです。
> char name2[4][]ではポインタを4つ確保した事にはならないみたい
というのも、全くその通りで、配列の定義では、ポインタ変数の領域
を確保する余地はないのです。
お返事どうもありがとうございます。
ranxさんのおかげで,自分が何が分かっていなかったのかが分かりました。
本当に勉強になりました。感謝感謝です^^
今後ともご指導いただけるようよろしくお願いします。
No.2
- 回答日時:
例えば、"abc" というのは、変数名は存在しませんが、コンパイラが自動的に作成した char 名前なし[4] = {'a','b','c','\0'} で初期化された配列を意味します。
例外として char の配列を初期するときには初期化する値そのものになります。ですから、char *name1[4] = {"abcdefghi","jkl","l","mn"}; は、
char 名前なし0[10] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\0' };
char 名前なし1[4] = { 'j', 'k', 'l', '\0' };
char 名前なし2[2] = { 'l', '\0' };
char 名前なし3[3] = { 'm', 'n', '\0' };
char *name1[4] = { 名前なし0, 名前なし1, 名前なし2, 名前なし3 };
というように解釈され、
同様に、char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"}; は、
char name2[8][4] = {
{ 'a', 'b', 'c', '\0' },
{ 'd', 'e', 'f', '\0' },
{ 'g', 'h', 'i', '\0' },
{ 'j', 'k', 'l', '\0' },
{ 'm', 'n', 'o', '\0' },
{ 'p', 'q', 'r', '\0' },
{ 's', 't', 'u', '\0' },
{ 'v', 'w', 'x', '\0' }
};
というように記述したのと全く同じ意味ですから、ポインタとは直接関係ありません。
どちらも、printf(name1[0]); や printf(name2[0]); のように参照できますが、データの構造は明らかに違います。
>char name2[4][]に近いと思いました。
この発想は正しいです。文字列で初期化する場合に限っては1次元目の大きさも省略できてもよさそうなものですが、まあ、決まりは決まりなのでしょう。
詳細な説明どうもありがとうございます。(^^)
変数が示すアドレスを見ていったらよく分かりました。
今後もご指導いただけるようよろしくお願いします。
No.1
- 回答日時:
char *name1[4] = {"abcdefghi","jkl","l","mn"};
は文字列"abcdefghi","jkl","l","mn"をメモリ上に確保して、その文字列をポインタが指します。
char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"};
の場合は、8×4文字分のメモリを確保して、そこに文字列を代入します。
8はコンピュータが実際の文字列から判断します。
配列の最後の数字は必ず必要です。省略できません。
したがって、
char name2[4][];
はエラーになります。
しかし、
char *name3[]={"abc","def"};
はできます。
以上。
早速のお返事ありがとうございます。
printf("%d\n", "abcdefg");
とやってみたら"abcdefg"がアドレスを示していたので
よく分かりました。
まだまだ分からない事がたくさんあると思いますので
その時もどうかよろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript 配列の1要素を代入した変数を使って元の配列要素を削除できるか 1 2023/07/28 03:34
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- 工学 ちなみになぜv=(v・e1)e1+(v・e2)e2はe1やe2が、正規直交基底でないと成り立たないと 2 2022/12/22 17:22
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- 工学 以前、線形代数からフーリエ級数展開を導く上で 式v=(v, e1)e1+(v, e2)e2+…+(v 6 2022/06/29 17:24
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- 物理学 波の合成についてです E1(z,t)=A0cos(kz-ωt+Φ) E2(z,t)=A0cos(kz 1 2022/10/10 06:35
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
fgetc( )の戻り値はなぜ整数??
-
C言語のintとcharの違いってな...
-
char型にint型の数値を代入する。
-
C言語にて構造体のメンバがNULL...
-
csvファイルをfscanfで読み込む...
-
Micom Car Rally に向けて製作...
-
簡易版smtpクライアント(メール...
-
char 文字列型 の表現範囲が-12...
-
char AA[]{"全角文字"};から"全...
-
エクセルのMID関数は、C言語では?
-
Cの関数の引数のconst *charに...
-
C++17で、unsigned char * 配列...
-
警告
-
wsprintf( ポインタ , "%d" , "...
-
C言語のプログラムについてです
-
構造体のメンバーの静的なサイ...
-
ポインタとcharについて
-
文字型配列に格納した空白の切捨て
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
C言語にて構造体のメンバがNULL...
-
C言語のintとcharの違いってな...
-
DWORDとcharの変換
-
C++17で、unsigned char * 配列...
-
char 文字列型 の表現範囲が-12...
-
new charとnew char[N]の違いは?
-
char型にint型の数値を代入する。
-
動的メモリの初期化方法について。
-
小数点入りの文字列をfloat型に...
-
文字型配列に格納した空白の切捨て
-
fstream型オブジェクトを関数の...
-
C++Builder 2009 テキスト...
-
文字列の途中から途中までを抽出
-
C言語の文字リテラル中の16進文...
-
エクセルのMID関数は、C言語では?
-
文字列のswap
-
void型へのポインタ
-
VC++ char[10]へのCString値の代入
おすすめ情報