- 締切済み
Cでは文字列をどのように認識するのでしょうか?
C言語には文字列型というものは存在しないと教わりました。 文字列の終わりはヌル文字で認識できますが、 文字列型というものが存在しないのに何故次のバイトを読もうとするのですか? たとえばchar str[] = "abc";、あるいはchar *p = "abc";とあったとして printf(str);あるいはprintf(p); でなぜabcが出力されるのでしょうか?なぜaの次にbがbの次にcがあるとわかるのでしょうか? char型で先頭アドレスが渡された場合、ヌル文字を見つけるまでアドレスをインクリメントし続けるという決まりでもあるのでしょうか? それに文字列型というものが存在しないなら''と""を分ける意味もないのでは??
- みんなの回答 (7)
- 専門家の回答
みんなの回答
- TERABIT
- ベストアンサー率44% (4/9)
>私が言いたいのは文字列型が存在しないのに >なぜコンパイラはaの次にbがあるのか判断できるのか >という話です。 他の方が解説しているので、もうわかったかもしれませんが、 コンパイラは、aの次にbがあるかどうかなんて判断はしません。 char str[]="abc"; と書けば、str という名前で確保した領域 4byteを、'a','b','c','\0' で埋めるという事だけです。 char str[3] = "abc"; だったら、str という名前で確保した領域 3byteを、'a','b','c' で埋めるという事だけです。(C++ではエラーです) 配列だから、連続した領域に、順番に各データが格納されている事は、コンパイラは認識するでしょうが、 そのデータが何であるかは、プログラムを書いた人が指定した通りに認識するだけです。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
>ところでchar c = 'a'; >とした場合、aという文字定数をメモリ領域のどこかに格納して >それを変数cに渡して初期化しますがこのときcに渡されるのは >いったいどういう情報ですか?何を渡しているんでしょうか? >内部的にいったいどういう処理がされてるんでしょうか・・・ ・変数cが関数内で定義されたオート変数の場合 関数の最初に「変数cに0x61を代入する」と言う代入文が勝手に追加されるだけ。 文字定数がメモリのどこかに置かれたりはしない。 単に、 char c = 'a'; と書くと、 char c; c = 'a'; と書いた事になるだけ。代入文を自分で書いたのと一緒。 ・変数cが関数内で定義されたstatic変数や、関数外で定義された変数の場合 メモリのどこかに0x61が置かれ、そのメモリそのものが変数cになるだけ。 変数cに渡される物は何もないし、変数cを初期化する代入文がどこかに追加されたりはしない。 単に「最初からそこにあって、何もしないうちから、中身が0x61になっているだけ」である。 変数cの値を参照すると「最初から0x61が置かれているメモリからデータを取り出すだけ」になる。
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
コンパイラの言語仕様には「文字の配列」しかありません。言語仕様に文字列と言う物は存在しません。 コンパイラは「書いてあるソースコードをコンパイルするだけ」であり、ソースコードのどこかに "abc" と書いてあると、それを 1番目の要素⇒'a' 2番目の要素⇒'b' 3番目の要素⇒'c' 4番目の要素⇒'\0' のような「文字の配列」とみなし、値として「配列の先頭ポインタ」を持つようにコンパイルします。 >printf(str);あるいはprintf(p); >でなぜabcが出力されるのでしょうか?なぜaの次にbがbの次にcがあるとわかるのでしょうか? 「printfが、そういうふうに作ってあるから」です。 言い換えれば「配列の先頭アドレスが与えられたとして、配列の先頭から順に処理して、配列の要素にヌル文字が出て来るまで繰り返すようにプログラミングしてあるだけ」です。 これは「関数がそういうふうにプログラミングされているだけ」の話であって「C言語やCコンパイラには、まったく関係の無い話」です。 つまり「関数の仕様なだけ」であって「C言語の仕様ではない」のです。 >char型で先頭アドレスが渡された場合、ヌル文字を見つけるまでアドレスをインクリメントし続けるという決まりでもあるのでしょうか? 「C言語の言語仕様ではなく、ライブラリ関数の関数仕様」として「charの配列を文字列として代用し、最後の要素にヌル文字文を入れる事で字列列の終りとして代用しよう」と決めたのです。 なので 「C言語の言語仕様には文字列型というものは存在しない」 「ライブラリ関数の関数仕様には文字列が存在する」 と言う事になります。 質問者さんは「C言語の言語仕様」と「ライブラリ関数の関数仕様」が区別できずにゴッチャになっているので、混乱しているのです。 >それに文字列型というものが存在しないなら''と""を分ける意味もないのでは?? その通り。全部「''」で済ます事が出来ます。 実際 char *mes = "Message"; と書いても char mes[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', '\0' }; と書くのと同じです。 てゆ~か、初期の試作版Cコンパイラでは char *mes = "Message"; という書き方は出来ませんでした。文字列は char mes[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', '\0' }; と書かなければいけませんでした。 で、いちいち char mes[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', '\0' }; と書くのは「面倒」なので、言語仕様に char *mes = "Message"; と書いても同じ結果になるような「特例の追加仕様」を加えたのです。 つまり「人間が面倒な思いをしなくて済むように、人間が見て直感的に判るようにする為」と言う理由で --------------------------------------- char mes[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', '\0' }; と書く代わりに char *mes = "Message"; と書いても良い --------------------------------------- と言う言語仕様を加えたのです。 これは「charの配列の記述方法の特例を認めただけ」であって「言語仕様として文字列型を導入した訳ではない」と言う事に注意して下さい。 あくまでも「C言語には文字列型というものは存在しない」と言う言語仕様は変わっていません。
- -Kei
- ベストアンサー率50% (151/299)
>char c = 'a'; メモリ上に変数cの領域をcharのサイズ分確保して、そこを'a'の値(文字コード)で上書き >なぜコンパイラはaの次にbがあるのか判断できるのか 読み取った文字が\0でないから文字列の続きがあると判断できます。 文字列を処理する関数は「文字列の先頭アドレスが渡される」ことと、「文字列の終わりに\0がある」ことを前提に作ってあります。 文字列なのか文字なのかは判断していません。 コンパイラやコンパイラの警告の度合いによって違ってくるかもしれませんが、渡したのがint型でも動いてしまいます。 従って、最後が\0でないただのchar型の配列(c[0]='a'、c[1]='b'、c[2]='c')を渡すと、null文字がないので変数の外まで読みに行ってしまい想定外の動作をします。
- TERABIT
- ベストアンサー率44% (4/9)
char str[] = "abc"; の様な場合、文字列型ではなく、文字型(char型)の配列です。 int num[] = {1,2,3,4,5}; 等の、整数型の配列と同じ扱いです。 文字列の場合、最後の文字のセパレータとして、'\0' で終わる事が多いのと、 char str[] = "abc"; 等と書いた場合、"abc" の3文字+最後'\0' を入れた4文字分の領域が確保されるように決まっていますので、 (というかその方が便利なのでその様に作っているだけ) それに従ったprintf()等の関数が作られただけです。 文字列型を作りたいなら、自前で作ればいいだけです。 typedef struct {char str[256];} string; とか、 typedef struct {size_t len; char str[1]} string; 等の様に自分で作ってしまえばいいだけです。
- TinyPine
- ベストアンサー率30% (719/2386)
char型で先頭アドレスが渡された場合、ヌル文字を見つけるまでアドレスをインクリメントし続けるという決まりでもあるのでしょうか? その通りです。元々機械語には文字列の概念なんかありませんよね。 レジスターに入っているデーターしか扱わないんだから。 人間はそれでは不便なので、ヌルまでの列を文字列とすると定義しただけ。 別にヌルで無くてもそれこそ"でも良かったわけです。 ただ、"は文字として人間が感知する文字ですから、文字列の開始、終了の区別を付ける文字を文字列の中に入れる時は2回繰り替えそうと決めただけ。 No.1の方が書かれている様に、自分で文字列を解析しようとすると、面白いですよ。
お礼
なるほど。やはりそうでしたか。ありがとうございます ところでchar c = 'a'; とした場合、aという文字定数をメモリ領域のどこかに格納して それを変数cに渡して初期化しますがこのときcに渡されるのは いったいどういう情報ですか?何を渡しているんでしょうか? 内部的にいったいどういう処理がされてるんでしょうか・・・
- sakuraitarou
- ベストアンサー率11% (13/118)
なんでって…? コンパイラを作ってみれば理解できると思うよ。 字句解析や構文解析。面白いと思うよ。
補足
私が言いたいのは文字列型が存在しないのに なぜコンパイラはaの次にbがあるのか判断できるのか という話です。