• 検索結果がありません。

02: 変数と標準入出力

N/A
N/A
Protected

Academic year: 2021

シェア "02: 変数と標準入出力"

Copied!
25
0
0

読み込み中.... (全文を見る)

全文

(1)

13: 構造体

Linux にログインし、以下の講義ページ

を開いておくこと

http://www-it.sci.waseda.ac.jp/

teachers/w483692/CPR1/

2015-07-06

C プログラミング入門

総機1 (月1)

1

(2)

例題:多角形の面積

2015-07-06 C プログラミング入門 総機1 (月1)

2

𝒑

0

𝒑

1

𝒑

2

𝒑

3

𝒑

4

𝑆

𝑆

= �

𝑇

𝑖

𝑛−1

𝑖=0

= �

1

2

𝒑

𝑖

𝒑

𝑖+1

𝑛−1

𝑖=0

𝑇

0

𝜃

𝟎

where 𝒑

𝑛

= 𝒑

0

この計算は、𝑇𝑖 を符号付き面積とし、頂点の順に 番号付けを行うことで、原点の位置によらない。 二次元の位置ベクトル n = 5 (5角形) の例 原点 (ゼロベクトル)

(3)

2015-07-06 C プログラミング入門 総機1 (月1)

3

例題:多角形の面積

// n 個の x 座標列 px と, y 座標列 py の作る多角形の面積

// ただし、点は左回りに並んでいるとする

double PolygonArea(double *px, double *py, int n) {

double S = 0.0; int i; for(i = 0; i < n; ++i) {

S += TriangleArea(px[i], py[i], px[(i+1)%n], py[(i+1)%n]); } return S; } 1.0 −2.4 −5.0 −1.5 2.0 1.0 1.3 −0.2 −2.0 −0.3 *px *py double px[] と書いてもよい 1 つ目の点の座標 i == n-1 の時、 0 となる

(4)

2015-07-06 C プログラミング入門 総機1 (月1)

4

例題:多角形の面積

// 3点 (0,0), (x1, y1), (x2, y2) のなす三角形の面積

// 時計回りに並んでいる場合正、そうでない場合は負となる

double TriangleArea(double x1, double y1, double x2, double y2) {

return (x1*y2 - x2*y1) / 2.0; }

𝒑

1

= 𝑥

1

, 𝑦

1

𝑇

𝜃

𝟎

𝒑

2

= 𝑥

2

, 𝑦

2

𝑇 =

1

2 𝒑

1

𝒑

2

sin 𝜃 =

1

2

𝒑

1

𝒑

2

=

1

2 𝑥

1

𝑦

2

− 𝑥

2

𝑦

1

(5)

観察ポイント

点の座標 x, y がバラバラに扱われている

関数の引数の数が多い

点を表す新しい型を作れないか?

たとえば…

2015-07-06 C プログラミング入門 総機1 (月1)

5

例題:多角形の面積

引数の総数が 減っている バラバラに扱う場合 POINT という型で表した場合 double PolygonArea(double *px,

double *py, int n);

double PolygonArea(

int n);

POINT

*

p

,

double TriangleArea(double x1,

(6)

複数の変数をまとめて一つの変数として扱う

方法

int や double といった型と同じように使用

可能

2015-07-06 C プログラミング入門 総機1 (月1)

6

構造体の概要

typedef struct { double x, y; } Point; 構造体 Point 型の定義 { double S; Point P1 = { 1, 2 }; Point P2 = { -2, 1 }; S = TriangleArea(P1, P2); ... 構造体 Point 型を使ったコード

今日の目標:

このようなコードを書けるようになること

(7)

構造体の定義

構造体型の変数と typedef

構造体の初期化

構造体の読み書き

構造体のコピー

関数による構造体の扱い

構造体へのポインタ

2015-07-06 C プログラミング入門 総機1 (月1)

7

構造体の説明目次

(8)

構造体は一つのメモリ領域に複数の変数を格

納する

それぞれをメンバ

(member)

という

2015-07-06 C プログラミング入門 総機1 (月1)

8

構造体の定義

struct

TagName

{

int x, y;

double a, b, c;

}

;

キーワード 構造体を区別するためのタグ名 任意個数のメンバ変数 セミコロンで終わる

(9)

型名として "

struct TagName

" を使う

2015-07-06 C プログラミング入門 総機1 (月1)

9

構造体型の変数

... struct Point { double x, y; }; int main(void) { struct Point p1, p2; ... double x double y struct Point p1 double x double y struct Point p2 メモリ上のレイアウ ト(順番や隙間の大 きさ)は環境による 「struct + タグ名」で 一つの型名を構成する

(10)

struct

キーワードを付けるのは面倒なので、

多くの場合 typedef を使って別名を定義

2015-07-06 C プログラミング入門 総機1 (月1)

10

構造体型の変数

...

typedef struct Point

{ double x, y; } Point; int main(void) { struct Point p1; Point p2; ... double x double y struct Point p1 double x double y struct Point p2 1 単語で型名を書ける 構造体型を Point とい う型名として定義する タグ名と型名は同じで構わない タグ名を _Point や Point_tag の様 に区別する流儀もある また、構造体の別名をすべて大文字 で表す流儀もある この場合、タグ名を省略してもよい

(11)

構造体の初期化は、配列と似た記法を用いる

初期化をしない自動変数の値は不定

2015-07-06 C プログラミング入門 総機1 (月1)

11

構造体の初期化

... typedef struct { double x, y; } Point; int main(void) { Point p1 = { 1.0, 2.0 }; Point p2; ... 1.0 double x 2.0 double y struct Point p1 ? double x ? double y struct Point p2 通常の変数と同様 メンバのかかれて いる順に与える 初期化が一部のみ指 定されている場合は、 残りはすべてゼロと なる

(12)

同じ構造体の別の変数を与えることにより、

すべてのメンバのコピーで初期化する

2015-07-06 C プログラミング入門 総機1 (月1)

12

構造体の初期化

... typedef struct { double x, y; } Point; int main(void) { Point p1 = { 1.0, 2.0 }; Point p2 = p1; ... 1.0 double x 2.0 double y struct Point p1 1.0 double x 2.0 double y struct Point p2 配列との大きな違い すべてのメンバが コピーされる

(13)

構造体のメンバは

.

演算子を使う

2015-07-06 C プログラミング入門 総機1 (月1)

13

構造体のアクセス

... typedef struct { double x, y; } Point; int main(void) { Point p1 = { 1.0, 2.0 }; printf("p1=(%f,%f)¥n", p1.x, p1.y); p1.x = -p1.y; printf("p1=(%f,%f)¥n", p1.x, p1.y); ... p1=(1.000000,2.000000) p1=(-2.000000,2.000000) 1.0 double x 2.0 double y struct Point p1 メンバ変数を読む メンバ変数に代入する 出力

(14)

構造体は代入演算子によりコピーできる

2015-07-06 C プログラミング入門 総機1 (月1)

14

構造体のコピー

... typedef struct { double x, y; } Point; int main(void) { Point p1 = { 1.0, 2.0 }; Point p2 = p1; Point p3; p3 = p1; ... 初期化のイコール 代入演算子によるコピー

(15)

構造体は関数の引数、戻り値として使える

2015-07-06 C プログラミング入門 総機1 (月1)

15

関数で構造体を扱う

... typedef struct { double x, y; } Point; // 中点を計算し戻り値として返す

Point midpoint(Point p1, Point p2) {

double mx = (p1.x + p2.x)/2.0; double my = (p1.y + p2.y)/2.0; Point m = { mx, my }; return m; } int main(void) { Point st = { 1.0, 0.0 }; Point ed = { 2.0, 2.0 }; Point md; md = midpoint(st, ed); ... 仮引数へコピーされる 戻り値がコピーされる 配列と異なる 実引数がコピーが 渡される

(16)

構造体のメンバに配列を持たせることで、配

列のコピーを行うこともできる

2015-07-06 C プログラミング入門 総機1 (月1)

16

構造体の配列メンバ

... typedef struct {

char name[20]; int age;

} Person; int main(void) { Person X = { "Taro", 22 }; Person Y; Y = X; Y.name = X.name; "Taro" char name[20] 22 int age Person X "Taro" char name[20] 22 int age Person Y 配列のコピー 配列の直接のコピーは できない 配列を含む構造体自体 のコピーは可能

(17)

システムのメモリ領域

ポインタ変数は単純にアドレス値のコピー

ポインタの先はコピーしないので浅いコピー

(shallow copy)

と呼ばれる

2015-07-06 C プログラミング入門 総機1 (月1)

17

構造体のポインタ変数メンバ

typedef struct {

char *name; int age;

} Person; int main(void) { Person X = { "Taro", 22 }; Person Y; Y = X; Y.name = X.name; char *name 22 int age Person X char *name 22 int age Person Y アドレスのコピー この代入と同等 中のポインタはアドレ スがコピーされる "Taro" 配列ではなくポインタ

(18)

変数の種類 宣言 初期化 代入演算子に よるコピー 基本型 int x; = 25; 可能 配列 文字配列 int a[10]; = { 1, 2, 3 }; 不可能 char s[256]; = "string literal";

構造体 Pointstruct P; Point P; = Q; (= { 20ほかの構造体変数) , 30 }; 可能 (内容全体)

ポインタ変数 int *p; = &var; 可能 (アドレス値)

char *pstr; = "string literal";

2015-07-06 C プログラミング入門 総機1 (月1)

18

変数の比較

構造体のサイズが大きい場合はコピー に時間がかかることに注意 アドレス演算子や malloc() の戻り値からアドレスを得る

typedef struct Point {...} Point; を定義した場合

(19)

以下の場合に使われる

構造体を直接変更する必要がある場合

構造体のコピーに時間がかかるのを避けたい場合

2015-07-06 C プログラミング入門 総機1 (月1)

19

構造体へのポインタ

... // 点の座標を原点に変更する

void setOrigin(Point *p) { (*p).x = 0; (*p).y = 0; } ポインタ p の内容を読むために、まず デリファレンス演算子 * が必要 p の指す構造体のメンバにアクセスす るために . 演算子を使うのだが、演算 子の優先順位の関係で括弧が必要とな る。

(20)

(*p).x

という記述を簡略化するためにアロー

演算子 p

->x

が用意されている

ポインタ p が指す構造体のメンバを直接矢印で指

しているイメージ

2015-07-06 C プログラミング入門 総機1 (月1)

20

構造体へのポインタ (アロー演算子)

... // 点の座標を原点に変更する

void setOrigin(Point *p) {

p->x = 0; p->y = 0; }

(21)

通常の配列と同じ

動的メモリで確保する場合は sizeof を使う

2015-07-06 C プログラミング入門 総機1 (月1)

21

構造体の配列・動的メモリ

... { int i; Point points[10]; for(i = 0; i < 10; ++i) { points[i].x = i; points[i].y = i*i; ... ... { int i;

Point *points=malloc(sizeof(Point)*10);

for(i = 0; i < 10; ++i) { points[i].x = i; points[i].y = i*i; ... 10 要素の配列変数の場合 10 要素の動的メモリの場合 添え字演算子の優先順位のほうが高い

(22)

関連する情報を一つにまとめることができる

他の変数と同じように扱える

関数などでのやり取りが簡潔になる

ポインタを介した操作が(さらに)理解しに

くい

普通の変数なら

.

演算子

ポインタ変数なら

->

演算子

2015-07-06 C プログラミング入門 総機1 (月1)

22

構造体の利点・欠点

(23)

<stdio.h> の FILE

OpenCV

(一般のライブラリの一つ) の

CvPoint, CvSize, CvRect など

秋期「C プログラミング」で扱うリンクリス

トや木のようなデータ構造

C++ では変数だけでなく関数も持てるよう

に拡張されている (クラスと呼ばれる)

2015-07-06 C プログラミング入門 総機1 (月1)

23

構造体の例

(24)

構造体の変数を以下の構文で直接定義するこ

とができるが、あまり使用されない。

struct TagName { ... } varname;

今までの例では最後の変数名を省略し、型の定義

のみを行っている

構造体にビット単位でアクセスすることを可

能にするビットフィールドという機能がある

講義では省略する

メモリ効率やバイナリレベルでの互換性のために

使われるが、通常は使用しない

2015-07-06 C プログラミング入門 総機1 (月1)

24

構造体の細かい話 (1)

(25)

C99 での新機能

メンバ名を指定した初期化

(Designated Initializer)

例: Point P = {

.y = 10, .x = 20 };

最後のメンバとしてサイズを指定しない配列が書

ける (0長配列)

構造体をリテラルとして書く複合リテラル

(compound literal) 2015-07-06 C プログラミング入門 総機1 (月1)

25

構造体の細かい話 (2)

参照

関連したドキュメント

2008 ) 。潜在型 MMP-9 は TIMP-1 と複合体を形成することから TIMP-1 を含む含む潜在型 MMP-9 受 容体を仮定して MMP-9

などに名を残す数学者であるが、「ガロア理論 (Galois theory)」の教科書を

注:一般品についての機種型名は、その部品が最初に使用された機種型名を示します。

 我が国における肝硬変の原因としては,C型 やB型といった肝炎ウイルスによるものが最も 多い(図

・Squamous cell carcinoma 8070 とその亜型/変異型 注3: 以下のような状況にて腫瘤の組織型が異なると

このうち、大型X線検査装置については、コンテナで輸出入される貨物やコンテナ自体を利用した密輸

つまり、p 型の語が p 型の語を修飾するという関係になっている。しかし、p 型の語同士の Merge

①就労継続支援B型事業においては、定員32名のところ、4月初日現在32名の利用登録があり、今