• ベストアンサー

配列について

初歩的な質問ですいませんが、質問よろしくお願いします。 ◎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]' に変換できません。」といったようなエラーが出てしまうか分かりません。 教えていただければ嬉しいです。

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

  • ベストアンサー
  • asuncion
  • ベストアンサー率33% (2126/6287)
回答No.1

◎1 >char ss[10]="AB"; 配列ss[]の定義と初期化を同時に行なっている例です。 別の書き方をすると、 char ss[10] = { 'A', 'B', '\0' }; となり、実質的に◎2と同じです。 ◎4 >ss="AB"; 配列名は、その配列の先頭要素のアドレスです。 ss[]を配列として確保しているため、先頭要素のアドレスssを書き換えることはできません。 ss = "AB"; という文は、メモリー中のどこかにある文字列リテラル"AB"のアドレスを、 書き換えることのできないssに代入しようとしているため、エラーが出ます。

muffler
質問者

お礼

書き換えられない配列ssの先頭アドレスを「ss="AB";」としてしまうと、"AB"の先頭アドレスを代入してしまう事になってしまうという感じですかね? それにともない、配列ss[]の定義と初期化を同時に行えば良いという事ですね。

その他の回答 (7)

  • Rou_Jin
  • ベストアンサー率44% (11/25)
回答No.8

6です。 さっき気づきました... こんなことが出来れば、strcpyとかいらなくなってしまいます。 この4年ほどプログラミングしていないので、すっかり忘れていました。すみません。

  • chie65535
  • ベストアンサー率43% (8516/19360)
回答No.7

>◎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"); って言う方法もあります。 これは「かなりトリッキーな方法」なので、実行環境によっては「何が起こるか判らない」です。

muffler
質問者

お礼

>「ii=10;」は「lvalue=rvalue」と言う代入式なので許されます。 >「ss="AB";」は「rvalue=rvalue」となり、rvalueが代入式の左辺にあ>るので許されません。 >「ss="AB";」は「"DEF"="ABC";」とか「20=ii+10;」と書くのと同じ >で、コンパイラに「それは無理」と怒られます。 上の記述納得できました。 代入先に指定できない式に代入しようとしていたという事ですね。 ありがとうございました。

  • Rou_Jin
  • ベストアンサー率44% (11/25)
回答No.6

*ss = "AB"; でもOKだと思います(確認はしていません) これだと「配列ss[10]のポインタアドレスssが指し示す領域の内容 (要するに配列ss[10])を"AB"にする」といった意味になります。

  • xceu
  • ベストアンサー率25% (2/8)
回答No.5

そうですね、ポインタ==先頭アドレスですからね。 配列も関数も構造体も先頭アドレスからの参照ですから、 機会があればアセンブラも勉強してみるといいですよ、ポインタへの理解が っぐっと深まると思います。

  • xceu
  • ベストアンサー率25% (2/8)
回答No.4

こんな使い方もありますよ。 #include <stdio.h> int main(void) { char *ss; ss="abcdefg"; printf("%s\n",ss); return 0; } まあいろいろと試してみるのもおもしろいですね。

muffler
質問者

お礼

ご回答ありがとうございます。 これは、ポインタssに文字列abcdefgの先頭のアドレスを渡して、表示しているという感じですか?

  • asuncion
  • ベストアンサー率33% (2126/6287)
回答No.3

>#2さん >基本的に宣言後の配列型変数への文字列の代入はできません。 基本的にできないという風に書かれてしまうと、 strcpy()を使う方法が何だか例外的であるように見えてしまいます。 実際には例外でも何でもなくて、普通に使う方法です。 誤解なさらないようにしてください。念のため。>質問者さん

muffler
質問者

お礼

>strcpy()を使う方法が何だか例外的であるように見えてしまいます。 >実際には例外でも何でもなくて、普通に使う方法です。 説明の補足をしてもらいありがとうございます。 以上の記述、しっかりと頭に入れておきます。

  • xceu
  • ベストアンサー率25% (2/8)
回答No.2

基本的に宣言後の配列型変数への文字列の代入はできません。 代入は宣言時にするのです。例えば #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; } というかんじで文字列関数をつかうとよいでしょう。

muffler
質問者

お礼

>宣言後に代入したいのであれば >strcpy(ss,"AB"); をつかう この記述納得できました、ありがとうございます。

関連するQ&A

  • 配列やポインタに文字列を設定することについて

    ◎1------------------------- #include<stdio.h> int main(void) { char ss[80]; scanf("%s",ss); printf("%s\n",ss); return 0; } ---------------------------- ◎2--------------------------- #include<stdio.h> int main(void) { char *ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- ◎3---------------------- #include<stdio.h> int main(void) { char *ss; ss="abcde"; printf("%s\n",ss); return 0; } ------------------------- 以上3つプログラムで疑問をいだいたのですが、 まず◎1で、これは例えば、 cahr ss[80]="abc"; のように配列ssに文字列"abc"そのものを入れているのか、 char *ss="xyz"; のようにまず"xyz"という文字列をメモリ上のどこかに設定し、その先頭番地をssに代入しているのか、どちらの考えでいいのかわかりません。 次に、◎2、3ではどちらも正常に実行できたのですが、特に◎3で「ss="abcde";」と記述していますが、ssにはアドレスを代入するという認識かあるのですが、文字列定数を代入しても問題ないのか?という疑問があります。 教えていただけたら嬉しいです。

  • ポインタについて

    今初めてポインタというものを勉強しております。 よろしくお願いします。 ◎1---------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt; pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } --------------------------------------- ◎1のようにmydtのアドレスをポインタptに代入すれば、このプログラムは正常に動きました。 ◎2----------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } ---------------------------------------- ◎2で「int *pt=&mydt;」があまりどういう意味かはわかりませんが、これも正常に動きました。 ◎3------------------------------------ #include<stdio.h> int main(void) { int mydt=1234; int *pt; *pt=&mydt printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } -------------------------------------- ◎3のように◎2と違って「*pt=&mydt」の代入を後から行うと、「'=' : 'int *__w64 ' から 'int' に変換できません。」といったようなエラーが起きてしまいます。 ◎1と◎2の違い、後何故◎3はダメなのかがわかりません。 教えていただけると嬉しいです。 後補足として、配列とポインタについてですが、 ◎4------------------------------ char ss[10]="ABCDE"; char *ssp=ss; --------------------------------- ◎5---------------------------- char ss[10]="ABCDE"; char *ssp; ssp=ss; -------------------------------- ◎4と◎5も同じような事だとは思いますが違いを教えていただけると嬉しいです。 よろしくお願いします。

  • int型とchar型について

    C言語初心者です。 よろしくお願いします。 ◎1----------------------- #include<stdio.h> int main(void) { int ss[4]="789"; printf("%c\n",ss[0]); return 0; } --------------------------- ◎2----------------------- #include<stdio.h> int main(void) { int *p; p="789"; printf("%c\n",*p); return 0; } --------------------------- ◎1、◎2の2つのプログラムについて疑問があります。 ◎1の「int ss[4]="789";」と◎2の「int *p;」のintの部分は今まで、何の疑問も抱かず、「char」として入力していました。 そこでchar型は1バイトの整数、int型は4バイトの整数ということで容量が違うだけで、intとしても大丈夫だろうと思ったのですが、 ◎1では、「'initializing' : 'char [4]' から 'int [4]' に変換することはできません。」とエラーが出て、◎2では「'char [4]' から 'int *' に変換することはできません。」とエラーが出ます。 intは文字列は扱えないということなのでしょうか? 以上intだと実行できない理由がわかりません。 初歩的なことですいませんが、教えていただけると嬉しいです。

  • 配列要素内の数値

    #include <stdio.h> int main(void) { int arr[1]={123456789}; int *x[1]; *x = arr; printf("%d ",*(x[0])); /* 123456789 と表示*/ return 0;} 実行すると123456789と表示されるまでは分かるのですが、*(x[0])の部分を別の書き方にして、arr[0]に入ってある「123456789」という数値の千の値である6という数値のみを取り出して、表示することは可能なのでしょうか?(6000と取り出したいのではなく、6として取り出したい) 次のように数値を文字列の一つ一つを扱うかのように、扱いたいのです。*(x[0])の部分の変更だけで6を取り出せるような方法はありますか? #include <stdio.h> int main(void) { char *arr[]={"pen"}; printf("%c\n",*(arr[0]+0)); printf("%c\n",*(arr[0]+1)); printf("%c\n",*(arr[0]+2)); return 0;}

  • ポインタにによる値の表現と文字列の表現について

    ◎1------------------------------ #include<stdio.h> int main(void) { char *pt="ABC"; printf("pt=%s\n",pt); char dt[10]="ABCDE"; char *pp; pp=dt; printf("pp=%s\n",pp); return 0; } -------------------------------------- ◎2---------------------------------- #include<stdio.h> int main(void) { char *pt="ABC"; printf("*pt=%s\n",*pt); char dt[10]="ABCDE"; char *pp; pp=dt; printf("*pp=%s\n",*pp); return 0; } ----------------------------------- ◎3--------------------------------------- #include<stdio.h> int main(void) { int ary[5]={111,222,333,444,-1}; int* pt=ary; while(1){ printf("%d ",*pt); ++pt; if(*pt==-1){ break; } } puts(""); return 0; } ----------------------------------------------- 以上3つのプログラムで、◎1はprintfで「*」が付いてなく、正常に実行出来ました。 ◎2はprintfで「*」が付いてなく、エラーは出ませんが、文字列が表示されませんでした。 ◎3は文字列ではなく値ですが、printfで「*」が付いていて正常に実行できます。 これは、値の場合は「*pt」とすることで、ptのアドレスに値を代入しているという事で、「printf("%d ",*pt);」で実行できたということですかね? 文字列の場合は、先頭のアドレスを渡すだけなので、「printf("pt=%s\n",pt);」のようにしてアドレスを参照しないとダメであるということですか? ◎2で「printf("*pt=%s\n",*pt);」としてしまうと、何が起きてしまうのかわかりません。 以上、教えていただけると嬉しいです。

  • 文字列の連結するプログラム

    独学でプログラミングをやっているんですが2つ文字列を1つにする方法がよくわかりません。(1)のプログラムは(b+3)のところは文字の長さを指定しているからだめで(2)はstrcpyやstrcatなどのコマンドを使わずにやるそうです。While分とかでやるんでしょうか?教えてください。 (1) #include <stdio.h> int main (void){ char spelA[] = "abc"; char spelB[] = "def"; char spelC[20]; int a,b; spel[6]=0; for(a=0;spel[a]!=0;a++){ spelC[i] = spelA[i]; }; for(b=0;spelB[b]!=0;b++){ spelC[b+3] = spelB[b]; }; printf("%s\n",spelC); return(0); }; (2) #include <stdio.h> #include <string.h> int main (void){ char spelA[] = "abc"; char spelB[] = "def"; char spelC[20]; strcpy(spelC,spelA); strcat(spelC,spelB); printf("%s\n",spelC); return(0); }

  • ASCIIコード入力

    プログラムを作っていてどうしてもわからなくなりまして… #include <stdio.h> int main(void) { char c; c=38; printf("%c\n",c); return 0; } この場合は&が出てくるからいいんですけど… #include <stdio.h> int main(void) { char c; scanf("%c",&c); printf("%c\n",c); return 0; } この場合は97をscanすると9が出てきます。ASCIIコード入力でaを表示させたいんですが、何が間違っているのでしょうか? 初心者なもので…お願いしますm(__)m

  • ポインタと配列

    初歩的な質問なんですが、 #include <stdio.h> #include <string.h> main() { char ss[10]; char *p; strcpy(ss,"ABCDE"); p=ss; while(*p){ *p=*p+1; ++p; } printf("ss=%s\n",ss); } で実行結果が ss=BCDEF になります。 while(*p){ *p=*p+1; ++p; } の部分がどうしても理解できません。 参考書にも、解説が載ってなくて困っています。 ご教授宜しくお願いします。

  • C言語の初心者です。これを実行してみてください。

    「a」って打ち込んだら「a」ってでましたか? #include<stdio.h> int main(void){ char a; printf("aaa\n"); scanf_s("%c", &a); printf("%c", a); return 0; }

  • C言語のint型の配列が分かりません

    #include<stdio.h> int main(void) { int str[ ]={0,1,2} printf("%s\n", str); return 0; } というプログラムをC言語でつくってみましたが動きません.(012と表示されて欲しかったのですが) int str[ ]={1,2,3}の部分をchar str[ ]={'0','1','2'}とすれば動きます. そこで質問なのですが, printf("~%s~", (配列名));  はchar型の配列にしか適応できないのですか? ※追記 puts関数の定義は int puts (const char *str); であるそうなので char型の仮引数にはchar型のアドレスを渡さなければいけません. ではprintf関数の定義は一体どんなものなのですか?

専門家に質問してみよう