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
