最近更新したページ
2013-10-20
2013-09-29
2013-09-23
2012-01-07
2011-11-09
2011-10-23
2011-10-09
2011-10-01
2011-09-29
2011-09-03
2011-08-07
2011-08-02
2011-07-29
2011-07-10
2011-05-05
2011-05-04
2011-04-24
2011-04-13
2011-04-05
2011-03-26
2011-02-18
2011-02-15
2010-12-26
2010-12-07
2010-12-05
2010-11-23
2010-09-28
2010-09-23
2010-08-26
2010-08-22
2010-07-16
2010-01-17
2010-01-11
2009-10-04
2009-08-21
2009-08-13
2009-06-18
2009-06-01
2009-04-29
2009-02-16
2009-02-11
2009-02-03
2008-07-22
2008-07-21
2008-07-15
2008-07-14
2008-07-13
2008-07-12
2008-07-08
2008-07-05
2008-06-28
2008-06-17
2008-06-05
2008-06-02
2008-06-01
2008-05-29
2008-05-26
2008-05-21
2008-05-19
2008-05-18
2007-10-31
2007-10-27
2007-09-28
2007-09-23
2007-09-17
2007-09-16
2007-09-14
2007-09-11
2007-06-18
2007-04-15
2006-12-21
2006-11-30
2006-11-22
2006-08-17
2006-03-29
2006-03-28
2006-03-27

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() で同じデータ領域の操作が出来ている。

▲上へ [ 編集 ]

  • 問題点
    1. 動的配列宣言時、同時に値代入(初期化)出来ない。(要 push_back)
      1. char[10] 等の文字配列は、後代入に strcpy(chr[],"文字列"); とする。
      2. VC++ strcpy() -> strcpy_s() 推奨 warning 多発。(strcpy_s MS拡張)
      3. テストデータ代入が面倒。

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; // 柊沢 エリオル
}
※構造体としてわかりやすいが、構造体変数を個別にプログラム内に埋め込むのは一般的では無い。

▲上へ [ 編集 ]

リンク


内部リンク


外部リンク


  • 現在ありません

▲上へ
2008年06月28日(土) 08:50:57 Modified by cafeboy1




スマートフォン版で見る