- ベストアンサー
配列について
初歩的な質問ですいませんが、質問よろしくお願いします。 ◎1----------------------------- #include<stdio.h> int main(void) { char ss[10]="AB"; printf("ss=%s\n",ss); return 0; } ------------------------------------ ◎2-------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss[0]='A'; ss[1]='B'; ss[2]=0; printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎3------------------------------- #include<stdio.h> #include<string.h> int main(void) { char ss[10]; strcpy(ss,"AB"); printf("ss=%s\n",ss); return 0; } ----------------------------------- ◎4------------------------------- #include<stdio.h> int main(void) { char ss[10]; ss="AB"; printf("ss=%s\n",ss); return 0; } ---------------------------------- 以上4つのプログラムで、◎2と◎3は正常に動くと理解できたのですが、何故、◎1は正常に動き、◎4は「'const char [3]' から 'char [10]' に変換できません。」といったようなエラーが出てしまうか分かりません。 教えていただければ嬉しいです。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
◎1 >char ss[10]="AB"; 配列ss[]の定義と初期化を同時に行なっている例です。 別の書き方をすると、 char ss[10] = { 'A', 'B', '\0' }; となり、実質的に◎2と同じです。 ◎4 >ss="AB"; 配列名は、その配列の先頭要素のアドレスです。 ss[]を配列として確保しているため、先頭要素のアドレスssを書き換えることはできません。 ss = "AB"; という文は、メモリー中のどこかにある文字列リテラル"AB"のアドレスを、 書き換えることのできないssに代入しようとしているため、エラーが出ます。
その他の回答 (7)
- Rou_Jin
- ベストアンサー率44% (11/25)
6です。 さっき気づきました... こんなことが出来れば、strcpyとかいらなくなってしまいます。 この4年ほどプログラミングしていないので、すっかり忘れていました。すみません。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
>◎1 >char ss[10]="AB"; これは、charの配列の初期化の「例外的な書き方」です。 本来、この配列は char ss[10]={ 'A', 'B', '\n', 0, 0, 0, 0, 0, 0, 0 }; と書くか、後半を略して char ss[10]={ 'A', 'B', '\n', }; と書かなくてはいけません。 このように要素を1文字づつ書くのでは「面倒臭い」ので、以下のような「例外的に、簡単な書き方を許す」事にしました。 char ss[10]="AB"; これが「◎1が許される理由」です。 >◎4 >char ss[10]; >ss="AB"; これは int ii=10; と int ii; ii=10; が同じで、どっちで書いてもOKだから char ss[10]="AB"; と char ss[10]; ss="AB"; も同じなのだろう、と思ってやってみたら、エラーになっちゃって悩んだ、と言う事でしょうか? 「char ss[10]のss」と「int iiのii」は別物です。 「int iiのii」と同じなのは「char ss[10]のss[0]やss[1]など」です。 Cでは「式に使える物」が「lvalue」と「rvalue」の2つあり、それぞれ ・lvalue 代入式の左辺(代入する先)に置ける値のこと ・rvalue 代入式の左辺(代入する先)に置けない値のこと となっています。 先ほどのiiやssをlvalueとrvalueに分類すると ・lvalue ii、ss[0]、ss[1]…ss[9] ・rvalue ss、"AB"や10などの定数 となります。 「ii=10;」は「lvalue=rvalue」と言う代入式なので許されます。 「ss="AB";」は「rvalue=rvalue」となり、rvalueが代入式の左辺にあるので許されません。 「ss="AB";」は「"DEF"="ABC";」とか「20=ii+10;」と書くのと同じで、コンパイラに「それは無理」と怒られます。 以下蛇足。 ANo.6の >*ss = "AB"; でもOKだと思います(確認はしていません) >これだと「配列ss[10]のポインタアドレスssが指し示す領域の内容 >(要するに配列ss[10])を"AB"にする」といった意味になります。 について。 これは期待した結果にはなりません。 *ss = "AB"; の意味は ss[0] = "AB"; であり、ssの最初の要素(つまりss[0])に代入するだけです。 ss[1]やss[2]には、何も代入されません。 以下、蛇足の蛇足。ここ以下、混乱の元になるので、質問者さんは読まないで置くか、読んでも「ふ~ん」と思うだけにして、忘れて下さい。 ANo.6の回答のような「無理矢理に代入」なら「文字列の長さに限界」はあるけど char ss[10]; *((double *)ss) = *((double *)"DE"); って言う方法もあります。 これは「かなりトリッキーな方法」なので、実行環境によっては「何が起こるか判らない」です。
お礼
>「ii=10;」は「lvalue=rvalue」と言う代入式なので許されます。 >「ss="AB";」は「rvalue=rvalue」となり、rvalueが代入式の左辺にあ>るので許されません。 >「ss="AB";」は「"DEF"="ABC";」とか「20=ii+10;」と書くのと同じ >で、コンパイラに「それは無理」と怒られます。 上の記述納得できました。 代入先に指定できない式に代入しようとしていたという事ですね。 ありがとうございました。
- Rou_Jin
- ベストアンサー率44% (11/25)
*ss = "AB"; でもOKだと思います(確認はしていません) これだと「配列ss[10]のポインタアドレスssが指し示す領域の内容 (要するに配列ss[10])を"AB"にする」といった意味になります。
- xceu
- ベストアンサー率25% (2/8)
そうですね、ポインタ==先頭アドレスですからね。 配列も関数も構造体も先頭アドレスからの参照ですから、 機会があればアセンブラも勉強してみるといいですよ、ポインタへの理解が っぐっと深まると思います。
- xceu
- ベストアンサー率25% (2/8)
こんな使い方もありますよ。 #include <stdio.h> int main(void) { char *ss; ss="abcdefg"; printf("%s\n",ss); return 0; } まあいろいろと試してみるのもおもしろいですね。
お礼
ご回答ありがとうございます。 これは、ポインタssに文字列abcdefgの先頭のアドレスを渡して、表示しているという感じですか?
- asuncion
- ベストアンサー率33% (2127/6289)
>#2さん >基本的に宣言後の配列型変数への文字列の代入はできません。 基本的にできないという風に書かれてしまうと、 strcpy()を使う方法が何だか例外的であるように見えてしまいます。 実際には例外でも何でもなくて、普通に使う方法です。 誤解なさらないようにしてください。念のため。>質問者さん
お礼
>strcpy()を使う方法が何だか例外的であるように見えてしまいます。 >実際には例外でも何でもなくて、普通に使う方法です。 説明の補足をしてもらいありがとうございます。 以上の記述、しっかりと頭に入れておきます。
- xceu
- ベストアンサー率25% (2/8)
基本的に宣言後の配列型変数への文字列の代入はできません。 代入は宣言時にするのです。例えば #include<stdio.h> int main(void) { char ss[10]="AB"; printf("ss=%s\n",ss); return 0; } てかんじで。 ちなみに宣言後に代入したいのであれば #include<stdio.h> #include<string.h> // strcpyをつかう上で必要 int main(void) { char ss[10]; strcpy(ss,"AB"); // この部分 printf("ss=%s\n",ss); return 0; } というかんじで文字列関数をつかうとよいでしょう。
お礼
>宣言後に代入したいのであれば >strcpy(ss,"AB"); をつかう この記述納得できました、ありがとうございます。
お礼
書き換えられない配列ssの先頭アドレスを「ss="AB";」としてしまうと、"AB"の先頭アドレスを代入してしまう事になってしまうという感じですかね? それにともない、配列ss[]の定義と初期化を同時に行えば良いという事ですね。