こんにちは､ そしてお帰りなさい｡
本講演では､ これまでの課題に対する解決策を提示したいと思います｡
ポインタを構造体の中の要素として持ち､ 構造体である2つの関数にポインタを渡す方法のデモです｡
では､ コードブロックを出して､ 新しいプロジェクトを作りましょう｡
これはコンソール・アプリケーションになるのですが､ この構造体ポインタの例と名付けることにします｡
この要件は､ 基本的に商品名､
数量､ 価格､ 金額を格納する商品タイプ構造でした｡
そして､ 項目名は文字ポインタにする予定でした｡
基本的に数量を価格に乗じただけの金額にするつもりだったのでしょう｡
そして､ 構造体へのポインタをパラメータとする2つの関数を用意しました｡
そこで､ まず最初に､ 構造を作成することにします｡
そして､ 先ほども言いましたが､ 複数の機能で使いたい場合は､
グローバルに構造を作っておくとよいでしょう｡
構造を作るということは､ それを定義することなのです｡
メモリを割り当てないのか
だから､ グローバルに置いても損はない｡
そして､ それらは通常､ ヘッダーファイルの中に入ります｡
だから､ 構造体を作るには､ structと言えばいいんです｡
この項目を呼ぶことにして､ 4つの要素を用意します｡
文字ポインタを用意し､ これをアイテム名と呼ぶことにします｡
量を持つことになる｡
値段のフロートと､ 金額のフロートを用意するんです｡
そうやって､ かなり基本的な構造を定義することができるんです｡
さて､ メイン関数の内部では､ 構造体型の変数とポインタを作成したいと思います｡
まず､ 構造体の名前をstruct itemとし､ このitemを呼び出すだけでよいのです｡
しかも､ これは変なポインターを作っているだけです｡
これは､ 構造体内の4つの変数と要素にメモリを割り当てることになります｡
そこで､ ポインタを作成するのですが､ これは単に struct item と言えばよいでしょう｡
通常､ ポインタの名前にはpという接頭辞を付けるので､
p項目とします｡
そこで､ アスタリスクと言い､ p項目と言う｡
そして､ 次の行では､ ポインターのアイテムに割り当てます｡
だから､ address ofを使う必要があり､ itemと言います｡
そして､ ここでは､ ポインタの構造体の要素にメモリを割り当てています｡
アイテム名である文字ポインタのメモリが確保されていないので､
次のステップになります｡
さて､ なぜアイテム構造体を作成する必要があるのかと聞かれるかもしれません｡
本当にしないんです｡
ポインタを作成すれば､ そのポインタは､ その構造体アイテムのポインタのためのメモリを作成するだけでよいのです｡
intとfloatのメモリは確保されますが､
項目名の割り当てはまだ行わなければなりません｡
ただ､ これは普通に良い練習になるので､ 好きでやっています｡
通常､ 最初のアイテムの構造体で行うことは､
それを初期化することです｡
でも､ そんなことは必要ないんです｡
そこで､ まず最初に､ 項目名用にメモリを確保します｡
ですから､ 基本的にポインタであれば､ 特殊な演算子を使って要素にアクセスすることができます｡
ポインタである構造体には､ 要素にアクセスするためのダッシュや大小の記号があることを忘れないでください｡
そうでなければ､ 要素にアクセスするためにポインタの参照を解除する必要があります｡
括弧の中でこんなことができる｡
ポインターを非参照にすることができるので､
star p itemのように､ ドットで要素にアクセスするようにする必要があるのです｡
このようなことをするのは､ まったくもって正当なことです｡
しかし､ これは本当に必要でない余分な構文なのです｡
そこで､ cには特殊な構文があり､ 構造体がポインタである場合はいつでも､ 要素にアクセスすることができるようになっています｡
基本的にはp項目であるポインタの名前を言って､ ダッシュの後にgreater thanを使えばいいのです｡
そして今回は､ アイテム名に対してメモリを確保したい｡
そこで､ malloc関数から返されたものを代入することにします｡
malloc関数はvoidポインタを返すことを覚えておいてください｡
だから､ キャラクタースターにキャスティングする必要があるんです｡
しかし､ mallocを呼び出すだけで､ mallocと言いながら､ 作りたいバイトの大きさを指定すればいいのです｡
今回は30とし､ charのサイズがコンピュータによって異なる場合に備えて､
charのサイズに乗じることにします｡
そして､ これはアイテム名のためのメモリを確保することになります｡
項目名は構造体内部のポインタであるため､ このような処理を行う必要があります｡
他の構造体に代入しても､ その分のメモリは確保されない｡
だから､ こうするしかないんです｡
さて､ メモリを確保した後にまず行いたいのは､
mallocのチェックです｡
というわけで､ ここでNULLをチェックしたい｡
p項目がNULLならNULLと言うことにしています｡
そうでなければ､ メモリを確保できなかったらreturnかexitと言ったほうがいいかもしれません､
プログラムを終了して､ それをnegative oneに渡すことができます｡
そうでない場合は､ 項目を読み込むので､ 関数を作りたい｡
これから作成する関数は､ read itemと呼ばれるものです｡
この上の構造体の上に関数宣言を置いてみましょう｡
渡された構造体にデータを読み込んでいるだけなのです｡
データを返すことはない｡
つまり､ read itemと言えば､ 構造体を受け取り､ それがポインタになるわけです｡
つまり､ 構造体の項目､ アスタリスクIということですね｡
この値を定数にして､ 値を変化させることもできますが､ ここでは値を変化させています｡
しかし､ 定数構造体の場合､ そのポインタが指す値は変更できないことになります｡
アスタリスクの後に定数をつけると､ アドレスは変更できないということになりますし､ アスタリスクの直前には名前の後にそのようなものをつけることになります｡
そうすると､ アドレスは変更できないことになりますが､
コピー値で受け渡ししているので､ それは冗長です｡
私たちの読み物もあります｡
そして､ ここにいる間に､ 私のプリントアイテムもやっておこうと思います｡
これは､ 関数の宣言､ 関数のプロトタイプになるだけです｡
ここでは､ 非常に似ている､ また､ ポインタを取ることになります｡
アスタリスクの後にスペースを入れてもいいのかどうか？
これで､ メインメソッドの下に読み取り項目を定義することができます｡
そして､ これは項目の値を読み込んで､ 合計金額を計算するものです｡
つまり､ void read itemと言えば､ ポインタを持つことができるのです｡
そして､ この内部では､ 単にscanfsを使いたいだけなのです｡
ユーザーに情報を入力するように伝えるために､ いくつかのメッセージを出力することにしています｡
そこで､ 製品名を入力してくださいということで､ 読み込むことになります｡
そこで､ scanfと言い､ 構造体へのポインタがあるので､ ダッシュ then greater thanを使ってアクセスすることができるのです｡
scanfのために読み込みたい､ 商品名は文字バッファです｡
だから､ パーセントsと言いたいし､ Iと言いたい､ 項目名に格納する｡
また､ インテリセンスで項目名まで戻ることができます｡
文字ポインタなのでoperatorのアドレスは使わなくていいんです｡
次に､ プリントアウトして価格を取得したいのですが､
おそらくここに改行を追加して､ 価格を入力します｡
それを構造体に格納するんです｡
だからまた､ 値段は浮くけど｡
だから､ パーセントfと言うことになるが､ ポインタだからアクセスもする､ やはりダッシュ then
greater thanを使いたい｡
ただし､ 今回は価格と言い､ そのアドレスを取得する必要があるので､
価格の前にアンパサンドを付けます｡
そして､ 量も同じようにします｡
だから､ 数量は整数である｡
つまり､ パーセントdと言うことができるのですが､
そのアドレスはまだ取得する必要があります｡
さて､ 3つの情報を保存したり､ ユーザーに入力してもらったりしたので､
今度は実際に金額を計算したり､ 金額に何かを保存したりすることができます｡
金額は､ 数量に価格をかけただけのものです｡
そこで､ 構文を使って構造体にアクセスし､ それをキャストして､ 数量と価格を掛け合わせたものを署名することになります｡
そして､ これがリードアイテム機能です｡
構造体ポインタを取る｡
そして､ このポインタを読み込み項目の内部で変更すると､ 関数の外部で変更されることになるわけです｡
つまり､ この関数にどんな構造体を渡しても､ それが修正されるのです｡
すべてのアイテム､ アイテム名､ 価格､ 数量､ 金額を保存することになります｡
それがデータで読み取れるわけです｡
この時点で､ テストをしたくなるのですが､ おそらくこの前にコンパイルとテストをしたいのでしょう｡
しかし､ これでmainの中でread itemメソッドを呼び出し､ 作成した構造体にそれを渡すことができるようになりました｡
だから､ read itemと言えばいいし､ p itemと言えばいいのです｡
ポインタなのでアドレスを渡す必要はなく､ 構造体を渡すだけでいいのです｡
そして､ 次にできることは､ それをプリントアウトすることです｡
そしてこれが示すのは､ データが保存されていること､ p項目が関数内部で変更され､
関数外部で保存されていること､ メイン関数が実際にこれらの値を保存していることです｡
そこで､ 再びポインタを渡してprint itemと言えば､ print item関数が定義できる｡
プリント項目はかなり基本的なものです｡
何も返さないので､ voidと言い､ print itemはポインタを取ると言っています｡
だから､ struct item star Iとでも名付けておけばいいんです｡
そして､ 渡された構造体のデータをプリントアウトするだけです｡
そこで､ printf name percent s､ I item name､ I price､ I quantity､
I amountのようなことをして､ データをフォーマットします｡
データをプリントアウトした後､ メインで最後にやらなければならないことは何かというと､
本当に重要なfree関数です｡
項目名用に確保したメモリを解放したいので､ freeを呼び出すことになったのです｡
だから､ free p item と言って､ アイテム名にアクセスすればいいのです｡
関数が戻ったときにスタック上の構造体全体が削除されるため､
構造体全体を解放することはしません｡
我々は､ mallocしたものを解放したいだけなのです｡
アイテム名分しかmallocしていないので､ それを解放して､
mainから戻ります｡
では､ さっそくこれを作ってみましょう｡
そして､ エラーが発生しています｡
それでは､ 構造物アイテムスターと書いてありますね｡
つまり､ 構造の上に機能を定義してしまうというミスがあったわけです｡
しかし､ パラメータを構造体型として受け取るという機能｡
だから､ 使う場所の上に構造が定義されていないといけないんです｡
そこで､ 関数を12行目と13行目に移動させています｡
これで､ コンパイルができるようになりました｡
では､ これを実行してみましょう｡
そして､ ここで何が出てくるか見てみましょう｡
もう1つエラーがあります｡
p項目がNULLかどうか､ しっかりチェックする必要があります｡
if p item for trueと言うだけなら､ 常にtrueになる｡
つまり､ NULLではないという意味のnotシンボルで真偽を確認するか､
NULLかどうかを確認するかのどちらかです｡
だから､ そこにNULLを追加しただけです｡
だから､ 今はそれを実行すれば､ 問題ないはずだ｡
製品名を入力することができます｡
シリアルと言い､ 価格は1ということにします｡ 99.
そして､ それを5つ持っているとします｡
そして今度はそれをプリントアウトして､ シリアル・ドル99と言うわけです｡
5､ 合計で9となります｡ 95.
値段は､ プリントアウトの仕方が気に入らないが｡
だから､ それを直そう｡
プリントアイテムでは､ for price dor 2 f floatsと言えばいいわけで､ これで少しは見栄えが良くなったかな､
と思って実行します｡
少しはマシなフォーマットにしよう｡
4本で少しは見栄えが良くなり､ 万事OKになりました｡
というわけで､ 今回も構造体とポインタを使った基本的なプログラムです｡
トップで構造を作ったのです｡
ポインターを含むメンバーを持っています｡ 文字配列とは対照的に､
コピーとアドレスだけで済むので､ 非常に効率的な方法です｡
read item print item の2つの func 宣言があり､
ポインタを取って破壊します｡
そして､ そのポインタを作成し､ mainの中の通常の構造体に代入しています｡
22行目でメモリを確保しています｡
メモリが正常に確保されたことを確認し､ 確保されていない場合はプログラムを終了します｡
そして､ 構造体へのポインタを取る2つの関数を呼び出して､
それらを渡します｡
そして最後に､ メモリを解放して､ プログラムを終了します｡
そして､ その機能はとてもわかりやすいものです｡
そのポインターを取るのです｡
ポインタへのアクセスは､ ダッシュを使ったthen greater thanで行います｡
そして､ ポインターを要素に持たないscanfsでは､ そのアドレスを取得します｡
そして､ 基本的にはそれだけです｡
私はこのプログラムを保存するから､ あなたはそれを見てください｡
何か質問があれば教えてください｡ ありがとうございます｡