C 文字列 新しいページはコチラ
提供: yonewiki
(→文字列) |
(→文字列) |
||
151行: | 151行: | ||
もう面倒見れきれませんわ。となっているのがcout関数の実情なのだろう。cout関数のソースコードを追ってみる?んや、やめとく。<br /> | もう面倒見れきれませんわ。となっているのがcout関数の実情なのだろう。cout関数のソースコードを追ってみる?んや、やめとく。<br /> | ||
さすがに時間がかかりそうだ。ちょろっとWebで検索してみたが、ここまで追いかけた人もあまりいなさそう。<br /> | さすがに時間がかかりそうだ。ちょろっとWebで検索してみたが、ここまで追いかけた人もあまりいなさそう。<br /> | ||
+ | てな具合で、話をそらしつつ、出力の異なりに蹴りをつけようと思ったのですが、このようになる法則はありまして…<br /> | ||
+ | <br /> | ||
+ | ん、まてよ。<br /> | ||
+ | <br /> | ||
+ | ポインタの変数を使ってないのに、cStr1はアドレスを保持する変数なの?って気付いた人は鋭いっす。そこから、cout関数の動作を説明し得るのです。<br /> | ||
+ | そうなんです。配列を宣言すると、配列番号の添え字を省くと、アドレス変数を指し示すし、配列番号を与えると中身を見てくれる。<br /> | ||
+ | ポインタの変数と同じなのです。<br /> | ||
+ | <br /> | ||
+ | つまり、cStr1はchar *cStr1と宣言されたポインタ変数で、cStr1=&cStr1[0]とされている状態と同じなのです。<br /> | ||
+ | であるから、以下のように | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | #include <iostream> | ||
+ | int main(){ | ||
+ | char *pcStr1; //文字型のポインタ変数定義 | ||
+ | char cStr1[] = "yonewiki"; | ||
+ | pcStr1 = &cStr1[0] | ||
+ | std::cout << "pcStr1 = "<< pcStr1 << "\n"; | ||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | 出力結果 | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | pcStr1 =yonewiki | ||
+ | </syntaxhighlight> | ||
+ | となります。だとしたら、さきほどの少し疑問だったcout関数での扱いはごく自然な振る舞いにも思えませんか?<br /> | ||
+ | &pcStr1って指示したら、アドレスを返す。printf関数は書式指定で%sだから、引数で指定されたアドレスから\0が中身に格納されているアドレスまで<br /> | ||
+ | 文字列を返す。そういうことです。別に面倒になことしやがってということではなくて、ポインタ変数の扱いについての一貫性をもってますよね。<br /> | ||
+ | cout関数とprintf関数とでは出力指示が異なるために違う結果になるわけです。アドレスそのものを出力するのがアドレス演算子の役割であり、<br /> | ||
+ | 一方で文字列配列のアドレスを意味する形でcStr1であるだとか&cStr1[0]のように文字型のアドレスを渡されたら文字列を出力する。<br /> | ||
+ | ということは、<br /> | ||
+ | 文字型の配列になっていない1文字だけが格納されている文字変数のアドレスを出力すると\0が無いので、以下のように使用すると不具合がおこります。<br /> | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | #include <iostream> | ||
+ | int main(){ | ||
+ | char *pcChar; //文字型のポインタ変数定義 | ||
+ | char cChar = 'a'; | ||
+ | pcChar = &cChar | ||
+ | std::cout << "cout pcChar ="<< pcChar << "\n"; | ||
+ | std::cout << "cout *pcChar ="<< *pcChar << "\n"; | ||
+ | printf("printf %s pcChar =%s\n", pcChar); | ||
+ | printf("printf %c *pcChar =%c\n", *pcChar); | ||
+ | printf("printf %c pcChar =%c\n", pcChar); | ||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | 出力結果 | ||
+ | <syntaxhighlight lang="cpp"> | ||
+ | cout pcChar =aフフフフフフフフフフフフ | ||
+ | cout *pcChar =a | ||
+ | printf %s pcChar =aフフフフフフフフフフフフ | ||
+ | printf %s *pcChar =a | ||
+ | printf %s *pcChar =+ | ||
+ | </syntaxhighlight> | ||
+ | というお話でした。どうでしょう。納得していただけたでしょうか。<br /> | ||
+ | printf関数でアドレスを引数にpcCharとして%c書式でで出力しようとするとおそらくアドレス番号の<br /> | ||
+ | 下位1バイトの文字コードが動かすたびに割り当てられるアドレスが異なるのでランダムに出力されるでしょう。<br /> | ||
+ | C言語の文字列という話だけで、ここまで掘り下げて理解してたら日が暮れる。<br /> | ||
+ | <br /> | ||
+ | 疲れますよね。VBとか、JAVAとか、Perlとか、こんなことしなくてもプログラムできるのに。<br /> | ||
+ | でも、この程度でひるんじゃいけないよ。まだまだ複雑な世界が広がっています。<br /> | ||
+ | プログラムをより柔軟に記述するための要素がC言語には存在します。おそろしく複雑です。<br /> | ||
+ | <br /> | ||
+ | C言語では、プログラムをより記述しやすくするための手法も存在し、<br /> | ||
+ | 演算子の意味を付け足したりもできちゃうのです。そうやってCの関数は作られていたりして、<br /> | ||
+ | 有識者の能力は半端ないことをやってのける。そこの勉強はしないにしても、これくらい掘り下げないとポインタは<br /> | ||
+ | 理解できない。自分もいまさらながらに思い知らされることは多いです。<br /> | ||
+ | でも、まぁ調べてみるのも楽しいと思えないと疑問は解決できないのかもしれない。<br /> | ||
+ | しっかし、このC言語っていう体系を作った人たちって凄くないか?完璧だよね。<br /> | ||
<br /> | <br /> | ||
次はポインタを使った文字列操作についての記事を書こうと思います。なかなかやるきになんないすけどね。<br /> | 次はポインタを使った文字列操作についての記事を書こうと思います。なかなかやるきになんないすけどね。<br /> | ||
+ | 自分の理解していることを文章にするって意外と難しいし、意外と自分でもわかっていないことに気付く、<br /> | ||
+ | そんなだから、わかってもらおうとするのも難しい。自分もわかったつもりの無能なのかもしれないし。<br /> | ||
+ | 会社で、講師やってくれないかって言われてもなんとなく嫌だ。ものすごい時間をかけて調べたことを<br /> | ||
+ | 体系的に理解できる状態にまとめることなんて、そうたやすくはない。しかも2時間程度でバシッととか考えてる人もいるし、無理だろ。ぉぃ。<br /> | ||
+ | 文字列の操作だけでかるく1カ月分くらいのお話をしないと、本当の意味での理解なんてできないと思う。<br /> | ||
+ | でも、最近、気が付いたのは、何か躓いたらネットで調べて、答えを見つける。あるいは自分で考える。<br /> | ||
+ | だとしたら、自分が気が付いていることくらいはネットに残していくのも大事なんじゃないかってこと。<br /> | ||
+ | 誰かがそれを見て、また前進する力になれているのだとしたら、それはそれでいいことだと思うから。<br /> | ||
+ | <br /> | ||
+ | <br /> | ||
最近はMediaWikiの中に文字を打ち込む時間も多く取れてるので、更新していけるような気がする。でも今日はここまでかな。<br /> | 最近はMediaWikiの中に文字を打ち込む時間も多く取れてるので、更新していけるような気がする。でも今日はここまでかな。<br /> | ||
<br /> | <br /> | ||
[[C PlusPlus|C++]]へ戻る | [[C PlusPlus|C++]]へ戻る |