【c++builder starter チュートリアルシリーズ】シーズン2 c++builderの部 第5回...

28
© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. 第5回 配列 と 構造体シーズン2:プログラミング言語をやさしく覚えよう C++Builderの部

Upload: -

Post on 22-Mar-2017

47 views

Category:

Engineering


4 download

TRANSCRIPT

© 2017 Embarcadero Technologies, Inc.

All rights reserved. Proprietary and confidential.

第5回

‟配列 と 構造体„

シーズン2:プログラミング言語をやさしく覚えよう

C++Builderの部

2© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

Delphi / C++Builder Starter チュートリアルシリーズ

シーズン2 :2017年1月23日 ~ 3月27日 全 9 回

時間 :毎週月曜 17 時 00分~17時 50分

Delphi 17時00分~17時20分 / C++Builder 17時30分~17時50分

ねらい :プログラミング言語をやさしく覚えようシーズン2

第1回 2017年1月23日 シューティングゲームのプログラム

第2回 1月30日 変数と型

第3回 2月6日 条件 とループ

第4回 2月13日 関数

第5回 2月20日 配列 と 構造体

第6回 2月27日 文字列と オブジェクト

第7回 3月6日 オブジェクト指向

第8回 3月13日 作ってみよう(1)

第9回 3月27日 作ってみよう(2)

セミナー情報 : 下記のWebサイト

http://forms.embarcadero.com/starter-tutorial-webinar

3© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

第5回「配列と構造体」

今日のねらい

• 配列とは何か、またその使い方を知る

• 構造体とは何か、またその使い方を知る

実施内容

• 配列の定義、宣言、使用例

• 静的・動的配列の違いと参照型について学ぶ

• 構造体の定義、宣言、使用例

4© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

無料版 C++Builder 10.1 Berlin Starter Edition 入手方法

• シリアルキーを知らせるメール内にも再ダウンロードリンク有

• ダウンロード、インストール参考ブログ:https://goo.gl/CCBNdx

エンバ

Web製品

C++

Builder

Starter

バナー登録 Get

無料で使える開発環境をダウンロード

EDN*に登録済の方はEDNアカウントでダウンロード可

登録完了後、自動でインストーラーのダウンロード開始

インストール時にシリアルキーを入力

登録時のメールアドレスにシリアルキーが配信される

5© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

「配列」とは

辞書の定義では「順序をきめてならべること」

例えば「クラスの生徒の体重の数値を、出席番号順に並べる」というのも配

列である

配列の例(体重を0.1kgの精度で計測)

配列の例(体重をkg単位で計測)

出席番号 1 2 3 4 5 6 7 8 9 10

体重(kg) 67.1 73.4 60.6 58.2 62.1 70.9 51.7 64.1 74.2 65.2

出席番号 1 2 3 4 5 6 7 8 9 10

体重(kg) 67 73 61 58 62 71 52 64 74 65

6© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

これを C の文法で書いてみると?

C では以下のように書くことができる

このように、要素数が事前に決まっている配列は「静的配列」という

では事前に要素数が決まっていない配列はどのように宣言すればよいか?

// 0.1kg単位の体重を保持する配列を宣言し、初期値を定義している例。

double weight_double[] = { 67.1, 73.4, 60.6, 58.2, 62.1, 70.9, 51.7, 64.1, 74.2, 65.2 };

weight_double[0]; // この値は 67.1 である。添字は 0 から始める。

添字 0 1 2 3 4 5 6 7 8 9

weight_double 67.1 73.4 60.6 58.2 62.1 70.9 51.7 64.1 74.2 65.2

// 要素数5の配列を確保するだけ。初期値は設定しない例。int no_initialValue[5];

添字 0 1 2 3 4

no_initialValue ?? ?? ?? ?? ??

10個分のDouble型の要素を

確保して初期化されている

5個分のint型の要素は確保済み値は不定なので、値を別途設定せねばな

らない

7© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

要素数を事前に決めていない配列 = 「動的配列」

要素数が変動する配列の作り方

// 要素数が不定の配列を宣言する例1。変数の識別子に * をつけて宣言し、new で配列を作成する。

long *unknownSize;unknownSize = new long[5];

// new で作成した配列は使わなくなった時点で廃棄する

delete[] unknownSize;

// 要素数が不定の配列を宣言する例2。C++Builderには DynamicArray という型がある。

DynamicArray<bool> unknownSize;unknownSize.Length = 5;

// DynamicArray では Length を増やすこともできる

unknownSize.Length = 10;

// DynamicArray で作成した配列は Length = 0 とすると解放される

unknownSize.Length = 0;

8© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

{// 指定された値までの素数を「エラトステネスのふるい」で探す

// 静的配列を確保するconst int CALCRANGE= 1000;bool primeNumber[CALCRANGE];

// 配列の値を true で初期化for (int i = 0; i < CALCRANGE ; i++)

primeNumber[i] = true;

// 1 は除外して探すfor (int i = 2; i < CALCRANGE ; i++) {

if ( primeNumber[i] == true ) {// 見つかった素数を表示するMemo1->Lines->Insert(0, IntToStr(i) );

// 素数の倍数は素数ではないので調査範囲から外すために false にするfor (int j = 2; i * j < CALCRANGE ; j++)

primeNumber[ i * j ] = false;}

}}

静的配列の例

• 静的配列の大きさはコンパイルのとき

に設定されるので、固定の要素数を明

示せねばならない。

• 配列変数の要素数はマクロ定義するか、

または const int の変数を介して取り扱

うようにすると可読性が良くなる。

静的配列は他の変数と同様に、関数(また

はブロック)の終了時に捨てられる。

静的変数を関数の戻り値に使えないことを

意味する。

9© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

動的配列の例{

// 指定された値までの素数を「エラトステネスのふるい」で探す

// 素数を探す範囲をフォームから受け取るint calcRange = StrToInt(Edit1->Text);

// 動的配列を確保するbool *primeNumber;primeNumber = new bool[calcRange];

// 配列の値を true で初期化for (int i = 0 ; i < calcRange ; i++)

primeNumber[i] = true;

// 1 は除外して探す

for (int i = 2; i < calcRange ; i++) {if ( primeNumber[i] == true ) {

// 見つかった素数を表示するMemo1->Lines->Insert(0, IntToStr(i) );

// 素数の倍数は素数ではないので調査範囲から外すために false にする

for (int j = 2; i * j < calcRange ; j++)primeNumber[ i * j ] = false;

}}

// 使い終わったので解放しておくdelete[] primeNumber;

}

bool型の配列 primeNumber を宣言し、大きさを動的に確保する。

不要になった時点で明示的に解放する

10© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

静的配列と動的配列のデータ管理の違い

静的配列は「関数やブロックで管理するメモリ」を使う。

静的配列の要素は「関数やブロック」を抜ける時に廃棄対象となる。このために静的配列

は関数の戻り値には使えない。(今どきのコンパイラはこのような実装はエラーになる)

関数やブロックで管理するメモリ

int a[5];a 0 1 2 3 4

値 値 値 値 値

関数X

{

int n[] = 関数Y();

}

関数Y

int a[5];

return a;

a 0 1 2 3 4

値 値 値 値 値a 0 1 2 3 4

値 値 値 値 値

11© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

静的配列と動的配列のデータ管理の違い

動的配列は new した時点で「アプリケーション内で共通に使えるメモリ」に確保される。

delete すると破棄される。

delete を明示的に実行しない限りは、new で確保した領域はメモリ上に残る。

• new を実行した処理を抜けても確保したメモリが残るので、実行結果を呼び出し側に渡すことができる。

• delete を忘れると、メモリリーク(不要になったメモリの解放が行わず、アプリケーションが使用できるメモ

リが減る状況)の原因となる。

関数やブロックで管理するメモリ

int *a;

a = new int[5];

delete[] a;

アプリケーション内で共通に使えるメモリ

0 1 2 3 4

値 値 値 値 値

a

??

a

xxxxxxxx

0 1 2 3 4

値 値 値 値 値

a

xxxxxxxx

変数 a は new で確保したメモリを参照

delete により変数 a の参照先のメモリを解放

12© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

2次元配列(多次元配列)

型名前[要素数][要素数]; のように宣言すると、2次元の配列になる。

型名前[要素数][要素数][要素数]; のように2次元以上の配列も作成可能だが、必要となる

データ量に留意が必要。たとえば int[1000][1000][1000]の3次元配列では約4GBのメモリ

が必要。

{const int MATRIX_SIZE = 10;int multipleChart[MATRIX_SIZE][MATRIX_SIZE];

// 九九の表を作る

for(int i = 1; i < MATRIX_SIZE; i++) {for(int j = 1; j < MATRIX_SIZE; j++) {

multipleChart[i][j] = i * j;}

}}

1 2 3 4 5 6 7 8 9

1 1 2 3 4 5 6 7 8 9

2 2 4 6 8 10 12 14 16 18

3 3 6 9 12 15 18 21 24 27

4 4 8 12 16 20 24 28 32 36

5 5 10 15 20 25 30 35 40 45

6 6 12 18 24 30 36 42 48 54

7 7 14 21 28 35 42 49 56 63

8 8 16 24 32 40 48 56 64 72

9 9 18 27 36 45 54 63 72 81

13© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

配列のまとめ

同じ種類のデータの集合を扱う場合に使う

必要な要素数が分かっている場合は静的配列が使える

プログラムの実行状況によって要素数が変わる場合は動的配列を

使う

動的配列は不要になったら delete する

多次元配列も作成可能だが、データ量に気をつける

14© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

複数の種類のデータを扱うには?

データ処理では、複数の種類のデータを一括で扱

いたい場合がある

たとえば「郵便番号」

• 「都道府県名、市区町村名、町域名」が紐づく

• ただし同じ郵便番号が複数の町域に割り当てられている場

合がある

これを配列で管理しようとすると…

• zip[n] = 1120001;

• pref[n] = “東京都”;

• city[n] = “文京区”;

• area[n] = “後楽”;

郵便番号 都道府県名 市区町村名 町域名1120001東京都 文京区 白山

1120002東京都 文京区 小石川

1120003東京都 文京区 春日

1120004東京都 文京区 後楽1120005東京都 文京区 水道

1120006東京都 文京区 小日向

1120011東京都 文京区 千石

... … … …

9996837山形県 酒田市 金谷

9996837山形県 酒田市 新町

15© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体は “struct 名前”で宣言、定義する

まとめて扱うデータ型と変数名を { } の中に列挙する。これをメンバまたはメンバ変数という。

先ほどの郵便番号の情報を構造体にすると?

構造体 (struct) を使えば、複数の種類のデータをまとめて扱える

// 構造体 SZipCode の型宣言

struct SZipCode {int Zipcode;String Pref;String City;String Area;

};

struct 名前{型 名前;型 名前;…………

};

SZipCode

Zipcode int

Pref String

City String

Area String

16© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体の使用例// 構造体 zipCode の型を定義struct SZipCode{

int Zipcode;String Pref;String City;String Area;

};

// 変数の作成

SZipCode data;

// 値の代入1

data.Zipcode=1120004;data.Pref=L"東京都";data.City=L"文京区";data.Area=L"後楽";

// 値の代入2data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + data.Zipcode );Memo1->Lines->Insert(0, "都道府県:" + data.Pref );Memo1->Lines->Insert(0, "市区町村名:" + data.City );Memo1->Lines->Insert(0, "町域名:" + data.Area );

構造体の型定義

17© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体の使用例// 構造体 zipCode の型を定義

struct SZipCode{int Zipcode;String Pref;String City;String Area;

};

// 変数の作成SZipCode data;

// 値の代入1

data.Zipcode=1120004;data.Pref=L"東京都";data.City=L"文京区";data.Area=L"後楽";

// 値の代入2data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + data.Zipcode );Memo1->Lines->Insert(0, "都道府県:" + data.Pref );Memo1->Lines->Insert(0, "市区町村名:" + data.City );Memo1->Lines->Insert(0, "町域名:" + data.Area );

ここでは郵便番号1件を扱う

18© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体の使用例// 構造体 zipCode の型を定義

struct SZipCode{int Zipcode;String Pref;String City;String Area;

};

// 変数の作成

SZipCode data;

// 値の代入1data.Zipcode=1120004;data.Pref=L"東京都";data.City=L"文京区";data.Area=L"後楽";

// 値の代入2data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + data.Zipcode );Memo1->Lines->Insert(0, "都道府県:" + data.Pref );Memo1->Lines->Insert(0, "市区町村名:" + data.City );Memo1->Lines->Insert(0, "町域名:" + data.Area );

値はメンバ変数を個別に指定しての代入ができる。また { } の中に値を列挙して代入することもできる。

19© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体の使用例// 構造体 zipCode の型を定義

struct SZipCode{int Zipcode;String Pref;String City;String Area;

};

// 変数の作成

SZipCode data;

// 値の代入1

data.Zipcode=1120004;data.Pref=L"東京都";data.City=L"文京区";data.Area=L"後楽";

// 値の代入2data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + data.Zipcode );Memo1->Lines->Insert(0, "都道府県:" + data.Pref );Memo1->Lines->Insert(0, "市区町村名:" + data.City );Memo1->Lines->Insert(0, "町域名:" + data.Area );

代入でメンバ変数を扱った際と同様に“名前.メンバ変数” で値を参照できる。

20© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体の使用例// 構造体 zipCode の型を定義struct SZipCode{

int Zipcode;String Pref;String City;String Area;

};

// 変数の作成SZipCode data;

// 値の代入1data.Zipcode=1120004;data.Pref=L"東京都";data.City=L"文京区";data.Area=L"後楽";

// 値の代入2data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + data.Zipcode );Memo1->Lines->Insert(0, "都道府県:" + data.Pref );Memo1->Lines->Insert(0, "市区町村名:" + data.City );Memo1->Lines->Insert(0, "町域名:" + data.Area );

21© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

配列で構造体を使う// 構造体 zipCode の型を定義

struct SZipCode{int Zipcode;String Pref;String City;String Area;

};

// 構造体の配列変数を作成

SZipCode *dataArray;dataArray = new SZipCode[100];

// 値の代入dataArray[0] = { 1120004, L"東京都", L"文京区", L"後楽" };

// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + dataArray[0].Zipcode );Memo1->Lines->Insert(0, "都道府県:" + dataArray[0].Pref );Memo1->Lines->Insert(0, "市区町村名:" + dataArray[0].City );Memo1->Lines->Insert(0, "町域名:" + dataArray[0].Area );

// 不要になったら削除delete[] dataArray;

dataArray を * 付きで宣言し、new SZipCode でメモリを確保する

不要になったら消す

22© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

関数とのやりとりに構造体を使うと…

を// 構造体 zipCode の型を定義

struct SZipCode{int Zipcode;String Pref;String City;String Area;

};

// SZipCode を引数にとる関数の例

void doPrint( SZipCode: &value ) {// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + value.Zipcode );Memo1->Lines->Insert(0, "都道府県:" + value.Pref );Memo1->Lines->Insert(0, "市区町村名:" + value.City );Memo1->Lines->Insert(0, "町域名:" + value.Area );

}

// 変数の作成

SZipCode data;

// 値の代入data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 関数呼び出し(構造体)

doPrint( data );

複数の要素をひとまとめでやり取りできるので実装がシンプルになる。

構造体を引数にとる関数は原則「参照渡し」にするので & を付ける。

「値渡し」も可能だが、渡すデータ量が大きい場合は値のコピーが発生する。

23© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体を使わないと……// 構造体 zipCode の型を定義

struct SZipCode{int Zipcode;String Pref;String City;String Area;

};

// パラメータを個別に渡す関数の

void doPrint( int Zipcode, String Pref, City, Area ) {// 値の参照Memo1->Lines->Insert(0, "郵便番号:" + Zipcode );Memo1->Lines->Insert(0, "都道府県:" + Pref );Memo1->Lines->Insert(0, "市区町村名:" + City );Memo1->Lines->Insert(0, "町域名:" + Area );

}

// 変数の作成

SZipCode data;

// 値の代入data = { 1120004, L"東京都", L"文京区", L"後楽" };

// 関数呼び出し(個別パラメータ指定)

doPrint( data.Zipcode, data.Pref, data.City, data.Area );

関数に渡す値を列挙せねばならず、実装の可読性が落ちる

受けわたす値はすべて「値渡し」になるのでデータ量によっては処理性能に影響が出る

24© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体の中に構造体を入れる

構造体の中で指定する型は任意の型を指定できる

事前に宣言定義された構造体を別の構造体で用いることもできる

// 郵便番号に対応する住所情報の定義

struct SZipAddress {String Pref;String City;String Area;

};

struct SZipCode{int Zipcode;

SZipAddress ZipJPN; // 住所情報の日本語標記SZipAddress ZipENG; // 住所情報の英語語標記

};

25© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

構造体のまとめ

複数の種類のデータをまとめて扱える

構造体を配列にすることもできる

構造体は参照渡しで扱う

構造体のメンバの型に制限はなく、別の構造体を使うこともでき

26© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

本日のセミナー内容は弊社ブログに掲載予定

[コミュニティ]↓

[日本人ブログ]

実施内容の再視聴

皆さんが見ているWebページの下に、順次アップロード

エンバカデロWebサイト : http://forms.embarcadero.com/starter-tutorial-webinar

[リソース] – [イベント]の「Delphi / C++Builder Starter チュートリアルシリーズ」ページ

実施内容サマリー

• Community embarcadero (コミュニティエンバカデロ)にWebリンク、サンプルコード情報等

http://community.embarcadero.com/

「エンバカデロ」で検索

27© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

第5回「配列と構造体」まとめ

今日のねらい

• 配列とは何か、またその使い方を知る

• 構造体とは何か、またその使い方を知る

実施内容

• 配列の定義、宣言、使用例

• 静的・動的配列の違いと参照型について学ぶ

• 構造体の定義、宣言、使用例

28© 2017 Embarcadero Technologies, Inc. All rights reserved. Proprietary and confidential. #embtwebi_jp

次回のC++Builderパート

2月27日(月)17:30より

“文字列とオブジェクト„