- ベストアンサー
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だと実行できない理由がわかりません。 初歩的なことですいませんが、教えていただけると嬉しいです。
- みんなの回答 (15)
- 専門家の回答
質問者が選んだベストアンサー
>intは文字列は扱えないということなのでしょうか? >以上intだと実行できない理由がわかりません。 →"789”は 文字列リテラルと呼ばれchar型の配列としてC言語仕様で決められ,初期化する場合もchar型の配列とされています。 この為「int ss[4]="789";」はコンパイルエラーとなることが予想されます。 int型の配列に文字コードを格納したいのであれば「int ss[]={'7','8','9','\0'};」とすべきで,扱いにくいですがint型配列で文字列を格納したことになります。 >printf("%c\n%d\n",*p,*p); >この*pは7のアドレスの値を指しているのに、 >55× 256^0+56×256^1+57×256^2+0×256^3 >以上の'8''9'も含めた計算が行われたのかが疑問としてあります。 →まずこの例はC言語仕様とは関係なく,VC++環境(CPU x86系)でのメモリ操作がからんだ結果ですので全ての実行環境で同じ結果にはならないことを注意して下さい。 「int *p = (int *)"789";」はchar型の配列で'7','8','9','\0'の順に文字コードが格納されその先頭アドレスを「int*型」として「int *p」に代入し初期化されています。 この「p」のアドレスが仮に0x1000とした場合,次の様に文字列が格納されています。この実行環境の'0'~'9'の文字コードは0x30~0x39が割り当てられています。 0x1000 0x37 ('7') <--- int *pの指すアドレス 0x1001 0x38 ('8') 0x1002 0x39 ('9') 0x1003 0x00 ('\0') ここで「int *型」の「p」を「*p」とすると,この環境の「int型」は32ビット(4バイト)ひと固まりとして処理され「*p = 0x00393837;」と結果が得られます。順番通り取り出すと「0x37383900」となるように考えるのが自然かもしれませんが,「CPU x86系」ではこの様な取り出し方ではなくローバイトから取り出し「0x00393837」となります。 「0x00393837」は10進数で「3749943」ですのでこの結果になります。 ちなみに「printf("%c\n%d\n",*p,*p);」の最初の「%c」で「7」と出力されていましたが,*pは「0x00393837」ですので下位8ビット「0x37」が出力されたことが予測されます。 >p=(int *)"789";のようにint型にしてpにアドレスを渡すと、他の回答者さんにも質問したのですが、' 'の1つを1バイトのメモリと考えると、 >「'7','<不定>','<不定>','<不定>'」・・・や >「' 7 ',' 8 ',' 9 ',' 0 '」 >ではなく、'' ''1つを4バイトとして、 >「'' 7 ''」・・・ >のように、4バイトの領域1つ1つに'7''8''9'が入っていくという事なのですかね?? →いいえ,(int *)でキャストしてもchar型の配列で格納されていますので1バイト毎にそれぞれ格納され合計で4バイトとなります。 >あともう1つ疑問なのですが、 >>この4バイトの数値をint型として読み込むと >>55×256^0+56×256^1+57×256^2+0×256^3となります。 > >という回答をもらった部分なのですが、1バイトが256でintは4バイトという事で、256の部分は、256^4の値が入るとまだ完全に理解していないので、そう思ってしまったのですが、 >>55×256^0+56×256^1+57×256^2+0×256^3 >の部分を説明していただけると助かります。 →4つのキーワードから考えると「256^0」,「256^1」,「256^2」, 「256^3」の4つが対応します。 まず式を全て16進数に変えて256^n(重み)はどの様なものか確認します。 3749943(0x00393837) = 55(0x37)*256^0+56(0x38)*256^1+55(0x39)*256^2+0(0x00)*256^3 0x00393837 = 0x37*0x01(256^0)+0x38*0x0100(256^1)+0x39*0x010000(256^2)+0x00*0x01000000(256^3) ・次に足す順番を入れ替えて計算結果と見比べます。 0x00393837 = 0x00*0x01000000 + 0x39*0x010000 + 0x38*0x0100 + 0x37*0x01 0x00393837 = 0x00000000 + 0x390000 + 0x3800 + 0x37 このように8ビット毎に重みを付けて計算しています。
その他の回答 (14)
- cistronezk
- ベストアンサー率38% (120/309)
回答3です。修正します。 誤: >cp++は1バイト増加しますが、ip++は4バイト増加するはずです。 正: cp++は1増加しますが、ip++は4増加するはずです。 両者がアドレス「1」番地を指していたら、インクリメントによってcp++は「2」を、ip++は「5」を指すということです。
- cistronezk
- ベストアンサー率38% (120/309)
char *cp; int *ip; 両者の違いはポインタをインクリメントしたときに明確になります。 cp++は1バイト増加しますが、ip++は4バイト増加するはずです。 一方、文字列(たとえば"12345")は連続する(例では6バイトの)メモリの中で1文字1バイト割り当てられます。 int *ip = "12345"; これがもし可能だとすると、 (ip+0)は、'1'のアドレスを指し、(ip+1)は'5'のアドレスを指すことになります。これでは、各文字を操作できません。 また*(ip+0)の値は「'1','2','3','4'」、*(ip+1)は「'5','\0','<不定>','<不定>'」となります。これも使い物になりそうもありません。 操作できるようにするためには、 char *cp = "12345"; int *ip = "12345"; とでメモリの割り当て方を変えれば可能でしょう。しかし実装はおそらく大変ですし、実現してもそれを使うプログラマは混乱するはずです。 以上が「int *ip = "12345";」ができない理由の一部かと思います。
お礼
ご回答ありがとうございます。 int *ip = "12345";が可能だとして、intなので4バイトごとに'1''2''3''4''5'がメモリに格納されないのですかね? やはり1バイトずつに格納しようとするのでしょうか? *(ip+0)の値「'1','<不定>','<不定>','<不定>'」 *(ip+1)の値「'2','<不定>','<不定>','<不定>'」 といったような感じになるから、やはりダメなのかな。。
- N-Ishikawa
- ベストアンサー率25% (1/4)
(2)の「p="789";」は"789"が格納されているアドレスをpに代入しています。 アドレスは型が何であろうとアドレスそのもののサイズは変わりません。 なのでpに代入できます。 ここで *pは pから始まる 2バイトもしくは4バイトを表します。 #intは 型の大きさがイマイチ不明なので、カウンタ以外には使用しない方が無難です。 で、その後のprintf()には *pが表す数値を渡すのですが、書式で %cを指定しているので 下位1バイトを文字として表示することになります。 ですのでうまくいっているように見えるのです。 試しに以下を実行してみるといいかと思います。 printf("%c\n%d\n",*p,*p); '7'の文字コードは10進数で55なのですが、恐らく14391が表示されるかと思います。 (1)は「int ss[4]={'7','8','9','\0'};」と書けばいいかと思います。 文字列はあくまで文字列ですので intではなく、charを使用するようにしましょう。 intでもある程度うまく動作するのは char型でも内部では 結局intにcastして 使われているからです。 だからといって、プログラム作成者の方で適当に intとcharを混ぜて使用すると イマイチうまく動かない、コンパイルできない、って感じになるんですよね。
お礼
ご回答ありがとうございます。 ◎2に関しては、まず「int *p;」ではエラーが出るので、「char *p;」に変え、「printf("%c\n%d\n",*p,*p);」を追加し実行してみたところ、 7 55 が出力されました。 文字としての7、10進数としての55という感じですかね?? ◎1については、 >文字列はあくまで文字列ですので intではなく、charを使用するようにしましょう。 以上のご回答しっかり頭に入れて起きます!
- asuncion
- ベストアンサー率33% (2127/6289)
'a' の話と "a" の話とを混同されているようです。 前者は、char型でもint型でも扱えます(厳密にはint型)。 後者は、char *型です。int *型ではありません。
お礼
ご回答ありがとうございます。 'a'だと一文字を代入ということで、"a"だと文字列リテラルと考え先頭アドレスを代入という考えですかね?
- 1
- 2
お礼
ご回答ありがとうございます。 >(int *)でキャストしてもchar型の配列で格納されていますので1バイト毎に >それぞれ格納され合計で4バイトとなります。 以上のご回答がどうも理解できないのですが、 printf("*p=%c\n*p+1=%c\n",*p,*p+1); printf("p=%p\np+1=%p\n",p,p+1); 以上を入力すると、1つ目のprintfで、 *p=7 *p+1=8 出力されるのはわかるのですが、 2つ目のprintfは、 p=0042002C p+1=00420030 と出力され(C→0なので)'8'は次の4バイト目に格納されていると理解し、1バイト毎にそれぞれ格納とは違うと理解してしまったのですが、違いますかね? あと、 >「int *型」の「p」を「*p」とすると,この環境の「int型」は32ビット >(4バイト)ひと固まりとして処理 とあるのですが、この記述がどうも理解できません。 以上ご回答いただけると嬉しいです。