確率的解析と乱択アルゴリズム
確率的解析と乱択アルゴリズム
確率論と計算機における問題解決の手法として
確率的解析と乱択アルゴリズムについて解説していく。
ここでは以下の問題を考える。
雇用問題
問題:
あなたは秘書を雇おうとしている。
その際にあなたは代理店を利用することにした。
その代理店は毎日1人、秘書を送ってくる。
あなたはその候補者と面談し、採用するかどうか選択する。
しかし、面談するのにあなたは費用を払う必要がある。
それに加え実際に候補者を雇うには更に費用がかかる。
そこであなたは現在の秘書よりも候補者が優れている場合すぐにでも雇う。
しかし、いくら費用がかかるか見積もりたい。
かかる費用を求めなさい。
確率的解析 ~Probabilistic Analysis~
上記の問題の様に確率を用いる問題の解析を「確率的解析」という。
確率的解析とは実行時間解析の手法ではない。
上記の問題における雇用コストを解析する手法である。
確率的解析を適用するには、入力分布に関する知識を用いるか
その分布自体を仮定してしまう必要がある。
それが完了すれば実行時間の平均を計算してアルゴリズムを解析する。
平均は入力可能な分布の上でとること、つまり全ての可能な入力に対する平均を算出する。
入力分布は慎重に決める必要がある。
というのも、問題において入力集合に対してある分布をとることで効率のよいアルゴリズムを設計するためである。
しかし妥当な入力分布が存在しない場合ある。
そのようなときには確率的解析を用いることができない。
今回の雇用問題の場合、候補者はランダムに出現し二人の候補者を比較できると仮定できる。
この仮定より、以下を満たす全順序が存在する仮定する。
ここまで示した仮定により、候補者全員を1からnまでの数でただ一通りにランク付け出来る。
それを求める関数をとし候補者のランクを表し、大きいほど能力値が高いとする。
よって候補者がランダムに出現することと、ランクから作られる通りの置換のうち
任意の一つに一致する事象はどれも等確率である。
またはランクリストは一様ランダム置換と言える。
確率的解析における乱択アルゴリズム
確率的解析を用いるには入力分布に関する知識が必須となる。(上記)
しかし、入力分布がわからない場合も多く、たとえ分布がはっきりとわかっていたとしても
必ずアルゴリズムとしてモデルに出来るとは限らない。
そこでアルゴリズムの振る舞いをランダムにして、アルゴリズム設計の道具としてランダム性を使うことが出来る。
ただこのままでは最初に挙げた問題の解決法としては使えないので
問題を以下のように変更する。
代理店が候補者リストを事前に送ってくる。
そのリストから私達が毎日面談するものを決める。
こうすることでランダムな順序で送られてくる候補者に
ランダムな順序を強制する。
指標確率変数
雇用問題やその他乱択アルゴリズムを用いるであろう多数のアルゴリズム解析に指標確率変数を用いる。
これは確率と綿密な関係にある期待値をお互いに変換する便利な道具のようなものである。
標本空間と事象が与えられている時、に関する指標確率変数を
と定義する。
例1
一枚のコインをコイントスして表がでる回数の期待値を求めてみる。
標本空間はとし、コインには裏表しかないので確率となる。
今回は表が出る回数の期待値なので、事象(表が出るとき)に対して指標確率変数を定義できる。
ここでは上記の指標確率変数にしたがって、表が出るなら1、裏がでるなら0とする。
この様にこの問題(コイントスで表が出る回数の期待値を求める)に対して指標確率変数を定義した。
この場合の期待値をとして、指標確率変数を用いて期待値を計算する。
よって1枚のコインをコイントスした時、表がでる回数の期待値はとなる。
今回のコイントス問題の様に単純な問題だと指標確率変数を用いるのは面倒に感じるかも知れないが
これが一回のコイントスではなく一般の回に対してだと圧倒的に便利になる。
その例を次に示す。
雇用問題への応用
候補者は上記の例同様人いるのでが人目の指標確率変数となる。
それでは人目の指標確率変数を以下のように定義する。
また確率変数は次の様に定義できる。
更に人目が最初の候補者から人目までの候補者の中で最も優れている確率はなので
上記の例2よりこの問題の期待値は次の様に表せる。
乱択アルゴリズムの適用
雇用問題やコイントスの問題のような入力全ての置換が等しい確率で成立するという過程が成り立つような問題では
確率的解析が乱択アルゴリズムを用いた開発の指針となる。
具体的にはアルゴリズムが実行される前に候補者の順番をランダムに並び変え
強制的に全ての置換の出現確率を等しくするようにする。
確率的解析と乱択アルゴリズムの違い
上記の記述より、候補者がランダムに出現しようと期待値は変化しない
決定的なアルゴリズム、つまり解が一意に決まるものと比べて
乱択アルゴリズムは入力時ではなく、アルゴリズム内で入力分布のランダム化が発生する。
そのため、特定の入力に対して情報の更新が何回起こるかわからない。
しかし、以前の実行と今回の実行でランダム化が同じである確率はとても低い。
よって、特定の入力があったとき、その入力に対して常に最悪の処理を引き起こすことがない。
乱択アルゴリズムが最悪の処理を実行してしまうのは単に運が悪かったからというだけである。
ここまでの解説で雇用問題に乱択アルゴリズムを適用するのに必要なことは
単に入力配列のランダム化である。
これで乱択アルゴリズムが適用できる。
またこの他にも、以下のような問題にも適用できる。
追加問題
個の箱がある。
箱を開けるまでわからないが半分は当たりになっている。
あたりを見つけよう。
この場合、最悪のケース。先頭から探索するとして
当たりが全て箱の後ろ半分に偏っていた場合かかってしまう。
しかし、その箱の列をランダム化すると
開ける箱の個数に対する期待値は2以下なので、すぐに発見することができる。
gdbを使ってコアダンプの原因を解析
コアダンプは嫌いだ。
大学やその他情報系専門科のある学校に通ったことがある人が一度は触ったことがあるであろう、C言語。
こいつは近年の言語に比べてものすごく面倒くさい書き方をするし、手間もかかる。
中でも最悪なのが「コアダンプ」の文字。
これは、多くのC言語ユーザを苦しめてきただろう。
一応エラーの部類に入ると思うが、こいつはどこで問題が起きているか普通は出力してくれないから直すのがすごく大変。
それでは解析の準備
これはこの前自分が実際にコアダンプを発生させてしまったコード。
このファイルをここでは「quicksort.c」とする。
#include<stdio.h> void quicksort(int array[],int left_index,int right_index){ int left = left_index,right = right_index,tmp; //基点を左右の中間から選択 int pivot = array[(left+right)/2]; while(1){ //左側で基点より大きい値を探す while(array[left] < pivot) left++; //右側で基点より小さい点を探す while(pivot < array[right]) right++;//ここが間違っている if(right < left) break; //値の入れ替え //基点より小さい数値を左、大きい数値を右へ移動させる tmp = array[left]; array[left] = array[right]; array[right] = tmp; left++; right--; } //再帰関数による分割統治法を行う if(left_index < right) quicksort(array,left_index,right); if(left < right_index) quicksort(array,left,right_index); } int main(){ int i; int array[] = {2,4,5,3,1,6,3,1,9}; quicksort(array,0,9-1); for(i = 0; i < 9; i++) printf("%d\n",array[i]); return 0; }
こいつを実行させると、もちろんこのメッセージがターミナルに出力される。
Segmentation fault (コアダンプ)
それでは解析を始める
まずコアダンプを解析するためにコンパイラオプションの「-g」をつける。
gcc quicksort.c -g -o quicksort
- gオプションをつけることで、デバッグ情報を出力するようにする。
つぎに、大抵コアダンプ機能が無効にされているの以下のコマンドで有効にする
ulimit -c unlimited
それが終わったら、問題のある(コアダンプのある)実行ファイルを実行する
./quicksort Segmentation fault (コアダンプ)
となる。
この時lsでカレントディレクトリを確認すると「core」や「core.xxxxx(xは数字)」といったファイルが生成される。
ここまでできたら、以下のコマンドでデバッグする
gdb ./quicksort core
そうすると、こんな出力が見えるはず(プログラムによって違う)
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./quicksort...done. warning: core file may not match specified executable file. [New LWP 13685] Core was generated by `./base1'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x0000000000400616 in quicksort (array=0x7ffe0656abc0, left_index=0, right_index=8) at quicksort.c:26 26 while(pivot < array[right]) (gdb)
これで大体わかってしまうんだけど、今回はちゃんと手順を踏む。
まずはBackTraceする。
(gdb) bt #0 0x0000000000400616 in quicksort (array=0x7ffe0656abc0, left_index=0, right_index=8) at quicksort.c:26 #1 0x0000000000400747 in main () at quicksort.c:56
これで問題のありそうな関数の番号を選択すると
#今回は#0のquicksort関数に問題がありそうだから0を選択 (gdb) frame 0 #0 0x0000000000400616 in quicksort (array=0x7ffe0656abc0, left_index=0, right_index=8) at quicksort.c:26 26 while(pivot < array[right])
というわけでこの26行目になにやら問題があることがわかった。
今回は
right++;
で配列の範囲外を参照してしまうことが問題になっていた。
というわけで、解析完了!
これがポインタなどの場合は以下の様に確かめることができる
(gdb)p [ここに確かめたい変数名、引数名など]
そうするとそれの値やメモリアドレスを指してくれる。
よくあるのは「0x0」というメモリアドレス。これはメモリが確保されていないことを指すので該当部分のポインタやアドレスまわりの処理を見なおそう。
セキュリティミニキャンプ北海道2016に参加してきた
初めてミニキャンに参加してきた
LOCAL学生部に加入して、しばらくしてからミニキャンのお知らせが回ってきたから何をやるんだという感じで詳細を見てみると…。Linuxでハードウェア制御、スマホアプリでサーバサイドへの攻撃と対策、クラウドセキュリティ基礎…。これほど興味を引く内容なのに申し込まないわけにはいかない!
というわけで、申し込んで無事行くことになって、この前の週末に参加してきた。
ミニキャンに参加してみて
セキュリティあんまり興味なかったけど、セキュリティキャンプはセキュリティ以外にも色々実習を行ったり、チームに分かれてディスカッションしたりと面白かった。
印象に残った講義の感想
初日に行われた、「スマホアプリでサーバサイドアプリケーションへの攻撃と対策を学ぶ」はミニキャンプが開催された二日間の中で特に面白かった。
BurpSuiteという脆弱性診断によく使用されるソフトウェアを使用して、実際にHTTP通信を覗いたり編集したりして脆弱性を探して行ったわけだけど、チーム別に行ったのでチームのみんなで「ああだこうだ」言いながら色々試していった。別のチームの事情はよくわからないけど、自分たちのチームはセキュリティとかネットワークに強いひとがいなくてすごく苦戦した。だけど、そういう分野に強い人が居なかったが故にみんなで意見出し合いながら実習を行えたのはすごくいい経験になったし、今までセキュリティの仕事ってどんなことするのか曖昧だったものが経験を通して「これがセキュリティの仕事だ」といったものを実感できたのも良かった。
それ以外で面白かったのは「クラウドセキュリティ基礎」。
これはいろんなパワーワードが飛び交ってすごく笑えた。特に「今日のサーバはペットではなく家畜」と「耐用年数間近のサーバなんて電気代バカ食いするだけのゴミ」が最高にキテる。それにこの講義の内容はwebサービスやサーバ関連の内容からクラウドに移っていったので、最近VPSを借りてwebサービスを構築しようとしていた自分にとってはすごくためになることばかりだった。それに今までサーバとかクラウドといった環境が用意できないからという理由でweb系の事を全くやってこなかったので、本当に基礎的な部分から始まった講義は全てが新鮮だった。
その次は、なんといっても「Linuxを用いたハードウェア制御」の講義がためになった。
実はミニキャン前はこれをすごく楽しみにしていた。実際はすごくハードウェア的なことを中心にやっていくものだったけど未経験だった電子工作的な部分とシステムコール的な処理を同時に学べたのは最高に面白かった。出来ることならハードウェア制御という名前らしく、自分でハードウェアを制御するプログラムを作ってみたかった。
全体を通して
ミニキャンが開催された、二日間は最高の時間だったと振り返ってみて思う。それもそうで、普段大学では、一年生ということもあるのかこういった内容はみんな勉強しないで、たとえやったとしても「授業でやるから」「テストがあるから」といったような理由で自分がわくわくするようなことがまず無い。それに一応存在するプログラミングサークル的なものではUnityとか他のライブラリ使ってゲームを作るだけなどと、もっといろんな事を勉強して吸収していきたい自分にとってはすごく生温い環境の中にいたからである。ただ、ミニキャンは違った。ミニキャンは、みんなが何かしら自分が得られるものを全部自分のものにしてしまえ。といったような気迫ややる気と言ったものが感じられ、チームディスカッション一つとっても今までの自分にはなかった発想がたくさん展開され、演習も「そうするのか!?」といった驚きばかりだった。生温い環境に居た自分にはこういった時間がすごく刺激的だった。その中で、自分のスキルの無さを多少なりとも実感し、このままでは数年後に社会に出て、今回出会った人たちと競っていくことになったら自分は確実に劣るといった根拠の無い確証も得た。
今回、ミニキャンに参加しそういった実感があったからこそ、それをそのままにせず、自分はもっともっと成長しなければいけない、成長し続けなければいけないと思う。ミニキャンは消えそうだった自分のエンジニア魂を燃えさせるいいきっかけとなった。参加して本当に良かった。
出来ることなら来年のセキュリティキャンプの全国大会に参加したい。きっとそこにはもっと成長できる刺激的な環境が待っているだろうから。
さくっとアセンブリ入門 hello,world編
とりあえず「Hello,World」
まずはお決まりの「Hello,World」から
.globl main main: movl $4,%eax movl $1,%ebx movl $msg,%ecx movl $13,%edx int $0x80 movl $1,%eax movl $0,%ebx int $0x80 .data msg: .asciz "Hello,World\n"
今まで色々なプログラミング言語に触れてきたけど、これほど初見で難解なhello,worldを見たことがない
わからないながら解説
まず一行目の「.globl」のように.から始まる命令をディレクティブといいアセンブラに対する命令を表している
その中でも「.globl」はエントリーポイントを指定するものである。またGASを使用するのでmainを指定しておく
二行目の「:」これがつくとC言語と同様にラベルになる
またラベルはプログラム実行中のメモリアドレスの代わりとして定数のように使用可能(最終行で使用)
三行目から六行目までは代入処理で「mov命令」と呼ばれるもの
この命令は以下の形式を取る
mov [代入元],[代入先]
詳しくは後述
$から始まるものは数値で%から始まるものはレジスタ
そしてこのmov命令を今回のコードの中では「mov」ではなく「movl」となっている
これは「long word」のlである。
アセンブリはただ数値としてすべてを扱うので何ビットずつ数値を扱っているかということを示す必要がある
これをオペレーションサフィックスといい以下のようなものが使える
サフィックス | サイズ |
---|---|
b | バイト、8ビット |
s | ショートで16ビット整数かシングルの32ビット浮動小数点 |
w | ワード、16ビット |
l | ロングで32ビット整数か64ビット浮動小数点 |
q | クワッド、64ビット |
t | 10バイト、80ビット浮動小数点 |
これらから、Byte値を代入するなら「movb」となりWord値を代入するなら「movw」となる
今回はLongWordなので「movl」となる
七行目の謎の処理は「割り込み命令」といい、CPUが処理をしている時に現行作業を復帰可能な状態にして割り込みする処理を実行するといったもの
またここでは16進数で0x80を指定しているが、これは割り込み番号0x80番でシステムコールを実行してくださいということ
11行目でのdataディレクティブでは実行用のコードがおいてあるのではなく、初期化済みのデータを置くと宣言している
最後はascizディレクティブは文字列を置くと宣言するもので最後にnull文字を付与する
メディアンフィルタ
メディアンフィルタ
移動平均法ではn*nの局所領域における濃度の平均値を領域中央の画素が保有する濃度として扱ったが
別の画質改善法にメディアンフィルタというものがある
これは局所領域中の濃度値の中央値を領域中央の画素が保有する濃度として扱う方法である
例えば以下のような画素の一次元配列が存在すると仮定する
1,4,5,6,7,3,2,9,5
これを移動平均方では平均値を領域中央として扱ったが
メディアンフィルタでは
1,2,3,4,5,5,6,7,9
と並べ替えて中央値を領域中央の値とする
詳しい仕組み
メディアンフィルタでは、局所領域における画素の中央値を扱うため
その領域内の画素に対して非線形な演算を必要とするが、領域内の要素数を奇数にする
つまりnを奇数としてn*nの領域に対して処理を行うことで中央値を一意に求めることが可能になる
メディアンフィルタの使いところ
メディアンフィルタは雑音、つまりノイズが画像の内容と無関係でランダムな白色雑音の時に有効な手段としてつかえる
これはメディアンフィルタによる処理を行うことでスパイク状の雑音が取り除かれることとエッジがボケることが少ないためである
平均値を取る移動平均法のような手段では処理を重ねていくたびに周辺画素への影響が大きくなるが
メディアンフィルタのように中央値を選ぶことで極端な値の影響を非線形な演算が吸収しているためである
OpenCVとPythonで実装してみる
いつもどおりPythonとOpenCVでメディアンフィルタをかけてみる
#coding:utf-8 import numpy as np import cv2 #画像を読み込み img = cv2.imread("lenna256.png") #グレースケール化 gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY) #これは奇数にしておく必要がある k = 3 res_img = cv2.medianBlur(gray,k) cv2.imshow("median filter",res_img) cv2.waitKey(0) cv2.destroyAllWindows()
ここで使った画像はいつものlenna256.png
これをグレースケール化してlenna256_median.pngを生成する
lenna256.png
そしてこれがメディアンフィルタを適用させた画像
lenna256_median.png
他の画質改善手法に比べてスパイク雑音を取り除き、エッジに与える作用が小さいので
移動平均法などに比べて、連続した部分は滑らかになり
輪郭線もある程度はっきりしている
サイトをリニューアルしたから今回使ったものをまとめてみた
はじめに
今回自分のサイトをリニューアルしたので
kentsu-141.github.io
これに使ったものをざっくりまとめてみる
基本的なデザイン
まず基本的なデザインはこのホームページを見て思いついた
sard.website
ただ画像なんかを用意するのがめんどくさかったのと
なるべく最初の状態でスクロールする状況を作りたくなかったので
折りたたみ(後述)といつもどおりのカラーだけでゴリ押しのスタイルで作ると
今回のようなサイトになった
折りたためるあれ
今回使ったもので、表示部分を折りたためるあれは「アコーディオン」というもので
htmlタグのdl,dt,ddタグとjqueryを使って作った
参考にしたサイトはこれ
liginc.co.jp
これで表示部分を折りたためるようになった
しかしデフォルトでは折りたたまれず展開された状態になってしまうので
dd{ display:none; }
をスタイルシートに追加しておいた
これでページ読み込み時で折りたたまれた状態になる
フォント
今回は今まで使ってこなかった方法でフォントを持ってきてみた
@import url(http://fonts.googleapis.com/css?family=Economica:400,700);
普段はダウンロードしたrobotoとかtahoma,impactあたりを使うんだけどこれもこれで良かった
こうして持ってきたフォントは以下のように使う(今回は全ページで統一なのでbodyタグに)
body{ font-family:'Economica',sans-serif; }
アニメーション
これが一番気になるだろうけど、特に独自実装したわけでなく
外部からwow.jsとanimate.cssを持ってきただけという
animate.cssは以下のサイトからいろいろ選べる
https://daneden.github.io/animate.css/
wow.jsはanimate.cssと併用するため必要
以下のレポジトリからダウンロードした
github.com
ただ注意すべきは、wow.jsをググればわかるが
ページがスクロールされ表示範囲に入った時にアニメーションに入ることや
サイズの大きい要素や、いくつも要素を同時に動かすと特にスマホなどで見た時にラグがでてかくかくになるので注意
最後に
割といつもフラットデザインになるようにしているが今回もなかなか微妙な出来になってしまった
C言語 構造体
6章 構造体
構造体とは、操作しやすいように一つの名前でまとめられた
1つ以上の異なった型の集まりである
この構造体と呼ばれるものは大きなプログラムで特に複雑なデータを組織化するのに役立つ
それは関連したデータを実体としてでなく一つの単位として扱えるという性質から来ている
6.1 構造体の基本事項
まずは構造体を使って二次元平面上の点を構造体を使って表してみる
int x,y;
普通はこう表すかもしれないけど、構造体でひとつの単位としてまとめるとこうなる
struct point{ int x; int y; };
これでpointという平面上での座標を表す一つの単位が出来た
前者に比べて後者のほうが何を示しているかわかりやすくなる
ここで少し説明するとstructという予約語の後に続いている名前は構造体タグと言われるものである
この構造体タグなるものは宣言以後、カッコ内の宣言部分の略称としてしようすることができる
構造体の中で命名された変数はメンバーと言われる
そして構造体タグとメンバー名は同名であってもぶつかることはない
構造体を使いたいときは以下のような記述をする
struct point pt;
これによりptはstruct point型であると宣言される
また以下のように各メンバーに対する定数式による初期化式の並びを定義の後につけることで構造体を初期化することができる
struct point max_pt = {100,100};
さらに宣言だけしておいて以下のように別々に初期化することも出来る
struct point min_pt; min_pt.x = -100; min_pt.y = -100;
上の例でわかるように
構造体型の変数名.メンバー名 >|| でその構造体のメンバにアクセスできるため、値を代入するときだけじゃなくて 値を呼び出したいときにも使用することが出来る 構造体は入れ子にすることも出来て 以下のようなメンバーを持つ構造体を宣言することも出来る >|c| struct rect{ struct point pt1; struct point pt2; };
この構造体は2つのpoint構造体をメンバとして含んでいる
ここでscreenを以下のように宣言しすると
struct rect screen
これでxが呼び出せる
screen.pt1.x
ここで紹介した以外にも構造体は以下のようにも宣言できる
struct{}x,y;
実は構造体タグは省略可能
6.2 構造体と関数
構造体に対して許される唯一の演算はコピーすること
&でそのアドレスを求めること
コピーと代入には関数に渡して関数から値を返すことも含まれている
しかし構造体の比較はできない
ここでは関数の値として構造体を返すことを例にあげてみる
struct point makePoint(int x,int y){ struct point tmp; tmp.x = x; tmp.y = y; return tmp; }
この関数はstruct point型の構造体を返すもので、前に書いたようにメンバー名と引数名が衝突していないことにも注目したい
ここで作成したmakePoint関数は任意の構造体を動的に初期化することができる
次に示すのは関数の引数と戻り値が構造体の場合のとき
struct point addPoint(struct point pt1,struct point pt2){ pt1.x += pt2.x; pt1.y += pt2.y; return pt1; }
ここは明示的な一時変数を使わないでpt1のメンバに加算しているが
これは構造体のパラメータが他のものと同じように値によって渡されることを強調するためである
これまでは構造体をそのまま渡してきたが関数に対して大きな構造体を渡す場合は構造体全体をコピーするより
ポインタを渡すほうが一般に能率的である
構造体ポインタは普通の変数へのポインタと変わらず以下のように宣言できる
struct point *pp;
これは変数ppがstruct point型へのポインタであることを示す
この時構造体ポインタのメンバにアクセスする場合は以下のようにする
(*pp).x; (*pp).y;
この時注意すべきことは*は.より優先順位が低いため()が必要になる
これを用いて以下のようなコードが書ける
struct point base; struct point *pointer; pointer = &base; printf("%d,%d",(*pointer).x,(*pointer).y);
また構造体のポインタへの参照はこれ以外にも別の方法がある
上の例に続いて、pointerが構造体へのポインタだとすると
pointer -> メンバー
のようにすることでメンバーを参照出来る
そこで2つ上の例は以下のように出力処理を書き直せる
printf("%d %d",pointer->x,pointer->y);
6.3 構造体配列
構造体自体は配列にすることができる
ここまでのまとめに準ずるなら
#define NUM 10 struct point pt[NUM];
もしくは
#define NUM 10 struct point{ int x; int y; }pt[NUM];
更にいうのであれば
struct point{ int x; int y; }pt[] = { 1,1, 2,1,... };
のようにも定義出来る
この時構造体は配列になっているので、構造体のメンバーにアクセスしたい場合は
//iを0以上の任意の整数として
point[i].x
point[i].y
見たいな風にすれば、その構造体のインデックスに対応したメンバーを参照することが出来る
6.4 typedef
ここで少し話は逸れるがtypedefという新しいデータ型を宣言するための機能を紹介する
ただこの説明ではわからないと思うので実際に例を上げる
typedef int Length;
これでLengthをint型と同意義のものとして定義する
なので以下のような構文が書ける
Length len = 10; Length maxLen = 20;
ということは文字列関連でいつもめんどくさいなと思っていたことを解消できる
それは文字列である。文字列はC言語においてポインタや配列で実現するのが通例になっているが
JavaやC++,C#といった言語を先に経験した人にとってはこれは煩わしいものであったと思う
それをtypedefを使って以下のようにすれば
typedef char *String;
他の言語と同じように文字列を宣言できる
String str = "hello,world!!";
ちなみに同意義のものとして新しい型を既存の型と結びつけるので
typedefで宣言した新しい型でキャストすることもできる
例えば
String str;
str = (String)malloc(100);
のように
6.5 共用体
共用体(union)と言われるものは構造体とすごく似ているが、異なる型を同一のメモリで扱うことが出来る
というのも共用体のすべてのメンバにおいてオフセットが0である構造体のようなものだからである
共用体のメンバは構造体と同じように参照できる
ただ共用体自体の宣言が少し違う
union SampleUnion{
};
これでひと通りの構造体、それに類似するもののまとめは終わり