プログラミング論 構造体 http://www.ns.kogakuin.ac.jp/~ct13140/Prog/

Slides:



Advertisements
Similar presentations
1 データ構造とアルゴリズム 第 3 回 配列,構造体,ポインタ ~ データ構造について学ぶための基礎~
Advertisements

第 10 回 宿題 出題日: 12 月 14 日 締切日: 12 月 21 日. 提出について 以下の場合は、出題日の出席を欠席とする 締切日を過ぎた場合 正解率が 7 割未満の場合 提出は、 PDF ファイルを印刷して、それに答 えを書いて提出すること。
プログラミング入門2 芝浦工業大学情報工学科青木 義満 第11回構造体. プログラミング入門2 2 構造体 5 人分のサッカー選手データ 全てのデータを関数に渡して,処理する場合 char name[5][256]; int assist[5]; int score[5]; void func( char.
C 言語講座第 5 回 構造体. 構造体とは ... 異なる型の値をまとめて新しい型とする 機能がある . つまり , 複数の変数を 1 つのまとまりにできる . 配列と違って同じ型でデータをまとめるのではな く違った型のデータをまとめられる .
アルゴリズムとデータ構造 第2回 線形リスト(復習).
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 動的な領域確保 情報工学科 篠埜 功.
第12回新しい型と構造体.
第13回構造体.
第12回構造体.
プログラミング入門2 ポインタについて補足 構造体 第11回 芝浦工業大学情報工学科 青木 義満、篠埜 功
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
基礎プログラミングおよび演習 第9回
16.3 関数と構造体 構造体ポインタ 地底探査ゲーム
構造体.
プログラミング演習II 2004年12月 21日(第8回) 理学部数学科・木村巌.
データ構造とアルゴリズム 第4回 リスト ~ データ構造(1)~.
第16章 構造体 16.1 構造体の定義と構造体変数 16.2 構造体の配列.
第3回 配列,構造体,ポインタ ~ データ構造について学ぶための基礎~
構造体 プログラミング入門2 芝浦工業大学情報工学科 青木 義満
構造体 構造体, 構造体とポインタの組み合わせ,.
プログラミング 3 構造体(1).
第10回 プログラミングⅡ 第10回
プログラミング論 関数ポインタ と 応用(qsort)
ちょっとした練習問題① 配列iroを['R', 'W', 'R', 'R', 'W' , 'W' , 'W']を宣言して、「W」のときの配列の番号をprintfで表示するようなプログラムを記述しなさい。
プログラミング2 関数
プログラミング論 ファイル入出力
ネットワークプログラミング 第4回「C言語の基礎~ポインタと配列」
データ構造とアルゴリズム 第4回 リスト ~ データ構造(1)~.
プログラミング論 II 2008年10月30日 文字列
第11回 宿題 出題日:12月21日 締切日:1月7日(木).
精密工学科プログラミング基礎 第10回資料 (12/18実施)
プログラミング 4 記憶の割り付け.
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
プログラミング入門2 第8回 ポインタ 情報工学科 篠埜 功.
ネットワークプログラミング 第3回「C言語の基礎~コマンドライン引数・構造体・ポインタ」
プログラミング 3 構造体(2).
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
プログラミング論 ファイル入出力
第11回 プログラミングⅡ 第11回
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
データ構造と アルゴリズム 第五回 知能情報学部 新田直也.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
復習 前回の関数のまとめ(1) プログラムはmain()関数の先頭から実行される
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
精密工学科プログラミング基礎Ⅱ 第5回資料 今回の授業で習得してほしいこと: 構造体 (教科書 91 ページ)
構造体と共用体.
データ構造とアルゴリズム 第11回 リスト構造(1)
情報基礎演習B 後半第2回 担当 岩村 TA 谷本君.
第13回 ポインタ 1 1.
プログラミング論 ポインタ
アルゴリズムとデータ構造1 2009年6月15日
ネットワーク・プログラミング Cプログラミングの基礎.
プログラミング論 文字列
アルゴリズムとデータ構造 2010年6月17日
フレンド関数とフレンド演算子.
2005年度 データ構造とアルゴリズム 第2回 「C言語の復習:配列」
データ構造と アルゴリズム 第四回 知能情報学部 新田直也.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
マスク合成(のような処理) 出力画像 Out 入力画像1 In1 In1 In2 Out 入力画像2 In
左右反転と180度回転 [0][xsize – 1] [0][0] → i ↓ j [ysize – 1][xsize – 1]
TList リスト構造とは? 複数のデータを扱うために、 データの内容と、次のデータへのポインタを持つ構造体を使う。
C言語講座第5回 2017 構造体.
プログラミング演習I 補講用課題
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
Presentation transcript:

プログラミング論 構造体 http://www.ns.kogakuin.ac.jp/~ct13140/Prog/

概要 構造体 複数の変数を組合わせて,ひとまとめにしたもの 簡単 重要 自己参照型, リスト 重要, 難しい

新しい構造体の宣言 例 struct 構造体名{ データ型 メンバ名1; データ型 メンバ名2; : データ型 メンバ名3; }; struct seiseki{ char name[20]; int math; int engl; }; これで「struct seiseki型」 という新しい型が作成(宣言)された. mathやenglは構造体のメンバ.

構造体型の変数の宣言 struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane, yasu; : } yasuという1個の変数の中に, char name[20], int math, int englの 3個が含まれている. int x, y; なら,intが型, xやyが変数名. 「struct seiseki」が型. sane や yasu が変数名.

メンバ変数へのアクセス (1) ドット(dot)演算子 . (2) アロー(arrow)演算子 -> 構造体変数.メンバ変数 構造体変数aの中の,メンバ変数xにアクセス a.x 構造体へのポインタpが指す構造体の中の,メンバ変数yにアクセス (*p).y (2) アロー(arrow)演算子 -> 構造体変数へのポインタ->メンバ変数 構造体へのポインタpが指す構造体の中の,メンバ変数zにアクセス p->z

メンバ変数へのアクセス (1) ドット演算子 (非ポインタ) struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane, yasu; sane.math = 80; sane.engl = 70; strcpy( sane.name, "saneyasu"); sane.name[0] = 'S'; printf("name=%s, math=%d\n", sane.name, sane.math); } (1) ドット演算子 . 構造体変数 . メンバ変数 実行結果 name=Saneyasu, math=80

メンバ変数へのアクセス (1) ドット演算子 (ポインタ) struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane, yasu; struct seiseki *p; p = &yasu; // アドレス1028~1031に1000が格納される yasu.math = 50; // アドレス1020~1023に50が格納される (*p).engl = 60; printf("math=%d, engl=%d\n", (*p).math, yasu.engl); } (1) ドット演算子 . 構造体変数 . メンバ変数 1000 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 char name[20] int math int engl struct seiseki *p yasu 実行結果 math=50, engl=60

メンバ変数へのアクセス (1) ドット演算子 (ポインタ) struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane, yasu; printf("%p %p\n", &sane, &(sane.name[0])); printf("%p %p\n", &(sane.math), &(sane.engl)); } (1) ドット演算子 . 構造体変数 . メンバ変数 ca18 ca2b ca2c ca2d ca2e caef ca30 ca31 ca32 ca33 char name[20] int math int engl sane 実行結果 0xbfb2ca18 0xbfb2ca18 0xbfb2ca2c 0xbfb2ca30

メンバ変数へのアクセス (1) ドット演算子 (ポインタ) struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane, yasu; struct seiseki *p; p = &yasu; (*p).math = 70; // OK *p.engl = 80; // NG! *(p.engl)=80 の意味になってしまう! } (1) ドット演算子 . 構造体変数 . メンバ変数 演算子の 優先順位に注意!

メンバ変数へのアクセス (2) アロー演算子 (ポインタ) struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane, yasu; struct seiseki *p; p = &sane; strcpy(p->name, "saneyasu"); p->math=10; p->engl=20; p->name[0] = 'S'; printf("name=%s, math=%d\n", p->name, p->math); } (2) アロー演算子 -> 構造体変数へのポインタ -> メンバ変数 p->xyz と (*p).xyz は同義 実行結果 name=Saneyasu, math=10

メンバ変数へのアクセス (ポインタ) ドット演算子 と アロー演算子 struct seiseki sane, yasu; struct seiseki *p; p = &sane; (*p).math = 70; p->engl = 80; ポインタの場合, (*p).math = 70; p->math = 70; のどちらを用いても問題ない. 通常 -> を用いる. アロー演算子は, シンタックスシュガー

構造体の宣言 (1)一般的(?)な構造体宣言と変数宣言 struct hoge{ int x; char y; }; void main(){ struct hoge z; }

構造体の宣言 (2)構造体宣言と変数宣言を別々に struct hoge{ int x; char y; }; struct hoge a, b; void main(){ } struct hogeが型名で, aとbが変数名. aとbはグローバル変数. (3)構造体宣言と変数宣言を同時に struct hoge{ int x; char y; } a, b; void main(){ } struct hogeが型名で, aとbが変数名. aとbはグローバル変数.

構造体の宣言 (3)再掲載 struct hoge{ int x; char y; } a, b; void main(){ } struct hogeが型名で, aとbが変数名. (4)名無し構造体 struct { int x; char y; } a, b; void main(){ } ・その構造体を二度と使わない ・変数を同時に宣言している 場合は,構造体名を省略可能

構造体の宣言 (5)typedefの使用 struct hoge{ int x; char y; }; typedef struct hoge sthoge; void main(){ sthoge a, b; } struct hoge型に, sthoge型という別名を与えた. struct hogeとsthogeが型名, aとbが変数名.

構造体の宣言 (6)構造体宣言とtypedef同時使用 typedef struct hoge{ int x; char y; } sthoge; void main(){ sthoge a, b; } struct hogeとsthogeが型名, aとbが変数名. (7)構造体宣言とtypedef同時使用 typedef struct{ int x; char y; } sthoge; void main(){ sthoge a, b; } 名無し構造体にsthogeの別名を付与. sthogeが型名, aとbが変数名.

構造体の初期化 (1)変数宣言と初期化を同時に struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki sane={"SaneYama",10,20}; struct seiseki yasu={"Yasu",5}; printf("%s %d %d\n",sane.name,sane.math,sane.engl); printf("%s %d %d\n",yasu.name,yasu.math,yasu.engl); } nameに"SaneYama"が, mathに10が, englに20が入る. {"Yasu",5,0} と同じ意味. 省略すると, 0になる. 実行結果 SaneYama 10 20 Yasu 5 0

構造体の初期化 (2)構造体宣言と変数宣言と初期化を同時に struct seiseki{ char name[20]; int math; int engl; } sane={"SaneYama",10,20}; void main(){ printf("%s %d %d\n",sane.name,sane.math,sane.engl); } 実行結果 SaneYama 10 20

構造体の初期化 (3)配列 struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki stu[10] = { {"Taro",10,20}, {"Jiro",30,40}, {"Saburo",50,60} printf("%s %d\n", stu[1].name, stu[1].math); } 実行結果 Jiro 30

構造体の初期化 (4)配列 struct seiseki{ char name[20]; int math; int engl; }; void main(){ struct seiseki stu[10] = { "Taro",10,20, "Jiro",30,40, "Saburo",50,60 printf("%s %d\n", stu[1].name, stu[1].math); } データの対応が正しければ, 内側の括弧{}は 省略可能. 実行結果 Jiro 30

構造体の演算 構造体に対して,以下の演算が可能 代入 (構造体同士の丸ごとコピー) 構造体のアドレス取得 構造体のメンバを参照(紹介済み) 構造体同士の比較はできない if( stu[0] < stu[1] ) はできない メンバ変数の比較は可能

構造体の演算 (1) 構造体同士のコピー struct seiseki{ char name[20]; int math; int engl; }; struct seiseki sane, yasu; strcpy( sane.name, "Saneyasu"); sane.math=30; sane.engl=40; yasu = sane; printf("%s %d\n", yasu.name, yasu.engl); この代入で, saneの中身 (name,math,engl) のすべてが, yasuにコピーされる. name,math,englを 格納可能である入れ物が 2個作成される. 実行結果 Saneyasu 40

構造体の演算 (2) アドレス獲得 & struct seiseki{ char name[20]; int math; int engl; }; &演算子で,構造体の先頭アドレスを取得可能 (以下,再掲載) struct seiseki sane; printf("%p %p\n", &sane, &(sane.name[0])); printf("%p %p\n", &(sane.math), &(sane.engl)); ca18 ca2b ca2c ca2d ca2e caef ca30 ca31 ca32 ca33 実行結果 0xbfb2ca18 0xbfb2ca18 0xbfb2ca2c 0xbfb2ca30 char name[20] int math int engl struct seiseki sane

構造体の演算 (2) アドレス獲得 & struct seiseki{ char name[20]; int math; int engl; }; struct seiseki sane, stu[5]; struct seiseki *p, *q; p = &sane; // アドレスを取得し,pに代入 q = stu; // stu[0]のアドレスをqに代入 Printf("sizeof(struct seiseki)=%d", sizeof(struct seiseki)); printf("&sane=%p\n", p); printf("stu =%p\n", q); printf("stu+2=%p\n", q+2); 実行結果 sizeof(struct seiseki)=28 &sane=0x7fffa1018570 stu =0x7fffa10184e0 stu+2=0x7fffa1018518 4e0 4f3 4f4 f48 4fb 4fc stu と stu+2の 差が 28*2=56 char name[20] int math int engl stu[0] stu[1]

構造体とポインタ 実行結果 p++ : pに格納されているアドレスが1増える. stu[0] 10, stu[1] 30 struct seiseki stu[2]={ {"sane", 10, 20},{"yasu",30,40} }; struct seiseki *p; p = stu; // pにstu[0]のアドレスを入れる printf("stu[0] %d, stu[1] %d\n",stu[0].math,stu[1].math); p->math++; // stu[0]のmathを1増やす. 10から11に変わる. p++; // pを1増やす. pがstu[0]からstu[1]のアドレスになる. p->math++; // stu[1]のmathを1増やす. 30から31に変わる. struct seiseki{ char name[20]; int math; int engl; }; 実行結果 stu[0] 10, stu[1] 30 stu[0] 11, stu[1] 30 stu[0] 11, stu[1] 31 p++ : pに格納されているアドレスが1増える. p->math++ : 「pに格納されているアドレス」に 存在する構造体の中のmathが1増える.

関数引数と構造体 (値渡し) aの中身は 変わっていない 実行結果 hoge: 10 20 main: 10 20 struct seiseki{ char name[20]; int math; int engl; }; void hoge(struct seiseki a){ printf("hoge: %d %d\n", a.math, a.engl); a.math = 90; a.engl = 95; } void main(){ struct seiseki a = {"sane",10,20}; hoge(a); printf("main: %d %d\n", a.math, a.engl); aの中身は 変わっていない 実行結果 hoge: 10 20 main: 10 20

関数引数と構造体 (アドレス渡し) aの中身は 変わっている 実行結果 hoge: 10 20 main: 90 95 struct seiseki{ char name[20]; int math; int engl; }; void hoge(struct seiseki *a){ printf("hoge: %d %d\n", a->math, a->engl); a->math = 90; a->engl = 95; } void main(){ struct seiseki a = {"sane",10,20}; hoge(&a); printf("main: %d %d\n", a.math, a.engl); aの中身は 変わっている 実行結果 hoge: 10 20 main: 90 95

struct score{ int math; int engl; }; void hoge( struct score struct score{ int math; int engl; }; void hoge( struct score *s){ // s[0]の中のmathを100にする } void main(){ struct score s[100]; s[0].math=…; s[0].engl=…; s[1].math=…; s[1].engl=…; : hoge( s ); 練習0

struct score{ int math; int engl; }; void fuga( struct score struct score{ int math; int engl; }; void fuga( struct score *s){ // s[10]の中のmathを100にする } void main(){ struct score s[100]; s[0].math=…; s[0].engl=…; s[1].math=…; s[1].engl=…; : hoge( s ); 練習1

struct score{ int math; int engl; }; void piyo( struct score struct score{ int math; int engl; }; void piyo( struct score *s){ //すべて(s[0]~s[99])の中のmathを100に } void main(){ struct score s[100]; s[0].math=…; s[0].engl=…; s[1].math=…; s[1].engl=…; : hoge( s ); 練習2

練習0 正解 (*s).math = 100; または s->math = 100; 以下はNG *s.math = 100; s.math = 100; 正解 0, 1, 2 練習1 正解 (*(s+10)).math = 100; または (s+10)->math = 100; 以下はNG (*s+10).math = 100; *(s+10).math = 100; *s+10.math = 100; 練習2 正解 int i; for(i=0; i<100; i++){ (s+i)->math = 100; }

入れ子構造体 (1) 構造体の中に構造体 構造体の中に,構造体 struct score{ int math; int engl; }; struct student{ struct score sc; char name[20]; void main(){ struct student sane; strcpy( sane.name, "Saneyasu"); sane.sc.math = 30; sane.sc.engl = 40; printf("%s %d\n", sane.name, sane.sc.math); } 構造体の中に,構造体 struct student型の変数saneの中に, struct score型の変数sがある. それは sane.sc である. struct score型の sane.sc の中に, int型の変数mathがある. それは sane.sc.math である. これで,math,engl,name のすべての箱ができる. 実行結果 Saneyasu 30

入れ子構造体 (2a) 構造体の中に構造体へのポインタ 構造体の中に, 構造体へのポインタ void main(){ struct student sane; : } struct score{ int math; int engl; }; struct student{ struct score *p; char name[20]; これで アドレスを入れる箱p と, charを20個入れるname ができる. intを入れるmath や intを入れるengl は作成されない. 100 101 102 103 104 105 123 p name[20] sane

入れ子構造体 (2a) 構造体の中に構造体へのポインタ 構造体の中に, 構造体へのポインタ void main(){ struct student sane; struct score sc={10,20}; sane.p = &sc; strcpy( sane.name, "Sane"); printf("%d\n", sane.p->math); printf("%d\n", sane.p->engl); printf("%s\n", sane.name); } struct score{ int math; int engl; }; struct student{ struct score *p; char name[20]; saneはアドレスでないので sane. とする 100 101 102 103 104 105 123 124 125 126 127 128 129 130 131 実行結果 10 20 Sane 124 'S' 'a' 10 20 p name[20] math engl sane sc

入れ子構造体 (2b) 構造体の中に構造体へのポインタ void main(){ struct score sc={10,20}; struct student sane; struct student *q; sane.p = &sc; q = &sane; strcpy( q->name, "Sane"); printf("%d\n", q->p->math); printf("%d\n", q->p->engl); printf("%s\n", q->name); } 構造体の中に, 構造体へのポインタ struct score{ int math; int engl; }; struct student{ struct score *p; char name[20]; q はアドレスなので q-> とする 100 101 102 103 104 105 123 124 125 126 127 128 129 130 131 実行結果 10 20 Sane 124 'S' 'a' 10 20 p name[20] math engl sane sc

自己参照型構造体 (1) 800 804 808 812 816 820 824 828 10 808 20 816 30 824 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d; a.data = 10; a.next = &b; b.data = 20; b.next = &c; c.data = 30; c.next = &d; d.data = 40; d.next = NULL; data next data next data next data next a b c d printf("%d ", a.data); printf("%d ", a.next->data); printf("%d ", a.next->next->data); printf("%d\n", a.next->next->next->data); } 実行結果 10 20 30 40

自己参照型構造体 (1) 800 804 808 812 816 820 824 828 10 808 20 816 30 824 40 data next data next data next data next a b c d a b c d data 10 data 20 data 30 data 40 next next next next X リンクリスト

自己参照型構造体 (2) これで p に 800(aのアドレス)が 代入される. 実行結果 10 20 30 40 800 804 808 812 816 820 824 828 10 808 20 816 30 824 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; a.next = &b; b.data = 20; b.next = &c; c.data = 30; c.next = &d; d.data = 40; d.next = NULL; data next data next data next data next a b c d これで p に 800(aのアドレス)が 代入される. p = &a; for(;;){ printf("%d ", p->data); p = p->next; if( p == NULL ){ break; } } 実行結果 10 20 30 40

自己参照型構造体 (2) これで, 「pがNULLでない間は 繰り返す」の意味になる. NULLと0はほぼ同じ. 実行結果 800 804 808 812 816 820 824 828 10 808 20 816 30 824 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; a.next = &b; b.data = 20; b.next = &c; c.data = 30; c.next = &d; d.data = 40; d.next = NULL; data next data next data next data next a b c d これで, 「pがNULLでない間は 繰り返す」の意味になる. NULLと0はほぼ同じ.   p = &a; for(; p; ){ printf("%d ", p->data); p = p->next; } 実行結果 10 20 30 40

自己参照型構造体 (2) もっと短くすることもできる. 実行結果 10 20 30 40 800 804 808 812 816 820 824 828 10 808 20 816 30 824 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; a.next = &b; b.data = 20; b.next = &c; c.data = 30; c.next = &d; d.data = 40; d.next = NULL; data next data next data next data next a b c d もっと短くすることもできる. for(p=&a; p; ){ printf("%d ", p->data); p = p->next; } 実行結果 10 20 30 40

自己参照型構造体 (2) もっと短くすることもできる. 実行結果 10 20 30 40 800 804 808 812 816 820 824 828 10 808 20 816 30 824 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; a.next = &b; b.data = 20; b.next = &c; c.data = 30; c.next = &d; d.data = 40; d.next = NULL; data next data next data next data next a b c d もっと短くすることもできる. for(p=&a; p; p = p->next){ printf("%d ", p->data); } 実行結果 10 20 30 40

自己参照型構造体 (3) リストからbを削除 a.next = a.next->next; a b c d data 10 data 20 data 30 data 40 next next next next X リストからbを削除 a.next = a.next->next; a b c d data 10 data 20 data 30 data 40 next next next next X

自己参照型構造体 (3) 800 804 808 812 816 820 824 828 10 816 20 816 30 824 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; a.next = &b; b.data = 20; b.next = &c; c.data = 30; c.next = &d; d.data = 40; d.next = NULL; data next data next data next data next a b c d a.next = a.next->next; p = &a; for(;;){ printf("%d ", p->data); p = p->next; if( p == NULL ){ break; } } 実行結果 10 30 40

自己参照型構造体 (4) bとcの順を交換 旧:a→b→c→d 新:a→c→b→d a b c d data 10 data 20 data 30 data 40 next next next next X bとcの順を交換 旧:a→b→c→d 新:a→c→b→d a b c d data 10 data 20 data 30 data 40 next next next next X

自己参照型構造体 (4) 800 804 808 812 816 820 824 828 10 816 20 824 30 808 40 #include <stdio.h> struct dp{ int data; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; : d.next = NULL; p = &a; struct dp *x, *y, *z; x = p->next; y = p->next->next; z = p->next->next->next; data next data next data next data next a b c d x->next = z; y->next = x; p->next = y; for(;;){ printf("%d ", p->data); p = p->next; if( p == NULL ){ break; } } 実行結果 10 30 20 40

自己参照型構造体 (5) 双方向リスト #include <stdio.h> struct dp{ int data; struct dp *prev; struct dp *next; }; void main(){ struct dp a, b, c, d, *p; a.data = 10; a.prev = NULL; a.next = &b; b.data = 20; b.prev = &a; b.next = &c; c.data = 30; c.prev = &b; c.next = &d; d.data = 40; d.prev = &c; d.next = NULL; p = &a; : } 800 804 808 812 816 820 824 828 832 836 840 844 10 812 20 800 824 30 812 828 40 824 data prev next data prev next data prev next data prev next a b c d

自己参照型構造体 (5) a b c d data 10 data 20 data 30 data 40 prev X prev prev next next next next X

自己参照型構造体 (練習) 双方向リスト #include <stdio.h> struct dp{ int data; struct dp *prev; struct dp *next; }; void main(){ struct dp *p, *q; struct dp x; : p = …; q = p-> next; /* p の次が q である. p と q の間に x を挿入するには? */ ??? : }

自己参照型構造体 (練習) cとdの間にxを挿入交換 旧:… b ←→ c ←→ d 新:… b ←→ c ←→ x ←→ d a b c data 10 data 20 data 30 data 40 prev X prev prev prev next next next next X cとdの間にxを挿入交換 旧:… b ←→ c ←→ d 新:… b ←→ c ←→ x ←→ d x data 100 prev (2) (1) next a b c d data 10 data 20 data 30 (3) data 40 (4) prev X prev prev prev next next next next X

自己参照型構造体 (正解) 双方向リスト #include <stdio.h> struct dp{ int data; struct dp *prev; struct dp *next; }; void main(){ struct dp *p, *q; struct dp x; : p = …; q = p-> next; p->next = &x; /* (1) */ q->prev = &x; /* (2) */ x.prev = p; /* (3) */ /* x.prev = &p; は NG */ x.next = q; /* (4) */ /* x.next = &q; は NG */ : }