こんにちは､ そしておかえりなさい
今回の講義では､ ポインタ演算と定数修飾子を使った課題についてのデモを行いたいと思います｡
コードブロックを持ち出そう｡ 新しいプロジェクトを作ります｡ これをポインタ演算の例と名付けることにする｡
そこで､ ここでは実際にポイント演算を使って文字列の長さを決定してみます｡
そこで､ まず最初に関数宣言を作成したいと思います｡
これは､ 文字列の長さを返そうとするものです｡ つまり､ 戻り値の型としてintを持つことになる｡
文字列の長さと呼ぶことにします｡
これはポインタを取るだけですが､ 定数ポインタにするつもりです｡
指し示すものの値を変えたくないのです｡
つまり､ 最初のキーワードとして定数を使い､ その後に文字という型を指定することになる｡
そして､ 私たちはスターと言い､ 好きな名前をつけることができます､ 文字列｡
繰り返しになりますが､ もしここに定数を入れると､ ポインタのアドレス､
ポインタの値は変更できないことを意味します｡
しかし､ これも冗長であり､ また､ 値によるパス､ コピーによるパスを実行しているため､
実際に行う必要はありません｡
だから､ どうせアドレスはコピーしてあるんだから､ そこで変更しても問題ない｡
しかし､ 何を指しているのかを変えることが重要です｡ もし､ 指しているものの価値が変わることを望まないのであれば､
間違いなくここで絶えず行いたいし､ それが重要です｡
さて､ あとはメインを作るだけです｡
を作成します｡ メインでやることは､
文字列の長さ､ つまり異なる文字列で文字列長関数を呼び出すことです｡
これは整数を返すので､ "パーセントd "と言って､ 渡した文字列の長さを出力します｡
文字列長を呼び出し､ 定数文字列を渡します｡
ここでは二重引用符で囲むだけです｡
ポインターも作らなくていいんです｡
ポインターを作って代入してから渡すという方法もありますが､ 定数であることを確認すればいいだけです｡
しかし､ 少ないコードで簡単なので､ 文字列の長さのテストと言えばいいのです｡
繰り返しになりますが､ これは定数リテラルの文字列です｡
もう少し使ってテストしてみます｡
その後にスペースを入れます｡ 改行を加えてみよう｡
ここでは､ 文字列の長さを呼び出すことにする｡ そして､ 実際に空の文字列で呼び出して､
ゼロになることを確認しましょう｡ そして､ 3つ目は､
文字列の長さをjasonとします｡
ちなみに､ これらの文字列長のリンクを作成し､ それを渡すと､
自動的にヌル末尾が追加されます｡
ポインターを宣言するときに､ それを学びます｡
それがメリットのひとつです｡ ポインターを作成し､ それがリテラルになる場合､
サイズを指定する必要はありません｡
配列は配列はポインタだから､ 配列ならcharacterとかやりたくなるよね｡
しかし､
もしサイズを指定したくないのであれば､
文字pと言い､ この中でjasonと言えばいいのです｡
文字配列のサイズを指定しないと､ 自動的にヌルのターミネータが追加されて､
サイズが作成されるという授業を思い出してください｡
そうすれば､ 間違いがない｡ 配列の内側にサイズを入れると､ ヌルターミネータが足りなくなることがあります｡
文字列の長さにリテラルを渡すと､ その末尾にヌル文字が追加されるのと同じことです｡
ですから､ 最初にこれらの変数を作っておいて､
それぞれを渡すというようなやり方でもよかったのです｡
でも､ 変数を作る時間がもったいない｡ だから､ そうすることにしているんです｡
さて､ このコードで本当に重要なのは､ 関数です｡
そこで､ 文字列の長さを作成することにします｡ 繰り返しになりますが､ これは整数を返すもので､
定数になることを忘れないでください｡ だから､ constant char star stringと言えばいいのです｡
そして､ 関数宣言の変数名が一致しなくてもよいことにも気づきます｡
これを文字列として並べると､ それもいいんです｡
さて､ この関数の内部では､ ローカルポインタを作成する必要があります｡ ローカルポインタは､
文字列の終端を指すことになるからです｡ そして､ 文字列の末尾のアドレスが決まれば､
文字列の先頭のアドレスをマイナスすることができるのです｡
文字列の先頭のアドレスが渡される｡
文字列は自動的に配列の最初の要素､ あるいは配列の最初のアドレスを指すようになります｡
そこで､ ローカルポインタを作成して､ もう一度別の定数char
starを作成し､ 最後のアドレスと言うことにすれば､
どうでしょう｡
そして､ これは文字列の先頭アドレスと等しくなり､ ループの中で毎回インクリメントされることになります｡
これでラストアドレスが決まりましたね｡ 繰り返しますが､ これはローカル変数で､ ヌル文字ターミネーターの直前のアドレスを格納することになります｡
さて､ これでwhileループを書けるようになりました｡
そして､ このwhileループは､ nullターミネーターが表示されたら終了するようになっています｡
さて､ これには2通りのやり方があります｡
キャラクターを比較することができた｡ そのため､ while star last
addressのように､ not equal to backslash zeroを参照解除するようなこともできますが､
これはちょっとコードが多くなってしまいます｡
本当に必要なのは､
ラストアドレスでwhile starと言うだけです｡
なぜなら､
Nullターミネーターをデリファレンスすると､ それは0に等しくなり､
0はfalseに等しくなるからです｡
ブール値には､ 1が真で0が偽であることが分かっています｡
だから､ 偽りであれば飛び出してしまう｡ つまり､ while条件の中にスターラストアドレスを入れるだけです｡
ここでもポインタの参照解除が行われます｡
そして､ 最後のアドレスを指すと､ ヌルの終端を指すことになる｡
さて､ 最後のアドレスを変更して､ 最終的にヌル終端を指すようにしなければなりません｡
ここでできることは､ プラス・プラス・ラストアドレスと言うことです｡
つまり､ このwhileループの各反復は､ ゼロを見つけるまでアドレスをインクリメントすることになる｡
ゼロはヌル終端を表す｡
つまり､ このwhileループが実行された後の最終的なアドレスは､
NULLターミネーターのアドレスを指していることになります｡
そして､ 渡された文字列のアドレスからヌルターミネーターのアドレスを引くことで､
長さを求めることができるのです｡
だから､ 次の行はこれで終わりです｡ 最終アドレスを返すと言うだけで､ 実際にはアドレスをマイナスしたいので､
何も参照解除したり､ 間接演算子を使ったりする必要はなく､
最終アドレスから文字列をマイナスすることができます｡
つまり､
文字列が渡され､ 我々はそれを全く修正しないのです｡
1文字目を指していますね｡ それは､ jを指しているのだろう｡
これがアドレスになりますし､ 8行目で初めて呼び出す場合は､ sのアドレスになります｡
Last addressは､ この最後のtのアドレスを指すことになる｡
実はもう一つ､ NULLターミネーターがあります｡ last addressからsのアドレスを引くと､
長さが出ますね｡
そして､ それが返ってくるというわけです｡
ということで､ ご理解いただけたでしょうか｡
17行目でも､ ローカル変数を作成しています｡ これは､
最後のアドレス､ つまりヌル終端記号のアドレスを記録しておく必要があるためです｡
このwhileループの実行が終わると､ 最後のアドレスは､ ヌルのターミネーターであるtの後を指すことになります｡
そして､ 文字列から最後のアドレスを減算すればよいのです｡ 文字列のアドレスは､ 入ってきたときにsを指しているので､
それを修正することはありません｡
では､ これで正しい長さが戻ってきたらどうでしょう｡
これを実行すると､ 渡された文字列の長さが表示されるはずです｡
だから､ 17の0と5が見えるのです｡
例えば､ 1 2 3 4 5 6 7 8 9 10 11 12 13､ あなたはスペースを数えるようになった､
14 15 16 17｡
そうです､
二重引用符で囲んでいるのは空です､ だから0になるはずです､ そしてジェイソンは5になるはずです､
だから17 0と5､ これが正しいです｡
そこで､ ポインタ演算で最終アドレスにインクリメント演算子を加え､
さらにポインタ演算で最終アドレスから文字列を引いた長さを求めました｡
かなりきれいです｡ ポイント演算の威力､ 表記の便利さを実証したいんです｡
インクリメント､ デクリメントで文字配列のいろいろな場所に行き､
文字を取り出すことが簡単にできる方法｡
今回は､
アドレスを取得し､ そのアドレスから互いにマイナスして長さを求めているだけです｡
というわけで､ 参考になったでしょうか｡ 今お話したことをすべて理解してください｡
繰り返しになりますが､ 定数の概念､ プラス・プラスの概念､ アドレスを参照し､ それがヌル・ターミネータを指している場合はゼロであるためジャンプアウトするという条件の概念､
そして2つのアドレスをマイナスにするという概念です｡
ありがとうございます｡