- ベストアンサー
ポインタにによる値の表現と文字列の表現について
◎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);」としてしまうと、何が起きてしまうのかわかりません。 以上、教えていただけると嬉しいです。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
◎1について printfの%sは「ポインタ」を受け取り、そのポインタの先にある文字列を表示します。 >char *pt="ABC"; 「ptはcharのポインタであり、そのポインタの先にある文字列は"ABC"だ」として、宣言と初期化を行っています。 >printf("pt=%s\n",pt); 「pt」は「ポインタ」であり「そのポインタの先にある文字列は"ABC"」です。なので「ABC」が表示されます。 >char dt[10]="ABCDE"; 「ptはcharの配列であり、その配列の各要素はA,B,C,D,E,\0だ」として、宣言と初期化を行っています。 >char *pp; 「ppはcharのポインタである」と宣言を行っています。 >pp=dt; 「ppが指すポインタは、dtを指せ」と代入しています。結果、ppのポインタはdtを指し、ppのポインタの先にある文字列は"ABCDE"になります。 >printf("pp=%s\n",pp); 「pp」は「ポインタ」であり「そのポインタの先にある文字列は"ABCDE"」です。なので「ABCDE」が表示されます。 ◎2について printfの%sは「ポインタ」を受け取り、そのポインタの先にある文字列を表示します。これは◎1も◎2も変わりません。 >char *pt="ABC"; >char dt[10]="ABCDE"; >char *pp; >pp=dt; は◎1と同一なので説明を省きます。 >printf("*pt=%s\n",*pt); >printf("*pp=%s\n",*pp); どちらも、%sに対して「指してるポインタの中から取り出した文字」つまり「A」を渡しています。「文字A」はポインタではありません。 しかし、printfは「文字A」(アスキーコードで0x41、65である可能性が高い)を「ポインタだと信じて動く」ので「メモリの65番地にある内容を文字列だと思って表示しよう」とします。 もし「メモリの65番地にある内容が0」なら「1文字も表示せずに文字列の終りが来る」ので、何も表示しません。 もし「メモリの65番地から始まって、ずっ~と、数メガバイト、文字列の終りを示す0が無かった」としたら「メモリの65番地から数メガバイトに渡って、延々と文字列として表示し続け、プログラムを止められなくなる」と言う事態に陥った筈です。 今回は「偶然、何も表示しなかっただけ」で済みましたが、下手したらパソコンを強制リセットするしか無い状態になってたかも。 ◎3について printfの%dは「数値」を受け取り、その数値を表示します。 >printf("%d ",*pt); ポインタとか*とはは何の関係もありません。「数値」を受け取るのだから「数値」を渡さなければなりません。 ptは「intを指してるポインタ」ですから、printfの引数に「*pt」と書くと「ポインタが指してる所にあるintの数値」が取り出されます。 そして、その「intの数値」がprintfに渡され、表示されます。 ここで注意しないとならないのは [[[ printfは、渡された物がすべて正しいと思って、疑いもしない ]]] と言う事です。 引数が足りなかったり、引数に指定した物の内容が変でも、何も疑わず、言われた通りに表示しようとします。 -------- 一連の質問を見るに、質問者さんは「ポインタや配列で、*が付いている時、宣言、初期化、代入、参照がきちんと区別が出来ていない」ようです。 Cでは「見た目に、まったく同じ書き方」をしていても「それがどこに書いてあるかとか、前後の文脈の繋がりとかで、まったく全然別の意味」になってしまう文があります。 また、printfの%sと%dのように「見た目にそっくりだけど、まったく全然別のモノを要求してる」という事もあります。 この辺りの「見極め」が出来るまで「似たような書き方だから、同じように出来る筈」と思ってはいけません。 と言うか「似たような書き方だから、同じように出来る筈」と思ってしまうのが「質問者さんの悪い所」です。 Cでは「1文字でも違えば、何かが絶対に違う筈」という「疑う能力」が要求されます。
その他の回答 (4)
- asuncion
- ベストアンサー率33% (2127/6289)
>(1)の*ptでアドレスに格納している内容、"ABC"を参照できると思ったんのですが、出来ません。。 私の先の回答には誤解を招きかねない箇所がありました。 pt = "ABC"; という文で、"ABC" の先頭文字 'A' のアドレスが pt に入ります。 その後、"ABC" 全体を取得するには、*pt ではなく pt を使います。 *pt は、pt が指している文字列 "ABC" の先頭文字 'A' 「だけ」を取得します。
お礼
>*pt は、pt が指している文字列 "ABC" の先頭文字 'A' 「だけ」を取>得します。 上記の内容理解できました。 確かに「printf("*pt=%c\n",*pt);」として、'A'は取得できていました。ありがとうございます。
- asuncion
- ベストアンサー率33% (2127/6289)
>値の場合は「*pt」とすることで、ptのアドレスに値を代入しているという 理解が正確ではありません。 ptがポインタ変数の場合、ptの値は、何かの変数のアドレスです。 そのとき、*ptは、その、何かの変数のアドレスに格納している内容を参照します。 これは、ptがchar *型であろうがint *型であろうが他の何型であろうが同じです。
お礼
ご回答ありがとうございます。 char *pt="ABC"; printf("*pt=%s\n",*pt); ////(1) (1)の*ptでアドレスに格納している内容、"ABC"を参照できると思ったんのですが、出来ません。。 やはり文字列の場合、ptにしてアドレスを参照しないとダメなのですかね?
- xceu
- ベストアンサー率25% (2/8)
> ◎2はprintfで「*」が付いてなく、エラーは出ませんが、文字列が表示されませんでした。 #include<stdio.h> int main(void) { char dt[10]="ABCDE"; char *pp; // ポインタ型の変数を使いますよ! pp=dt; printf("*pp=%c\n",*pp); // 値を渡している(dt[0]) printf("*pp=%s\n",pp); // アドレスを渡している return 0; } 宣言時の*と式の中の*は意味が違うっていうことですね。
- Yanch
- ベストアンサー率50% (114/225)
printf()の書式と、対応する引数のデータ型を調べれば、答えは明らかだと思いますが、 リファレンスとか参照されているのでしょうか。 "%s"は文字列に対応する書式制御文字で、char*を引数として受け取り処理します。 "%d"は整数に対応する書式制御文字で、intを引数として受け取りしょりします。 それぞれ、対応するデータ型で引数を受け渡す事が決められていますので、 間違った引数で実行した場合、printf()はどのような動作になるのかは不明です。
お礼
>printfの%sは「ポインタ」を受け取り、そのポインタの先にある文字 >列を表示します。 >printf("*pp=%s\n",*pp); >どちらも、%sに対して「指してるポインタの中から取り出した文字」 >つまり「A」を渡しています。「文字A」はポインタではありません。 >しかし、printfは「文字A」(アスキーコードで0x41、65である可能性>が高い)を「ポインタだと信じて動く」ので「メモリの65番地にある >内容を文字列だと思って表示しよう」とします。 上記の内容等理解できました。 細かくありがとうございます。 後、ご指摘いただいた辺りがまだ、ずばり欠点だと思います。 そこをしっかり把握して努力していきます!