C/C++ 構造体とポインタ
紆余曲折、sort->STL->日付・時刻-> 構造体へ戻って来た。
構造体とポインタ
構造体のデータ型(日付や性別の最適化)を除き、sample 5-4 でほぼ完成形と判断。
これをベースに構造体メンバを基準にソートを行えれば、当初の目的に達する。
vector 以外の list set map 等の利用については、機会があれば再考察。
C/C++ 構造体とソート ・・・ 作成中 ・・・
構造体変数について
構造体の参照と値渡し
・・・ 作成中 ・・・
構造体とポインタ
普通のポインタと特段変わらないが、構造体メンバ指定に「アロー(->)」を知っておく必要あり。sample 6-1
#pragma warning (disable:4996) #include <stdio.h> #include <string.h> // .C strcpy 使用時必要 struct { int cd; // 番号 char jname[20]; // 日本語名称 char aname[20]; // 英名 char nickname[20]; // あだ名 } val, *p; void main() { // pointer型 *p のアドレス変数 p へ // val のアドレス &val を代入することで、 // *p と val の実態が同じとなる。 p = &val; // ■ 1. val へ値を代入し、p で表示を確認 val.cd = 12; strcpy(val.jname, "ケルベロス"); strcpy(val.aname, "Kerberos"); strcpy(val.nickname, "ケロちゃん"); printf("%d %s %s %s \n", p->cd, p->jname, p->aname, p->nickname); // ■ 2. p で値を代入し、val で表示を確認 strcpy(p->jname, "スピネル・サン"); strcpy(p->aname, "Spinel Sun"); strcpy(p->nickname, "スッピー"); printf("%d %s %s %s \n", val.cd, val.jname, val.aname, val.nickname); }※ 1. 2. 共、基本的に同じ処理を行っている。
表示サンプル
12 ケルベロス Kerberos ケロちゃん 12 スピネル・サン Spinel Sun スッピー 続行するには何かキーを押してください . . .※単一構造体を使った新規登録と変更上書き、及び表示
▲上へ [ 編集 ]
構造体・STL(vector) の組合せサンプル
動的な配列(STL::vector)を利用した構造体配列。- 必要とした知識
- STL(vector iterator string 等)
構造体(動的な構造体配列(vector))
ポインタ(参照渡し,値渡し等)
構造体配列を動的な配列として利用する
sample 5-4
vector 及び string型を含んだ構造体。
#include <iostream> #include <vector> #include <string> using namespace std; #pragma warning (disable:4313) // printf の worning を黙らせる struct student { int no; int age; string Birthday; string blood_type; string boy_girl; string name; string memo; }; void move_arr(vector<student>& v_seito) { int max_no = 9; struct student seito[] = { { 1, 14, "4/1", "A", "g", "木之本 桜", "はにゃーん・ほえ〜" }, 〜 省略 〜 { 9, 13, "10/11", "AB", "g", "柳沢 奈緒子", "眼鏡っ子で怪談好き" } }; cout << "■2.move_arr()\n"; for(int i=0; i<max_no; i++) { printf("%i %s \n", seito[ i ].no, (seito[ i ].name).c_str()); v_seito.push_back( seito[ i ] ); } cout << "■3.move_arr()\n"; vector<student>::iterator it; for(it=v_seito.begin(); it<v_seito.end(); it++) { printf("%i %s \n", it->no, (it->name).c_str()); } } void main() { vector<student> v_seito; struct student seito; // ---------------- 検証用データ投入 ---------------- seito.no = 10; seito.age = 100; seito.Birthday = "?"; seito.blood_type = "?"; seito.boy_girl = "b"; seito.name = "ケロちゃん"; seito.memo = "なんで関西弁?"; v_seito.push_back( seito ); // ---------------- 検証データ end ---------------- // テストデータ代入と、代入データの目視チェック用表示 2. 3. move_arr(v_seito); // 処理された動的構造体配列の全表示 1. cout << "■1.main()\n"; vector<student>::iterator it; for(it=v_seito.begin(); it<v_seito.end(); it++) { printf("%2i %-24s %s \n", it->no, (it->name).c_str(), (it->memo).c_str() ); } }※動作未検証・めずらしくも、ほぼフル表示!
表示サンプル
■2.move_arr() 1 木之本 桜 ・・・ 〜 中略 〜 9 柳沢 奈緒子 ■3.move_arr() 10 ケロちゃん 1 木之本 桜 ・・・ 〜 中略 〜 9 柳沢 奈緒子 ■1.main() 10 ケロちゃん なんで関西弁? 1 木之本 桜 はにゃーん・ほえ〜 ・・・ 〜 中略 〜 9 柳沢 奈緒子 眼鏡っ子で怪談好き 続行するには何かキーを押してください . . .※1.main() へ、表示フォーマット、表示項目の追加あり。
[ 編集 ]
sample 5-3
問題点改善版
// 参照渡しされた v_seito へデータを代入する void move_arr2(vector<student2>& v_seito) { int max_no = 9; struct student2 seito[] = { { 1, 14, "4/1", "A", "g", "木之本 桜", "はにゃーん・ほえ〜" }, 〜 中略 〜 { 9, 13, "10/11", "AB", "g", "柳沢 奈緒子", "眼鏡っ子で怪談好き" } }; cout << "■2.move_arr() push_back 実行 代入する seito メンバ表示\n"; for(int i=0; i<max_no; i++) { printf("%i %s \n",seito[i].no,seito[i].name); // 代入データ表示 v_seito.push_back( seito[ i ] ); } cout << "■3.push_back 実行後の v_seito メンバを表示\n"; vector<student2>::iterator it; for(it=v_seito.begin(); it<v_seito.end(); it++) { printf("%i %s \n", it->no, it->name); // v_seito メンバ表示 } }
void main() { vector<student2> v_seito; struct student2 seito; // --- 検証用データの追加 ----------------------------------- seito.no = 10; seito.age = 100; strcpy(seito.Birthday, "?"); strcpy(seito.blood_type, "?"); strcpy(seito.boy_girl, "b"); strcpy(seito.name, "ケロちゃん"); strcpy(seito.memo, "なんで関西弁?"); v_seito.push_back( seito ); // --- 検証データ追加 end ---------------------------------- // 動的構造体配列 v_seito へテストデータを読込 move_arr2(v_seito); // 動的構造体配列 v_seito 代入データの表示 cout << "■1.main() テストデータ代入後の v_seito メンバ表示\n"; vector<student2>::iterator it; for(it=v_seito.begin(); it<v_seito.end(); it++) { printf("%i %s \n", it->no, it->name); } }※参照渡し手順とイテレータの使用方法が要と思われる。
表示サンプル
■2.move_arr() push_back 実行 代入する seito メンバ表示 1 木之本 桜 ・・・ 〜 中略 〜 9 柳沢 奈緒子 ■3.move_arr() push_back 実行後の v_seito メンバを表示 10 ケロちゃん // main で push_bak済みデータ 1 木之本 桜 ・・・ 〜 中略 〜 9 柳沢 奈緒子 ■1.main() テストデータ代入後の v_seito メンバ表示 10 ケロちゃん 1 木之本 桜 ・・・ 〜 中略 〜 9 柳沢 奈緒子 続行するには何かキーを押してください . . .※move_arr() main() で同じデータ領域の操作が出来ている。
▲上へ [ 編集 ]
- 問題点
- 動的配列宣言時、同時に値代入(初期化)出来ない。(要 push_back)
- char[10] 等の文字配列は、後代入に strcpy(chr[],"文字列"); とする。
- VC++ strcpy() -> strcpy_s() 推奨 warning 多発。(strcpy_s MS拡張)
- テストデータ代入が面倒。
sample 5-2
5-1 に追加・修正
// 追加関数 vpost_check() void vpost_check(struct student2& meibo) { cout << "vpost_check : "; cout << meibo.no << " "; cout << meibo.age << " "; cout << meibo.name; // 参照渡しチェックのため上書きしてみる strcpy(meibo.name, "ケロちゃん"); cout << " <--- " << meibo.name << endl; }
// main() へ行追加・その他表示のみ修正 void main() { 〜 省略 〜 // 以下最下行へ追加 printf("main 2-1 : no:%i name:%s \n",v_seito[0].no,v_seito[0].name); vpost_check(v_seito[ 0 ]); // 参照渡し printf("main 2-2 : no:%i name:%s \n",v_seito[0].no,v_seito[0].name); }
5-2 表示サンプル
post_check : 1 14 木之本 桜 <--- スッピー // 値渡し main 1-1 : no:1 name:木之本 桜 // 置換えなし main 2-1 : no:1 name:木之本 桜 // v_seito のメンバ表示 vpost_check : 1 14 木之本 桜 <--- ケロちゃん // 参照渡し main 2-2 : no:1 name:ケロちゃん // v_seito メンバが置換えられる 続行するには何かキーを押してください . . .※見やすいように、適当に修正入ってる...
[ 編集 ]
sample 5-1
動的な構造体配列<vecter>使用と、後代入時の値代入にstrcpyを使用する。
// うるさい warning を黙らせる魔法の言葉(vc専用) #pragma warning (disable:4313) // printf の warning #pragma warning (disable:4996) // strcpy の warning
void post_check(stract student meibo) { // 代入状態を目視チェックするだけ...無くても良い... cout << meibo.no << " "; // 1 cout << meibo.age << " "; // 14 cout << meibo.name; // 木之本 桜 // cout << (meibo.name).c_str(); // 参考:string型の場合 c_str でキャスト cout << endl; // 値渡しチェックのため上書きしてみる strcpy(meibo.name, "スッピー"); cout << meibo.name << endl; }
void main() { int max_no = 1; vector<student2> v_seito; // 動的構造体配列 struct student2 seito; // ごく普通の構造体変数
// 動的構造体配列のデータ追加準備 seito.no = 1; seito.age = 14; strcpy(seito.Birthday, "4/1"); strcpy(seito.blood_type, "A"); strcpy(seito.boy_girl, "g"); strcpy(seito.name, "木之本 桜"); strcpy(seito.memo, "はにゃーん・ほえ〜"); post_check(seito); // <-- 値渡しチェック // 動的な構造体配列 <vector> v_seito へ1レコード追加する v_seito.push_back( seito );
// 単純な転記のテスト(冗長) struct student tmp; // 転記用構造体 tmp for(int i=0; i<max_no; i++) { tmp = seito; // tmp へ代入 printf("no:%i name:%s \n", tmp.no, tmp.name); // tmp メンバを表示 } }
表示サンプル
1 14 木之本 桜 // 値渡しされた meibo.メンバ ケロちゃん // meibo.name を上書き no:1 name:木之本 桜 // 値渡しのため seito.name に変更無し 続行するには何かキーを押してください . . .※やってて訳わかんなくなって来た...
▲上へ [ 編集 ]
構造体のコピー
※構造体配列を含んだデータのコピーsample 4
void main() { int max_no = 9; student seito[] = { 〜 省略 〜 }; // 構造体配列の内容を、構造体 tmp へコピーして表示する student tmp; // 転記用構造体 tmp for(int i=0; i<max_no; i++) { tmp = seito[i]; // tmp へ代入 printf("no:%i name:%s \n", tmp.no, tep.name); // tmp メンバを表示 } }※修正、省略あり。
表示サンプル
no:1 name:木之本 桜 no:2 name:大道寺 知世 no:3 name:李 小狼 no:4 name:李 苺鈴 no:5 name:柊沢 エリオル no:6 name:山崎 貴史 no:7 name:三原 千春 no:8 name:佐々木 利佳 no:9 name:柳沢 奈緒子 続行するには何かキーを押してください . . .※素晴らしいことに!文字列配列も含め単純にコピーできてる。これは便利!
▲上へ [ 編集 ]
構造体配列とポインタの組み合わせ
※単純な構造体配列とポインタの組み合わせ例。sample 3
※sample 2 を更に修正。ポインタ効果的に使用しアクセスする。
void prn_data(student* p,int n) { printf("p=%X &p=%X *p=%X \n\n",p,&p,*p); cout << "-----------------------------\n"; for(int i=0; i<n; i++) { printf("no:%i name:%s \n",(p+i)->no,(p+i)->name); } } void main() { student seito[] = { { 1, 14, "4/1", "A", "g", "木之本 桜", "はにゃーん・ほえ〜" }, 〜 以下略 〜 }; student *p; // struct student 配列用の ポインタ確保 p = seito; // struct student &seito[0] 構造体先頭アドレス printf("main :p=%X &p=%X *p=%X \n",p,&p,*p); int max_no = 9; prn_data(p,max_no); cout << "-----------------------------------\n\n"; }※一部修正、割愛あり。
表示サンプル
main :p=12F90C &p=12F900 *p=1 prn_data :p=12F90C &p=12F81C *p=1 ----------------------------------- no:1 name:木之本 桜 no:2 name:大道寺 知世 no:3 name:李 小狼 no:4 name:李 苺鈴 no:5 name:柊沢 エリオル no:6 name:山崎 貴史 no:7 name:三原 千春 no:8 name:佐々木 利佳 no:9 name:柳沢 奈緒子 ----------------------------------- 続行するには何かキーを押してください . . .※通常データはファイル読み込み、xml 取得とかが一般的。取り合えず埋め込みデータでお勉強。
▲上へ [ 編集 ]
単純な構造体とポインタの組み合わせ
※比較的単純な構造体とポインタの組み合わせ例。sample 2
※sample 1 の生徒データを配列化した修正版。
#include <iostream> using namespace std; typedef struct { int no; int age; char Birthday[11]; char blood_type[3]; char boy_girl[5]; char name[25]; char memo[128]; } student; static student students[] = { { 1, 14, "4/1", "A", "女子", "木之本 桜", "はにゃーん・ほえ〜" }, { 2, 13, "9/3", "A", "女子", "大道寺 知世", "ビデオ撮影に執着" }, { 3, 14, "7/13", "O", "男子", "李 小狼", "無口" }, { 4, 13, "3/25", "B", "女子", "李 苺鈴", "気が強い" }, { 5, 13, "3/23", "AB", "男子", "柊沢 エリオル", "クロウの生まれ変わり" }, { 6, 13, "6/1", "AB", "男子", "山崎 貴史", "ホラ吹き" }, { 7, 14, "5/28", "O", "女子", "三原 千春", "山崎と幼なじみ" }, { 8, 14, "6/24", "A", "女子", "佐々木 利佳", "落ち着いている" }, { 9, 13, "10/11", "AB", "女子", "柳沢 奈緒子", "眼鏡っ子で怪談好き" } }; void main() { // 構造体の、先頭メンバアドレス取得 int student::* str_p = &student::no; cout << "--- アドレス表示 ---" << endl; cout << &str_p << endl; // 0012ff60 cout << "--- 値表示(参照) ---" << endl; cout << students[4].*str_p << endl; // 23 cout << "--------------------------" << endl; // 構造体変数のポインタ取得 student* p = &students[4]; cout << "--- ポインタ操作確認 -------------------" << endl; cout << "*str_p = " << p->*str_p << endl; // 5 cout << "*str_p+1 = " << p->*str_p+1 << endl; // 6 次のレコード cout << "--- 詳細表示確認 -----------------------" << endl; cout << "no = " << p->no << endl; // 5 cout << "age = " << p->age << endl; // 13 cout << "Boy/girl = " << p->boy_girl << endl; // 男子 cout << "name = " << p->name << endl; // 柊沢 エリオル }※実用性と可読性がだいぶ向上する。
[ 編集 ]
sample 1
#include <iostream> using namespace std; struct student { int no; int age; char Birthday[11]; char blood_type[3]; char boy_girl[5]; char name[25]; char memo[128]; }; static struct student sakura = { 1, 14, "4/1", "A", "女子", "木之本 桜", "はにゃーん・ほえ〜" }; static struct student tomoyo = { 2, 13, "9/3", "A", "女子", "大道寺 知世", "ビデオ撮影に執着" }; static struct student syaolan = { 3, 14, "7/13", "O", "男子", "李 小狼", "無口" }; static struct student meirin = { 4, 13, "3/25", "B", "女子", "李 苺鈴", "気が強い" }; static struct student eliol = { 5, 13, "3/23", "AB", "男子", "柊沢 エリオル", "クロウの生まれ変わり" }; static struct student yamazaki = { 6, 13, "6/1", "AB", "男子", "山崎 貴史", "ホラ吹き" }; static struct student chiharu = { 7, 14, "5/28", "O", "女子", "三原 千春", "山崎と幼なじみ" }; static struct student rika = { 8, 14, "6/24", "A", "女子", "佐々木 利佳", "落ち着いている" }; static struct student naoko = { 9, 13, "10/11", "AB", "女子", "柳沢 奈緒子", "眼鏡っ子で怪談好き" }; void main() { // 構造体の、先頭メンバアドレス取得 int student::* str_p = &student::no; cout << "--- アドレス表示 ---" << endl; cout << &str_p << endl; // 0012FF60 cout << "--- 値表示(参照) ---" << endl; cout << eliol.*str_p << endl; // 5 // 構造体変数のポインタ取得 student* p = &eliol; cout << "--- ポインタ操作確認 -------------------" << endl; cout << "*str_p = " << p->*str_p << endl; // 5 cout << "*str_p+1 = " << p->*str_p+1 << endl; // 6 次のレコード cout << "--- 詳細表示確認 -----------------------" << endl; cout << "no = " << p->no << endl; // 5 cout << "age = " << p->age << endl; // 13 cout << "Boy/girl = " << p->boy_girl << endl; // 男子 cout << "name = " << p->name << endl; // 柊沢 エリオル }※構造体としてわかりやすいが、構造体変数を個別にプログラム内に埋め込むのは一般的では無い。
▲上へ [ 編集 ]
リンク
内部リンク
- C/C++ C++/CLI C# 関連
- VC++ 2005 Express のインストール
- C/C++ の簡単なプログラム例
- 変数・定数
- 応用的プログラミング
- プログラムの分割/ダイナミックリンクライブラリ など
- その他
- C/C++ その他::書式文字/ESC code など
- VB2005リファレンス(覚え書き)
- SQL文:SQLステートメント
- VBA(VisualBasic for Applications)
外部リンク
- 現在ありません
▲上へ
2008年06月28日(土) 08:50:57 Modified by cafeboy1