プログラミング入門2 ポインタについて補足 構造体 第11回 芝浦工業大学情報工学科 青木 義満、篠埜 功

Slides:



Advertisements
Similar presentations
プログラミング入門2 芝浦工業大学情報工学科青木 義満 第11回構造体. プログラミング入門2 2 構造体 5 人分のサッカー選手データ 全てのデータを関数に渡して,処理する場合 char name[5][256]; int assist[5]; int score[5]; void func( char.
Advertisements

C 言語講座第 5 回 構造体. 構造体とは ... 異なる型の値をまとめて新しい型とする 機能がある . つまり , 複数の変数を 1 つのまとまりにできる . 配列と違って同じ型でデータをまとめるのではな く違った型のデータをまとめられる .
アルゴリズムとデータ構造 第2回 線形リスト(復習).
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第3回 配列(1) 情報・知能工学系 山本一公
プログラミング入門2 第1回 イントロダクション 芝浦工業大学情報工学科 青木 義満
ポインタ プログラミング入門2 第10回 芝浦工業大学情報工学科 青木 義満
プログラミング入門2 第4回 配列 for文 変数宣言 初期化
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 動的な領域確保 情報工学科 篠埜 功.
第12回新しい型と構造体.
第13回構造体.
課題解説: 関数の引数にポインタを使って2数を入れ替える
第12回構造体.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第1回 導入 情報工学科 篠埜 功.
プログラミング入門2 第6回 関数(2) 芝浦工業大学情報工学科 青木 義満
構造体.
第16章 構造体 16.1 構造体の定義と構造体変数 16.2 構造体の配列.
プログラミング入門2 第12回 データ型 関数のプロトタイプ宣言 動的な記憶域確保 芝浦工業大学情報工学科 青木 義満
演習問題の答え #include #include #define NUM 5 typedef struct { // 構造体の定義 float shincho; // 身長 float taiju; // 体重 } shintai; void hyouji(shintai.
プログラミング入門2 第3回 繰り返し文 芝浦工業大学情報工学科 青木 義満
第3回 配列,構造体,ポインタ ~ データ構造について学ぶための基礎~
構造体 プログラミング入門2 芝浦工業大学情報工学科 青木 義満
プログラミング 3 構造体(1).
第10回 プログラミングⅡ 第10回
第16章 構造体 16.1 構造体の定義と構造体変数 16.2 構造体の配列.
プログラミング入門2 第2回 型と演算 条件分岐 篠埜 功.
プログラミング入門2 第5回 関数(1) 芝浦工業大学情報工学科 青木 義満
プログラミング入門2 ファイルの入出力 ポインタ 芝浦工業大学情報工学科 青木 義満
Computer Graphics 第3回 座標変換 芝浦工業大学情報工学科 青木 義満
第11回 宿題 出題日:12月21日 締切日:1月7日(木).
精密工学科プログラミング基礎 第10回資料 (12/18実施)
プログラミング入門2 第12回 構造体の配列 データ型 関数のプロトタイプ宣言 動的な記憶域確保 芝浦工業大学情報工学科
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
第10章 これはかなり大変な事項!! ~ポインタ~
プログラミング入門2 第8回 ポインタ 情報工学科 篠埜 功.
プログラミング入門2 第2回 型と演算 条件分岐 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
地域情報学 C言語プログラミング 第5回 ポインタ、関数、ファイル入出力 2017年11月17日
プログラミング入門2 第11回 共用体、列挙体 情報工学科 篠埜 功.
第11回 プログラミングⅡ 第11回
プログラミング入門 第12回 情報工学科 篠埜 功.
プログラミング入門 第12回 情報工学科 篠埜 功.
プログラミング入門2 第12回 データ型 関数のプロトタイプ宣言 動的な記憶域確保 芝浦工業大学情報工学科 青木 義満
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
メモリとメモリアドレス, ポインタ変数,関数へのポインタ渡し
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
精密工学科プログラミング基礎Ⅱ 第5回資料 今回の授業で習得してほしいこと: 構造体 (教科書 91 ページ)
構造体と共用体.
プログラミング入門2 第9回 ポインタ 情報工学科 篠埜 功.
プログラミング 3 2 次元配列.
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
プログラミング入門2 第5回 配列 for文 変数宣言 初期化
プログラミング論 構造体
プログラミング入門 第12回 情報工学科 篠埜 功.
プログラミング入門2 第2回 型と演算 条件分岐 篠埜 功.
プログラミング 4 文字列.
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
マスク合成(のような処理) 出力画像 Out 入力画像1 In1 In1 In2 Out 入力画像2 In
プログラミング入門2 第5回 配列 変数宣言、初期化について
情報処理Ⅱ 小テスト 2005年2月1日(火).
C言語講座第5回 2017 構造体.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
Presentation transcript:

プログラミング入門2 ポインタについて補足 構造体 第11回 芝浦工業大学情報工学科 青木 義満、篠埜 功 I’ll get started with Introduction and Conventional works around our study, then mention our motivation and goal. Next, I’ll explain our 3D Face Modeling Method and its medical application. Finally, I’ll conclude this presentation with some future works. 芝浦工業大学情報工学科 青木 義満、篠埜 功

ポインタについて補足(20分程度) ポインタには型がある。 指す先の型に応じて型が異なる。 ポインタとは アドレス。ポインタ型(指す先の型がのとき * 型)を持つ。型に応じて、演算が異なる。 ポインタ型の変数とは     *型の変数( *p; のように宣言) は、型のサイズ(sizeof で取得可能)の領域のアドレスを保持するための変数。右辺値としてそのアドレスを持つ。(左辺値は、その変数自身のアドレス) (例) int x; int * p; x = 1; p = &x; 30番地 p用の領域(4byte) 34番地 x用の領域(4byte) プログラミング入門2

ポインタについて補足(20分程度) ポインタ型の演算 ポインタ型の式 と int型 の式は加算(型に応じて異なる)を行える。 型が同じポインタ同士は減算(型に応じて異なる)を行える。 eが へのポインタ型 ( * 型)の式のとき、式 *e の型は 型である。 eが へのポインタ型 ( * 型)の式のとき、式 *e は、eの指す先(eの評価結果の値(これはアドレス)およびによって決まる値)を右辺値、eの右辺値を左辺値として持つ。 30番地 p用の領域(4byte) (例) int x; int * p; x = 2; p = &x; /* pに34が代入される */ p = p + 1; /* 4が足され、pに38が代入される */ x = p - &x; /* pと&xは同じ型(int *型)であり、 (38 – 34) / 4 で、xに1が代入される */ p = p – 1; /* 4が引かれ、pに34が代入される */ 34番地 x用の領域(4byte) プログラミング入門2

ポインタについて補足(20分程度) &演算子について 左辺値を持つ式に&を付けることができる。 左辺値を持つ式の例 変数 配列型の式 *が一番外側についた式(e[i]の形の式もこれに該当) 左辺値をもたない式の例      1 など、基本型の式 一番外側が&になっている式 --- &(&e)の形の式は、eがとのような式であっても許されない。 プログラミング入門2

ポインタについて補足(20分程度) ポインタ型と配列型の違い ポインタ型の式は代入文(代入式)の左辺に書けるが、配列型の式は代入文(代入式)の左辺に書くことは許されない。 int x; /* x をint型として宣言 */ int *p; /* pをポインタ型 (int * 型)ととして宣言 */ p = &x; /* 式 p も 式 &x もともにポインタ型 (int * 型) */ はOKだが、 int a [3]; /* a を配列型 (int [3]型)として宣言 */ a = &x; /* 式a は配列型(int [3]型), 式&xはポインタ型(int *型) */ は許されない(コンパイル時にエラーになる)。 配列型の式(の右辺値)はアドレスの定数である(代入できない)。ただし、配列型の式は左辺値を持つ(次ページ参照)。 プログラミング入門2

ポインタについて補足(20分程度) 配列の左辺値について (例) int main () { int a [10]; printf (“%p\n”, a); /* aの値は、a[0]のアドレス &(a[0]) */ printf (“%p\n”, &a); /* &aの値は、aのアドレス */ printf (“%p\n”, a+1); /* 4が足される */ printf (“%p\n”, (&a)+1); /* 40が足される */ return 0; } 式a と 式&aの値(右辺値)は同じだが、型が異なる。 式a は 要素数10の配列型(int [10]型)。 式&aは要素数10の配列へのポインタ型(int (*) [10] 型)。 intが4byteの場合 int a[10][10][10][10]; と宣言されている場合を考えてみると、式 a, a[0], a[0][0], a[0][0][0], a[0][0][0][0] の左辺値(アドレス)はすべて等しいが、型が異なる。

構造体 3人分の学生の身体検査のデータ char name[3][20]; /* 3人分の学生の名前 */ int height[3]; /* 3人分の学生の身長 */ double weight[3]; /* 3人分の学生の体重 */ 全てのデータを関数に渡して,処理する場合 void func ( char name[ ][20], int height[ ], int weight[ ] ); void func ( char (* name) [20], int (*height), int (*weight)); という宣言と同一の意味を持つ。 各学生の情報が、3つの配列にばらばらに格納される。 => ひとつにまとめたい。 プログラミング入門2

構造体とは? 3人の学生の身体検査のデータ name[0] = “Taro”; height[0] = 176; char name[3][20]; /* 3人分の学生の名前 */ int height[3]; /* 3人分の学生の身長 */ double weight[3]; /* 3人分の学生の体重 */ 1人目のデータ 2人目のデータ 3人目のデータ name[0] = “Taro”; height[0] = 176; weight[0] = 64.5 name[1] = “Jiro”; height[1] = 165; weight[1] = 55.5; name[2] = “Saburo”; height[2] = 168; weight[2] = 70.0 各人の3つのデータが別々の配列に入っている。 各人のデータを1つにまとめたい。 プログラミング入門2

構造体とは? 構造体とは,複数の型のデータをひとまとめにしたデータ構造 char [20] 型 int 型 double 型 “Taro” 名前 身長 体重 char [20] 型 int 型 double 型 名前 身長 体重 “Taro” 176 64.5 名前 身長 体重 “Jiro” 165 55.5 名前 身長 体重 “Saburo” 168 70.0 プログラミング入門2

構造体型 struct { 変数宣言1; 変数宣言2; … } (例) struct { char name[20]; これまで、複合型(基本データを組み合わせて得られる型)として、配列型、ポインタ型、関数型などを扱ってきた。構造体型も複合型である。構造体型は、いくつかの変数宣言がまとまったものであり、以下の形のものである。 struct { 変数宣言1; 変数宣言2; … } (例) struct { char name[20]; int height; double weight; } 名前 身長 体重 char [20] 型 int 型 double 型 プログラミング入門2

構造体型の変数宣言 構造体型の変数宣言 を構造体型を表す型式とすると、  変数名; で宣言する。(通常の変数宣言と同じ) taro taro.name (例) struct { char name[20]; int height; double weight; } taro; taro 20byte taro.height 4byte taro.weight 8byte 宣言する変数名 プログラミング入門2

構造体のメンバーアクセス eがメンバーmを持つ構造体型の式のとき、e.mで構造体のメンバーが得られる。 (例)taroを前頁の構造体型の変数として宣言する。 struct { char name[20]; int height; double weight; } taro; taro.name, taro.height, taro.weightで各メンバーにアクセスできる。 (例) taro.name[0] = ‘T’; taro.name[1] = ‘a’; taro.name[2] = ‘r’; taro.name[3] = ‘o’; taro.name[4] = ‘\0’; taro.height = 176; taro.weight = 64.5; プログラミング入門2

typedefの使用 構造体を使うとき、構造体型に、typedefで名前を付けると便利がよい。 の形で使う。 (例) typedef int aaa; と宣言すると、aaaはintの別名。 typedef int bbb [3];と宣言すると、bbbはint [3]型の別名。 前ページの構造体型にstudentという名前を付ける。 構造体型の変数宣言 struct { char name[20]; int height; double weight; } taro; typedef struct { char name[20]; int height; double weight; } student; 比較 この宣言以降では、student a; などの宣言で構造体型の変数が宣言できる。 プログラミング入門2

構造体を使ったプログラム(構造体のメンバ) ソースファイル名:list1203.c (p.274, 若干変更) 構造体メンバへの値の代入と表示 #include <stdio.h> #include <string.h> /* 文字列操作関数用 strcpy使用のため*/ typedef struct{ char name[20]; /* 名前 */ int height; /* 身長 */ double weight; /* 体重 */ } student; int main(void) { student taro; /* 構造体メンバへの値の代入 */ strcpy(taro.name, “Taro"); /* 文字列Taroをtaro.nameにコピー */ taro.height = 176; /* 身長 */ taro.weight = 64.5; /* 体重 */ /* 構造体メンバの表示 */ printf("氏 名 = %s\n", taro.name); printf("身 長 = %d\n", taro.height); printf("体 重 = %f\n", taro.weight); return (0); } プログラミング入門2

構造体変数の初期化の構文 ソースファイル名:list1204.c (p.275, 若干変更) 構造体メンバの初期化 /* 学生を表す構造体型のtaroを初期化 */ #include <stdio.h> typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ double weight; /* 体重 */ } student; int main(void) { student taro = {“Taro", 176, 64.5}; printf("氏 名 = %s\n", taro.name); printf("身 長 = %d\n", taro.height); printf("体 重 = %f\n", taro.weight); return (0); } 構造体メンバの初期化は{ } を使って記述できる。 初期化時は、”Taro”と書くことによってtaro.nameの先頭から順に’T’, ‘a’, ‘r’, ‘o’, ‘\0’が代入される。(char配列の初期化と同じ) プログラミング入門2

構造体同士の値の代入 (p.280) student taro; student jiro = {“Jiro”, 165, 55.5}; 同じ型の構造体データであれば,互いに値を代入することが可能 student taro; student jiro = {“Jiro”, 165, 55.5}; …….. taro = jiro; jiro.name, jiro.height, jiro.weight をそれぞれtaro.name. taro.height, taro.weightに代入する。 プログラミング入門2

復習: 配列のコピー 注意点 (p.93) vb = va ; for (i = 0; i < 5; i++) va[5], vb[5] と2つの配列は要素数も同じだし,もっと簡単に次のように代入できないの? vb = va ; for (i = 0; i < 5; i++) vb[i] = va[i]; 面倒でも,1つ1つ代入していく 復習 (1) 配列型の式eの右辺値は、その先頭要素e[0]のアドレス(&e[0])。 (2) 配列型の式は左辺値はもつが、定数なので、代入式(代入文)の左辺には書けない。 プログラミング入門2

関数での構造体データの使用(値変更なし) ソースファイル名:struct1.c 関数への構造体データの受け渡し(値は変更しない) #include <stdio.h> typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; void print_data( student  std ) { printf("氏 名 = %s\n", std.name); printf("身 長 = %d\n", std.height); printf("体 重 = %f\n", std.weight); } int main(void) student taro = {“Taro", 176, 64.5}; print_data( taro ); return (0); 構造体データを受け取り, 値を表示する関数 値を変更しない→ポインタでなくてOK プログラミング入門2

関数での構造体データの使用(値変更あり) ソースファイル名:struct2.c 関数への構造体データの受け渡し(値の変更あり) #include <stdio.h> typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ double weight; /* 体重 */ } student; void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } int main(void) student taro = {“Taro", 176, 64.5}; change_data( &taro ); printf("氏 名 = %s\n", taro.name); printf("身 長 = %d\n", taro.height); printf("体 重 = %f\n", taro.weight); return (0); 構造体データを受け取り, 値を変更する関数 値を変更する→ポインタ(アドレス)で受け取り! プログラミング入門2

解説 構造体のポインタ渡し (注意) *std.heightと書くと、 *(std.height)と解釈される。 *stdはtaro のエイリアス void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } taro 106番地 106 change_data( &taro ); std (注意) *std.heightと書くと、 *(std.height)と解釈される。 student型のオブジェクトのアドレス を入れるための箱 (student型オブジェクトへのポインタ) プログラミング入門2

= アロー(->)演算子 eが構造体(型)へのポインタ型( * 型)の式のとき、その構造体のメンバm は (*e).m void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } void change_data( student *std ) { std->height = 180; std->weight = 80.0; } = change_data( &taro ); eが構造体(型)へのポインタ型( * 型)の式のとき、その構造体のメンバm は (*e).m で得られるが、これは e -> m と書いてもよい(syntax sugar)。 プログラミング入門2

関数での構造体データの使用(値変更あり) ソースファイル名:struct3.c(p.277,変更あり) 関数への構造体データの受け渡し(値の変更あり,アロー演算子使用) #include <stdio.h> typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; void change_data( student *std ) { std->height = 180; std->weight = 80.0; } int main(void) student taro = {“Taro", 176, 64.5}; change_data( &taro ); printf("氏 名 = %s\n", taro.name); printf("身 長 = %d\n", taro.height); printf("体 重 = %f\n", taro.weight); return (0); 構造体データを受け取り, 値を変更する関数 値を変更する→ポインタ(アドレス)で受け取り! プログラミング入門2

S 今日の課題1(第11回)(kadai11-1.c) キーボードから3点の2次元座標値(x, y)を読み込み, p2 S = (ax, ay) = (bx, by) p3 のとき、S = ½ | ax by – ay bx | p1 但し,座標を格納する構造体として以下のものを用いること。 typedef struct { double x; double y; } point; (注) double型の値の読み込みは、 scanf (“%lf”, &e); の様にする。ここで、eは、左辺値を持つdouble型の式(double型の変数など)。 表示の場合は%fでOK。(printf (“%f”, p.x)等。) 面積を求める関数は、座標を表すpoint型の引数p1, p2, p3を受け取り、面積をdouble型で求め、それを返り値として返す関数として定義せよ。    double size (point p1, point p2, point p3) { … } プログラミング入門2

今日の課題2(第11回) (kadai11-2.c) キーボードから2つの複素数を読み込み、その2つの複素数の和を出力するプログラムを作成せよ。ただし、複素数を表すために、以下の構造体 complex を用い、複素数の和は、関数を呼び出す形で求めよ。複素数のキーボードからの入力、画面への出力の形式は自由とする。 typedef struct { double re; double im; } complex; 和を求める関数は、複素数を表すcomplex型の引数num1, num2を受け取って、それらの和を表すcomplex型の値を返す関数として定義せよ。 complex sum (complex num1, complex num2) { …. } プログラミング入門2