プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

Slides:



Advertisements
Similar presentations
ゲームプログラミング講習 第2章 関数の使い方
Advertisements

サービス管理責任者等研修テキスト 分野別講義    「アセスメントと        支援提供の基本姿勢」 <児童発達支援管理責任者> 平成27年10月1日.
ヒトの思考プロセスの解明を目的とするワーキングメモリの研究
第27講 オームの法則 電気抵抗の役割について知る オームの法則を使えるようにする 抵抗の温度変化を理解する 教科書P.223~226
コラッツ予想の変形について 東邦大学 理学部 情報科 白柳研究室 山中 陽子.
コンパイラ 第3回 字句解析 ― 決定性有限オートマトンの導出 ―
第5章 家計に関する統計 ー 経済統計 ー.
公共財 公共経済論 II no.3 麻生良文.
VTX alignment D2 浅野秀光 2011年12月15日  放射線研ミーティング.
冷却フランシウム原子を用いた 電子の永久電気双極子能率探索のための ルビジウム磁力計の研究
生命情報学 (8) スケールフリーネットワーク
前半戦 「史上最強」風 札上げクイズ.

認知症を理解し 環境の重要性について考える
フッ化ナトリウムによる洗口 2010・9・13 宮崎市郡東諸県郡薬剤師会 学校薬剤師  日高 華代子.
食品の安全性に関わる社会システム:総括 健康弱者 ハイリスク集団 HACCP (食肉処理場・食品工場) 農場でのQAP 一般的衛生管理
規制改革とは? ○規制改革の目的は、経済の活性化と雇用の創出によって、   活力ある経済社会の実現を図ることにあります。
地域保健対策検討会 に関する私見(保健所のあり方)
公共政策大学院 鈴木一人 第8回 専門化する政治 公共政策大学院 鈴木一人
医薬品ネット販売規制について 2012年5月31日 ケンコーコム株式会社.
平成26年8月27日(水) 大阪府 健康医療部 薬務課 医療機器グループ
平成26年度 呼吸器学会からの提案結果 (オレンジ色の部分が承認された提案) 新規提案 既収載の変更 免疫組織化学染色、免疫細胞化学染色
エナジードリンクの危険性 2015年6月23日 経営学部市場戦略学科MR3195稲沢珠依.
自動吸引は 在宅を変えるか 大分協和病院 院長         山本 真.
毎月レポート ビジネスの情報 (2016年7月号).
医療の歴史と将来 医療と医薬品産業 個人的経験 3. 「これからの医療を考える」 (1)医薬品の研究開発 -タクロリムスの歴史-
社会福祉調査論 第4講 2.社会調査の概要 11月2日.
2015年12月28日-2016年3月28日 掲載分.
2010度 民事訴訟法講義 補論 関西大学法学部教授 栗田 隆.
腫瘍学概論 埼玉医科大学国際医療センター 包括的がんセンター 緩和医療科/緩和ケアチーム 奈良林 至
“企業リスクへの考え方に変化を求められています。 トータルなリスクマネジメント・サービスをプロデュースします。“
情報漏えい 経済情報学科 E  西村 諭 E  釣 洋平.
金融班(ミクロ).
第11回 2009年12月16日 今日の資料=A4・4枚+解答用紙 期末試験:2月3日(水)N2教室
【ABL用語集】(あいうえお順) No 用語 解説 12 公正市場価格 13 債権 14 指名債権 15 事業収益資産 16 集合動産 17
基礎理論(3) 情報の非対称性と逆選択 公共政策論II No.3 麻生良文.
浜中 健児 昭和42年3月27日生まれ 東京都在住 株式会社ピー・アール・エフ 代表取締役 (学歴) 高 校:千葉県立東葛飾高校 卒業
COPYRIGHT(C) 2011 KYUSHU UNIVERSITY. ALL RIGHTS RESERVED
Blosxom による CMS 構築と SEO テクニック
記入例 JAWS DAYS 2015 – JOB BOARD 会社名 採用職種 営業職/技術職/その他( ) 仕事内容 待遇 募集数
ネットビジネスの 企業と特性 MR1127 まさ.
Future Technology活用による業務改革
ネットビジネス論(杉浦) 第8回 ネットビジネスと情報技術.
g741001 長谷川 嵩 g740796 迫村 光秋 g741000 西田 健太郎 g741147 小井出 真聡
自然独占 公共経済論 II no.5 麻生良文.
Autonomic Resource Provisioning for Cloud-Based Software
Webショップにおける webデザイン 12/6 08A1022 甲斐 広大.
物理的な位置情報を活用した仮想クラウドの構築
ハイブリッドクラウドを実現させるポイントと SCSKのOSSへの取組み
寺尾 敦 青山学院大学社会情報学部 第12回 情報デザイン(4) 情報の構造化と表現 寺尾 敦 青山学院大学社会情報学部
【1−1.開発計画 – 設計・開発計画】 システム開発計画にはシステム開発を効率的、効果的に実行する根拠(人員と経験、開発手順、開発・導入するシステム・アプリケーション・サービス等)を記述すること。 システム開発の開始から終了までの全体スケジュールを記載すること。 アプリケーション機能配置、ソフトウェア、インフラ構成、ネットワーク構成について概要を示すこと。
6 日本のコーポレート・ガバナンス 2008年度「企業論」 川端 望.
急成長する中国ソフトウェア産業 中国ソフトウェアと情報サービス産業の規模 総売上高は5年間で約5.3倍の成長
米国ユタ州LDS病院胸部心臓外科フェローの経験
公益社団法人日本青年会議所 関東地区埼玉ブロック協議会 JCの情熱(おもい)育成委員会 2011年度第1回全体委員会
次世代大学教育研究会のこれまでの活動 2005年度次世代大学教育研究大会 明治大学駿河台校舎リバティタワー9階1096教室
子どもの本の情報 大阪府内の協力書店の情報 こちらをクリック 大阪府内の公立図書館・図書室の情報
第2回産業調査 小島浩道.
〈起点〉を示す格助詞「を」と「から」の選択について
広東省民弁本科高校日語専業骨幹教師研修会 ①日本語の格助詞の使い分け ②動詞の自他受身の選択について   -日本語教育と中日カルチャーショックの観点から- 名古屋大学 杉村 泰.
■5Ahバッテリー使用報告 事例紹介/東【その1】 ■iphon4S(晴れの昼間/AM8-PM3) ◆約1時間で68%⇒100%
『ワタシが!!』『地域の仲間で!!』 市民が始める自然エネルギー!!
ポイントカードの未来形を形にした「MUJI Passport」
SAP NetWeaver を支える Microsoft テクノロジーの全貌 (Appendix)
ガイダンス(内業) 測量学実習 第1回.
Python超入門 久保 幹雄 東京海洋大学.
熱力学の基礎 丸山 茂夫 東京大学大学院 工学系研究科 機械工学専攻
京都民医連中央病院 CHDF学習推進委員会
資料2-④ ④下水道.
Accessによる SQLの操作 ~実際にテーブルを操作してみよう!~.
Presentation transcript:

プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) C言語入門 第9週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

関数

関数 関数の定義の書式: 第4週資料pp.33-41,48-49. 関数の宣言 戻り値の型 関数名(引数の宣言, ...); .h ファイルへ書き出す 関数の定義 戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 } .c ファイルへ書き出す 関数の利用 変数名 = 関数名(引数, ...); 適宜呼び出す

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第4週資料pp.42-44. 関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) scopetest.c 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int gl = 100; void sub(int lo) { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d\n", __func__, __LINE__, ++gl, ++lo); } int main() int lo = 200; sub(300); return EXIT_SUCCESS; 関数の引数は呼び出し元とは別の変数になっていた mintty + bash + GNU C $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ g++ call_by_value.c && ./a lo=100 第4週資料pp.42-44. 教科書p.171. 関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す call_by_value.c 8 9 10 11 12 13 14 15 16 17 18 19 20 void sub(int lo) { lo = 200; } int main() int lo = 100; sub(lo); printf("lo=%d\n", lo); return EXIT_SUCCESS; 引数で受け取った変数を変更しても 呼び出し元には反映されない mintty + bash + GNU C $ g++ call_by_value.c && ./a lo=100

関数の引数(値渡し、参照渡し) 参照渡し: 呼出し元の値の格納場所を渡す $ g++ call_by_pointer.c && ./a 第4週資料pp.42-44. 教科書p.171. 関数の引数(値渡し、参照渡し) 参照渡し: 呼出し元の値の格納場所を渡す call_by_pointer.c これは正確には ポインタ渡しと言う 8 9 10 11 12 13 14 15 16 17 18 19 20 void sub(int *lo) { *lo = 200; } int main() int lo = 100; sub(&lo); printf("lo=%d\n", lo); return EXIT_SUCCESS; 引数で受け取った変数を変更すると 呼び出し元にも反映される scanf で見たことがある書き方! &: アドレス演算子 変数loのアドレスを 渡している mintty + bash + GNU C $ g++ call_by_pointer.c && ./a lo=200

関数の引数(値渡し、参照渡し) C++における参照渡し $ g++ call_by_reference.cpp && ./a lo=200 参考 関数の引数(値渡し、参照渡し) C++における参照渡し call_by_reference.cpp C++では 本物の参照渡しが 可能になった 4 5 6 7 8 9 10 11 12 13 14 15 16 void sub(int &lo) { lo = 200; } int main() int lo = 100; sub(lo); printf("lo=%d\n", lo); return EXIT_SUCCESS; 引数で受け取った変数を変更すると 呼び出し元にも反映される 値が変化することが 分かり難いという デメリットもある C++の参照渡しでは アドレス演算子「&」が不要 mintty + bash + GNU C++ $ g++ call_by_reference.cpp && ./a lo=200

ポインタ変数 メモリ上のアドレスを指し示すための変数 ポインタ型のサイズはアドレス空間のビット数 教科書pp.207-272. ポインタ変数 pointer: 指し示す者 メモリ上のアドレスを指し示すための変数 char * 型: char 型の変数へのポインタ int * 型: int 型の変数へのポインタ 要はアドレスを格納するための変数 ポインタ型のサイズはアドレス空間のビット数 32ビットアドレス空間なら4バイト 64ビットアドレス空間なら8バイト sizeof(char *)もsizeof(int *)も同じ

メモリの構成 1byte単位でアドレスが振られている つまり各アドレスには1byteの値を格納出来る 教科書 pp.52-56. 32bitのOSは32bitのアドレス空間 最大 2 32 Bytes=4GiB 64bitのOSは64bitのアドレス空間 最大 2 64 Bytes=16EiB 0x00 0x00000000 0x00000001 0x00000002 0x00000003 0xffffffff : 0x00 0x0000000000000000 0x0000000000000001 0x0000000000000002 0x0000000000000003 0xffffffffffffffff : ポインタ変数には これらの値が入る アドレス 格納値 アドレス 格納値

ポインタ変数 例: 16bit short型little endianの場合 short a = 0x1234; 教科書pp.207-272. ポインタ変数 宣言時に*を付けると ポインタ変数になる 要はリンク みたいなもの 例: 16bit short型little endianの場合 : short a = 0x1234; short *p = &a; &a 0x34 0x~00 a 0x12 0x~01 p に &a を入れておくと *p は a への 参照として機能する C言語ではこれを ポインタと言う 0x?? 0x~02 &aは 変数aの メモリ上の 先頭アドレス a 0x1234 0x?? 0x~03 0x~00 0x?? 0x~04 0x?? 0x~05 *p 0x1234 0x?? 0x~06 *pはアドレスpに 置かれた変数(ここではa) への参照 0x~00 0x?? 0x~07 0x?? 0x~08 p 0x~00 実際に存在している変数はpで中にはアドレスが格納されている : pは変数*pの アドレスを指し示す

ポインタ変数 変数が配置されたアドレスを扱うための変数 $ gcc pointertest1.c && ./a a=2 教科書pp.207-272. ポインタ変数 変数が配置されたアドレスを扱うための変数 pointertest1.c 変数の宣言で 変数名の前にポインタ宣言子「*」を付けると ポインタ変数になる。 この場合、 int 型の変数 *p を宣言した結果、 実際には int 型変数へのポインタである int * 型変数 p が宣言されると 理解しておくとスッキリする。 4 5 6 7 8 9 10 11 12 13 14 15 int main() { int a = 1; int *p; p = &a; *p = 2; printf("a=%d\n", a); return EXIT_SUCCESS; } mintty + bash + GNU C $ gcc pointertest1.c && ./a a=2

ポインタ変数 変数が配置されたアドレスを扱うための変数 $ gcc pointertest1.c && ./a a=2 教科書pp.207-272. ポインタ変数 変数が配置されたアドレスを扱うための変数 pointertest1.c 4 5 6 7 8 9 10 11 12 13 14 15 int main() { int a = 1; int *p; p = &a; *p = 2; printf("a=%d\n", a); return EXIT_SUCCESS; } アドレス演算子「&」を用いて int 型変数 a のアドレス &a を int 型の変数へのポインタ p に代入する a 1 0x~ mintty + bash + GNU C &a $ gcc pointertest1.c && ./a a=2 p 0x~

ポインタ変数 変数が配置されたアドレスを扱うための変数 $ gcc pointertest1.c && ./a a=2 教科書pp.207-272. ポインタ変数 変数が配置されたアドレスを扱うための変数 pointertest1.c int 型の変数へのポインタ p の前に 間接演算子「*」を付けると ポインタ変数 p が指し示すアドレスを int 型の変数としてアクセス出来る。 今 p に変数 a のアドレス &a が 入っているので、 *p に対するあらゆる操作は 変数 a に対する操作と同義となる。 実際 *p を書き変えることで a が 書き変えられていることが確認出来る。 4 5 6 7 8 9 10 11 12 13 14 15 int main() { int a = 1; int *p; p = &a; *p = 2; printf("a=%d\n", a); return EXIT_SUCCESS; } a 2 0x~ mintty + bash + GNU C *p $ gcc pointertest1.c && ./a a=2 p 0x~

ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 同じ「*」だが宣言時とそれ以外で意味が異なる 教科書pp.207-272., [1] pp.250,268-269. ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 同じ「*」だが宣言時とそれ以外で意味が異なる 宣言時 それ以外 *p pをポインタとして宣言 pが指すアドレスの格納値 *p=x pにxを代入 *pにxを代入 *は間接演算子 indirection operator または間接参照演算子 dereference operator ポインタ変数pが指すアドレス (言い換えると、ある型の変数*p)に 値xを代入する ポインタ変数pを宣言 (言い換えると、ある型の変数*pを宣言)し 宣言した変数pに アドレスxを代入する *はポインタ宣言子 pointer declarator 要注意

ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 $ gcc pointertest2.c && ./a sizeof(p1)=8 教科書pp.207-272. ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 pointertest2.cpp mintty + bash + GNU C 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int a = 1; int *p1, b; int *p2 = &a; p1 = &a; printf("sizeof(p1)=%d\n", sizeof(p1)); printf("sizeof(b)=%d\n", sizeof(b)); printf("&a=%#0*p\n", sizeof(&a)*2+2, &a); printf("p1=%#0*p\n", sizeof(p1)*2+2, p1); printf("p2=%#0*p\n", sizeof(p2)*2+2, p2); printf("a=%d\n", a); printf("*p1=%d\n", *p1); printf("*p2=%d\n", *p2); $ gcc pointertest2.c && ./a sizeof(p1)=8 sizeof(b)=4 &a=0x000000000022aabc p1=0x000000000022aabc p2=0x000000000022aabc a=1 *p1=1 *p2=1 要注意

ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 $ gcc pointertest2.c && ./a sizeof(p1)=8 教科書pp.207-272. ポインタ変数の宣言と代入 宣言時は「*」が間接演算子ではなく ポインタ宣言子として働いている 宣言時に初期化すると *p2 ではなく p2 に &a が代入される点が紛らわしい 要注意 「*」と「=」の使い方は要注意 pointertest2.cpp mintty + bash + GNU C 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int a = 1; int *p1, b; int *p2 = &a; p1 = &a; printf("sizeof(p1)=%d\n", sizeof(p1)); printf("sizeof(b)=%d\n", sizeof(b)); printf("&a=%#0*p\n", sizeof(&a)*2+2, &a); printf("p1=%#0*p\n", sizeof(p1)*2+2, p1); printf("p2=%#0*p\n", sizeof(p2)*2+2, p2); printf("a=%d\n", a); printf("*p1=%d\n", *p1); printf("*p2=%d\n", *p2); $ gcc pointertest2.c && ./a sizeof(p1)=8 sizeof(b)=4 &a=0x000000000022aabc p1=0x000000000022aabc p2=0x000000000022aabc a=1 *p1=1 *p2=1 p1 に &a を代入している 宣言時以外は*は関節演算子として働く ポインタの前に*が付くと、指し示す アドレスに格納されている値を操作する 要注意

ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 $ gcc pointertest2.c && ./a sizeof(p1)=8 教科書pp.207-272. ポインタ変数の宣言と代入 「*」と「=」の使い方は要注意 pointertest2.cpp mintty + bash + GNU C 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int a = 1; int *p1, b; int *p2 = &a; p1 = &a; printf("sizeof(p1)=%d\n", sizeof(p1)); printf("sizeof(b)=%d\n", sizeof(b)); printf("&a=%#0*p\n", sizeof(&a)*2+2, &a); printf("p1=%#0*p\n", sizeof(p1)*2+2, p1); printf("p2=%#0*p\n", sizeof(p2)*2+2, p2); printf("a=%d\n", a); printf("*p1=%d\n", *p1); printf("*p2=%d\n", *p2); $ gcc pointertest2.c && ./a sizeof(p1)=8 sizeof(b)=4 &a=0x000000000022aabc p1=0x000000000022aabc p2=0x000000000022aabc a=1 *p1=1 *p2=1 「int *」型の宣言ではなく、 「int」型の宣言である点も紛らわしい。 p1 はポインタ変数だが b は通常のint型変数 複数の変数を宣言する場合 変数名の前に ポインタ宣言子「*」を付けた変数だけが ポインタ変数になる 要注意 要注意

ポインタの表示 %p void *;ポインタとして印字(処理系依存) 第3週資料pp.24-33. 例 mintty + bash + GNU C printf("&a=%#0*p\n", sizeof(&a)*2+2, &a); $ gcc hoge.c && ./a &a=0x000000000022aabc %*pによる最小フィールド幅指定 1バイト=16進数2桁 先頭の0xで更に2桁 #: 16進表示が0でない場合、先頭を0xにする 0: フィールド幅いっぱいに左側から0を詰める *: 最小フィールド幅を引数で指定 p: void *;ポインタとして印字

1次元配列とポインタ 機能としてはほぼ同じ ポインタはアドレスを変更可能(少し柔軟) 教科書pp.207-272. 配列は1要素のバイト数×要素数 ポインタはアドレス空間のビット数/8 機能としてはほぼ同じ ポインタはアドレスを変更可能(少し柔軟) 配列 int p[N]; ポインタ int *p; sizeof(p) ○ 変数pの割り当てバイト数 &p △ 変数pのアドレス(配列はpと同じ) p アドレスp(p[0]のアドレス) *p アドレスpの格納値 p[x] アドレスpを先頭にしてx個目の要素の格納値 *(p+x) アドレスpを先頭にしてx個目の要素(p[x])の格納値 &p[x] アドレスpを先頭にしてx個目の要素(p[x])のアドレス p+x p+=x ×

ポインタ変数とアドレス演算 例: 16bit short型little endianの場合 short a = 0x1234; 教科書pp.207-272. ポインタ変数とアドレス演算 例: 16bit short型little endianの場合 : short a = 0x1234; short *pa = &a; pa 0x34 0x~00 *pa 0x12 0x~01 pa+1 0x?? 0x~02 *(pa+1) ±1するとsizeof(*pa)単位で アドレスが増減する つまり short 型配列の 0要素目、1要素目、... という意味になる 0x?? 0x~03 pa+2 0x?? 0x~04 *(pa+2) 0x?? 0x~05 pa+3 0x?? 0x~06 *(pa+3) 0x?? 0x~07 0x?? 0x~08 : 要注意

ポインタ変数とアドレス演算 例: 32bit int型little endianの場合 int a = 0x12345678; 教科書pp.207-272. ポインタ変数とアドレス演算 例: 32bit int型little endianの場合 : int a = 0x12345678; int *pa = &a; pa 0x78 0x~00 0x56 0x~01 *pa 0x34 0x~02 ±1するとsizeof(*pa)単位で アドレスが増減する つまり int 型配列の 0要素目、1要素目、... という意味になる 0x12 0x~03 pa+1 0x?? 0x~04 0x?? 0x~05 *(pa+1) 0x?? 0x~06 0x?? 0x~07 0x?? 0x~08 : 要注意

ポインタ変数の配列的利用法 例: 16bit short型little endianの場合 short a = 0x1234; 教科書pp.207-272. ポインタ変数の配列的利用法 例: 16bit short型little endianの場合 : short a = 0x1234; short *pa = &a; &pa[0] 0x34 0x~00 pa[0] 0x12 0x~01 &pa[1] 0x?? 0x~02 pa[1] 配列同様[x]で先頭x個目の 要素にアクセス出来る 要素の頭に&を付けると アドレスが得られる 0x?? 0x~03 &pa[2] 0x?? 0x~04 pa[2] 0x?? 0x~05 &pa[3] 0x?? 0x~06 pa[3] 0x?? 0x~07 0x?? 0x~08 :

ポインタ変数の配列的利用法 例: 32bit int型little endianの場合 int a = 0x12345678; 教科書pp.207-272. ポインタ変数の配列的利用法 例: 32bit int型little endianの場合 : int a = 0x12345678; int *pa = &a; &pa[0] 0x78 0x~00 0x56 0x~01 pa[0] 0x34 0x~02 配列同様[x]で先頭x個目の 要素にアクセス出来る 要素の頭に&を付けると アドレスが得られる 0x12 0x~03 &pa[1] 0x?? 0x~04 0x?? 0x~05 pa[1] 0x?? 0x~06 0x?? 0x~07 0x?? 0x~08 :

1次元配列とポインタ 教科書pp.207-272. pointertest3.c cygwin64 + mintty + bash + GNU C 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 int x; int a[] = {0,1,2,3,4,5,6,7,8,9}; int *p = a; fprintf(stderr, "x = ? "); scanf("%d", &x); printf("sizeof(a) = %p\n", sizeof(a)); printf("sizeof(p) = %p\n", sizeof(p)); printf("&a = %p\n", &a); printf("&p = %p\n", &p); printf("a = %p\n", a); printf("p = %p\n", p); printf("*a = %d\n", *a); printf("*p = %d\n", *p); printf("a[x] = %d\n", a[x]); printf("p[x] = %d\n", p[x]); printf("*(a+x) = %d\n", *(a+x)); printf("*(p+x) = %d\n", *(p+x)); printf("&a[x] = %p\n", &a[x]); printf("&p[x] = %p\n", &p[x]); printf("a+x = %p\n", a+x); printf("p+x = %p\n", p+x); //printf("a+=x = %p\n", a+=x); // Address of array variable can not be modified. printf("p+=x = %p\n", p+=x); $ gcc pointertest3.c && ./a x = ? 1 sizeof(a) = 0x28 sizeof(p) = 0x8 &a = 0x22aaa0 &p = 0x22aa98 a = 0x22aaa0 p = 0x22aaa0 *a = 0 *p = 0 a[x] = 1 p[x] = 1 *(a+x) = 1 *(p+x) = 1 &a[x] = 0x22aaa4 &p[x] = 0x22aaa4 a+x = 0x22aaa4 p+x = 0x22aaa4 p+=x = 0x22aaa4 pに1を足しているのに 結果が4増えていることが 確認出来る

1次元配列とポインタ 教科書pp.207-272. pointertest3.c cygwin64 + mintty + bash + GNU C 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int x; int a[] = {0,1,2,3,4,5,6,7,8,9}; int *p = a; fprintf(stderr, "x = ? "); scanf("%d", &x); printf("sizeof(a) = %p\n", sizeof(a)); printf("sizeof(p) = %p\n", sizeof(p)); printf("&a = %p\n", &a); printf("&p = %p\n", &p); printf("a = %p\n", a); printf("p = %p\n", p); $ gcc pointertest3.c && ./a x = ? 1 sizeof(a) = 0x28 sizeof(p) = 0x8 &a = 0x22aaa0 &p = 0x22aa98 a = 0x22aaa0 p = 0x22aaa0 <以下略> 配列変数aはメモリに配置されたアドレス 配列変数aのアドレス&aはつまりaと同じ ポインタ変数pは メモリ上のどこかに確保されており &pはそのアドレス pはそのアドレス&pに格納されたアドレス この例では&a *pはそのアドレスpに格納されたデータ

1次元配列とポインタ 例: 32bitOSで8bit char型little endianの場合 char a[] = {0,1,2,3}; 教科書pp.207-272. 1次元配列とポインタ 例: 32bitOSで8bit char型little endianの場合 : char a[] = {0,1,2,3}; char *p = &a; &a =a =p 0x00 0x~00 0x01 0x~01 a これ全体が配列aであり aはその先頭アドレス 0x02 0x~02 0x03 0x~03 &p 0x00 0x~04 配列変数aはメモリに配置されたアドレス 配列変数aのアドレス&aはつまりaと同じ ポインタ変数pは メモリ上のどこかに確保されており &pはそのアドレス pはそのアドレス&pに格納されたアドレス この例では&a *pはそのアドレスpに格納されたデータ 0x~~ 0x~05 p 0x~~ 0x~06 0x~~ 0x~07 0x?? 0x~08 :

1次元配列とポインタ 例: 32bitOSで8bit char型little endianの場合 char a[] = {0,1,2,3}; 教科書pp.207-272. 1次元配列とポインタ 例: 32bitOSで8bit char型little endianの場合 : char a[] = {0,1,2,3}; char *p = &a; &a =a =p 0x00 0x~00 0x01 0x~01 a sizeof(a) は aの1要素辺りのバイト数×要素数 つまりsizeof(char)*N 0x02 0x~02 0x03 0x~03 &p 0x00 0x~04 sizeof(p) は OSのアドレス空間のビット数/8 つまりsizeof(char *) 0x~~ 0x~05 p 0x~~ 0x~06 0x~~ 0x~07 0x?? 0x~08 :

ポインタ変数 教科書pp.207-272. pointertest4.c Cygwin64+mintty+bash+GNU C 8 9 10 11 12 13 14 15 16 17 18 int i, *p, a[] = {0,1,2,3,4,5,6,7,8,9}; printf("&a[0]=%#0*p\n", sizeof(&a[0])*2+2, &a[0]); printf("p = ? "); scanf("%p", &p); printf("*p="); scanf("%i", p); for (i = 0; i < sizeof(a) / sizeof(*a); i++) { printf("a[%d]=%#0*x\n", i, sizeof(*a)*2+2, a[i]); } $ gcc pointertest4.c && ./a &a[0]=0x000000000022aa90 p = ? 0x000000000022aa98 *p=0x12345678 a[0]=0000000000 a[1]=0x00000001 a[2]=0x12345678 a[3]=0x00000003 a[4]=0x00000004 a[5]=0x00000005 a[6]=0x00000006 a[7]=0x00000007 a[8]=0x00000008 a[9]=0x00000009 結果がどうなるかは別として アドレス演算子を使って 変数のアドレスを入れなくても 適当な値を入れても動く。

ポインタ変数 教科書pp.207-272. pointertest4.c Cygwin64+mintty+bash+GNU C 8 9 10 11 12 13 14 15 16 17 18 int i, *p, a[] = {0,1,2,3,4,5,6,7,8,9}; printf("&a[0]=%#0*p\n", sizeof(&a[0])*2+2, &a[0]); printf("p="); scanf("%p", &p); printf("*p="); scanf("%i", p); for (i = 0; i < sizeof(a) / sizeof(*a); i++) { printf("a[%d]=%#0*x\n", i, sizeof(*a)*2+2, a[i]); } $ gcc pointertest4.c && ./a &a[0]=0x000000000022aa90 p=0x000000000022aa92 *p=0x12345678 a[0]=0x56780000 a[1]=0x00001234 a[2]=0x00000002 a[3]=0x00000003 a[4]=0x00000004 a[5]=0x00000005 a[6]=0x00000006 a[7]=0x00000007 a[8]=0x00000008 a[9]=0x00000009 結果が正しいかどうかは別として 配列の途中のアドレスを ポインタに入れることも出来る

プログラムの実行時に 配列のサイズを適宜に決める事が必要 動的配列 多くの問題では 配列のサイズを事前に (コンパイルの段階では) 決められない。 実行時、プログラムに 与えるデータや パラメータによって 配列のサイズは決まる。 = プログラムの実行時に 配列のサイズを適宜に決める事が必要 malloc, calloc, realloc, free 関数

malloc 関数 void *malloc(site_t size); 引数: 戻り値 動的にメモリを確保する 確保したメモリへのポインタを返す 確保したメモリの内容は初期化されない エラーの場合は NULL を返す JM: malloc (3)

calloc 関数 void *calloc(site_t nobj, site_t size); 引数: 戻り値 動的にメモリを確保する 確保したメモリへのポインタを返す 確保したメモリの内容は0で初期化される エラーの場合は NULL を返す JM: malloc (3)

realloc 関数 void *realloc(void *p, site_t size); 引数: 戻り値 動的に確保したメモリのサイズを変更する 引数: p: サイズを変更するメモリへのポインタ size: 変更後のバイト数 戻り値 確保したメモリへのポインタを返す サイズ変更前後で小さい方のサイズまでは 前の内容が維持される 増加した部分のメモリの内容は初期化されない エラーの場合は NULL を返す 元のブロックは維持される JM: malloc (3)

free 関数 void free(void *p); 引数: 動的に確保したメモリを解放する p: 解放するメモリへのポインタ JM: malloc (3)

関数の作成 演習

演習: is_leap_year~.c の関数化

演習: is_odd.c print_evenodd.c を参考に以下の関数を作りなさい int is_odd(int i); 引数 戻り値 奇数かどうか判定する 引数 i: 判定する整数 戻り値 奇数なら1、奇数でなければ0を返す is_odd_test.c と共にコンパイルして動作を確認すること 2014-06-20追加 Cygwin64+mintty+bash+GNU C $ gcc is_odd_test.c is_odd.c && ./a i = ? 1 odd number

演習: is_even.c print_evenodd.c を参考に以下の関数を作りなさい int is_even(int i); 引数 偶数かどうか判定する 引数 i: 判定する整数 戻り値 偶数なら1、偶数でなければ0を返す is_even_test.c と共にコンパイルして動作を確認すること 2014-06-20追加 Cygwin64+mintty+bash+GNU C $ gcc is_even_test.c is_even.c && ./a i = ? 2 even number

演習: is_prime.c print_isprime.c を参考に以下の関数を作りなさい int is_prime(int i); 引数 素数かどうか判定する 引数 i: 判定する整数 戻り値 素数なら1、素数でなければ0を返す is_prime_test.c と共にコンパイルして動作を確認すること 2014-06-20追加 Cygwin64+mintty+bash+GNU C $ gcc is_prime_test.c is_prime.c && ./a i = ? 7 prime number

演習: swapi.c 以下の関数を作りなさい void swapi(int *a, int *b); 引数 引数で与えた変数の値を交換する 引数 a, b: 値を交換する変数へのポインタ swapi_test.c と共にコンパイルして動作を確認すること 2014-06-20追加 Cygwin64+mintty+bash+GNU C $ gcc swapi_test.c swapi.c && ./a a = ? 1 b = ? 2 a = 2 b = 1 ヒント 第6週資料pp.43-44. 本資料 p.6. を参考にせよ

演習: ヘッダファイルの作成 ここまでに作った is_odd, is_even, is_prime, swapi 関数のプロトタイプ宣言を myfunc.h というファイルにまとめよ。 第4週資料p.38.のis_leap_year_func.hを参考にせよ。 include ガードの識別子は MYFUNC_H とせよ。 誤:3週資料 正:4週資料

エラトステネスのふるい N以下の整数について既知の素数とその倍数をふるい落とすことで素数を判定するアルゴリズム 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 検索リストの先頭の数𝑥 (これは素数)が𝑥≤ 𝑁 なら ステップ3 そうでなければステップ4へ 𝑥を素数リストに移し 𝑥の倍数を探索リストから ふるい落とした後 ステップ2に戻る 探索リストに残った数を 素数リストに移動 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 探索リスト先頭の数は素数 先頭の2を素数と判定し 2の倍数を探索リストから削除する 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 検索リストの先頭の数𝑥 (これは素数)が𝑥≤ 𝑁 なら ステップ3 そうでなければステップ4へ 𝑥を素数リストに移し 𝑥の倍数を探索リストから ふるい落とした後 ステップ2に戻る 探索リストに残った数を 素数リストに移動 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 探索リスト先頭の数は素数 先頭の3を素数と判定し 3の倍数を探索リストから削除する 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 検索リストの先頭の数𝑥 (これは素数)が𝑥≤ 𝑁 なら ステップ3 そうでなければステップ4へ 𝑥を素数リストに移し 𝑥の倍数を探索リストから ふるい落とした後 ステップ2に戻る 探索リストに残った数を 素数リストに移動 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 探索リスト先頭の数は素数 先頭の5を素数と判定し 5の倍数を探索リストから削除する 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 検索リストの先頭の数𝑥 (これは素数)が𝑥≤ 𝑁 なら ステップ3 そうでなければステップ4へ 𝑥を素数リストに移し 𝑥の倍数を探索リストから ふるい落とした後 ステップ2に戻る 探索リストに残った数を 素数リストに移動 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 探索リスト先頭の数は素数 先頭の7を素数と判定し 7の倍数を探索リストから削除する 𝑁以下の素数の探索 2以上𝑁以下の整数を探索リストに入れる 検索リストの先頭の数𝑥 (これは素数)が𝑥≤ 𝑁 なら ステップ3 そうでなければステップ4へ 𝑥を素数リストに移し 𝑥の倍数を探索リストから ふるい落とした後 ステップ2に戻る 探索リストに残った数を 素数リストに移動 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 𝑁以下の素数の探索 2以上𝑁以下の数を探索リストに入れる 先頭の11は≤ 100 でないので 探索リストに残った数を素数と判定 𝑁以下の素数の探索 2以上𝑁以下の数を探索リストに入れる 検索リストの先頭の数𝑥 (これは素数)が𝑥≤ 𝑁 なら ステップ3 そうでなければステップ4へ 𝑥を素数リストに移し 𝑥の倍数を探索リストから ふるい落とした後 ステップ2に戻る 探索リストに残った数を 素数リストに移動 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

エラトステネスのふるい 通常の配列による探索リスト メモリ上のイメージ 添字 探索リストの初期化 2 #define N 100 int i, j = 2, n = N; // n は探索リストの件数 int slist[N-2]; for (i = 0; i < n; i++) { slist[i] = j++; } 3 1 4 2 5 3 6 4 7 5 8 6 訂正2014-06-20 誤:slist[N-1] 正:slist[N-2] 訂正2014-06-20 誤:n = N 正:n = N - 2 : n-1 100 98

エラトステネスのふるい 通常の配列による探索リスト 値の削除 添字 添字 2 2 普通の配列だと 値を削除して 詰める処理に 時間がかかる 3 1 3 1 4 2 5 2 4を削除 5 3 6 3 6 4 7 4 7 5 8 5 8 6 : : n-1 100 97 n-1 100 98 100 98

エラトステネスのふるい 通常の配列による探索リスト 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N-1)*4バイト必要 普通の配列だと 値を削除して 詰める処理に 時間がかかる 探索リストの初期化 探索リストから値xの削除 #define N 100 int i, j = 2, n = N-2; // n は探索リストの件数 int slist[N-2]; for (i = 0; i < n; i++) { slist[i] = j++; } for (i = 0; i < n; i++) { if (slist[i] == x) { for (j = 0; i + j + 1 < n; j++) { slist[i + j] = slist[i + j + 1]; // ↑ 探索リストから x を削除し // ↑ 以降の値を1つずつずらして詰める } n--; // 探索リストの件数をxを削除した分減らす break; 訂正あり p.49.参照

エラトステネスのふるい 通常の配列による探索リスト 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N-1)*4バイト必要 探索リストで値xの判定 for (i = 0; i < n; i++) { if (slist[i] == x) { // x が探索リストにある場合の処理 break; }

エラトステネスのふるい 通常の配列による探索リスト 値の削除を工夫 添字 添字 使ってない値を マイナスにして 検索時に 無視すると 削除は速くなるが 値の検索でごみ になった-1も 処理しなければ いけなくなる 2 2 3 1 3 1 4 2 -1 2 4を削除 5 3 5 3 6 4 6 4 7 5 7 5 8 6 8 6 : : マイナス値も 扱う場合は 使えない方法 n-1 100 98 n-1 100 98

エラトステネスのふるい 通常の配列による探索リスト 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N-1)*4バイト必要 削除は速いが 検索時にゴミも 検索するので 検索が遅くなる 探索リストの初期化 探索リストから値xの削除 #define N 100 int i, j = 2, n = N-2; // n は探索リストの件数 int slist[N-2]; for (i = 0; i < n; i++) { slist[i] = j++; } for (i = 0; i < n; i++) { if (slist[i] == x) { slist[i] = -1; // ↑ 探索リストから x を削除 break; } 訂正2014-06-20 誤:slist[i+j] 正:slist[i] 訂正あり p.49.参照

エラトステネスのふるい 通常の配列による探索リスト 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N-1)*4バイト必要 探索リストで値xの判定 for (i = 0; i < n; i++) { if (slist[i] == x) { // x が探索リストにある場合の処理 break; }

エラトステネスのふるい 1方向リストによる探索リスト 訂正2014-06-20 誤:slist[N][2] 正:slist[N-1][2] メモリ上のイメージ 探索リストの初期化 添字 #define N 100 int i, j = 2; int slist[N-1][2]; for (i = 0; i < N - 2; i++) { slist[i][0] = j++; slist[i][1] = i+1; // 次の値の格納位置 } slist[i][1] = -1; // 終端記号 訂正2014-06-20 誤:i<N-1でしたが 正:i<N-2の誤りでした 2 [0][0] 1 [0][1] 3 [1][0] 2 [1][1] 4 [2][0] 訂正2014-06-20 誤:slist[i][0] 正:slist[i][1] 3 [2][1] 5 [3][0] 2つの値をペアとして扱い 1つ目を次の値の格納場所の添え字 2つ目を格納値 として利用している 1つ目の値を ポインターっぽく 使っている : 99 [98][1] ? [99][0] マイナスの値を次の値がない目印 つまり終端記号として用いている N-1 -1 [99][1]

エラトステネスのふるい 1方向リストによる探索リスト 値の削除 添字 2 [0][0] 2 3 4 1 [0][1] 3 [1][0] 5 100 ? × 2 [1][1] 5 [2][0] 4を削除 4 [2][1] 5 [3][0] 2 3 5 : 99 [98][1] 5 100 ? × ? [99][0] N-1 -1 [99][1]

エラトステネスのふるい 1方向リストによる探索リスト 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N)*4*2バイト必要 使わなくなった メモリは 無駄になるが 削除が高速 探索リストの初期化 探索リストから値xの削除 メモリが通常の配列の 倍必要 #define N 100 int i, j = 2; int slist[N-1][2]; for (i = 0; i < N - 2; i++) { slist[i][0] = j++; slist[i][1] = i+1; // 次の値の格納位置 } slist[i][0] = -1; // 終端記号 for (i = 0; 0 <= slist[i][1]; i=slist[i][1]) { if (slist[i][0] == x) { j = slist[i][1]; slist[i][0] = slist[j][0]; slist[i][1] = slist[j][1]; // ↑ 探索リストの x が格納されている要素を // ↑ 次の要素で上書き break; } 訂正あり p.56.参照

エラトステネスのふるい 1方向リストによる探索リスト 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N)*4*2バイト必要 探索リストで値xの判定 for (i = 0; 0 <= slist[i][1]; i=slist[i][1]) { if (slist[i][0] == x) { // x が探索リストにある場合の処理 break; }

エラトステネスのふるい フラグ配列による探索リスト(int版) メモリ上のイメージ 添字 探索リストの初期化 #define N 100 int slist[N+1] = {0}; 1 2 3 4 5 6 添え字をxとして考え 格納値がゼロなら有効 格納値が非ゼロなら無効 と考える : N 100

エラトステネスのふるい フラグ配列による探索リスト(int版) 値の削除 添字 添字 1 1 2 2 使ってない値を 非ゼロ 削除は速い 検索はごみも 検索するので あまり速くない 4を削除 3 3 4 1 4 5 5 6 6 : : N 100 N 100

エラトステネスのふるい フラグ配列による探索リスト(int版) 探索リストの消費メモリ 2以上N以下の数を配列に保存すると Nが32bitで表現可能な整数と仮定して 初期状態で(N+1)*4バイト必要 こんなに必要? 探索リストの初期化 探索リストから値xの削除 検索しなくて良いので 削除は高速 #define N 100 int slist[N] = {0}; slist[x] = 1; 探索リストで値xの判定 if (!slist[x]) { // x が 0 の時の処理 // x が探索リストにある場合の処理 }

エラトステネスのふるい フラグ配列による探索リスト(char版) 探索リストの消費メモリ 2以上N以下の数を配列に保存すると 初期状態で(N+1)バイト必要 char で十分 必要メモリが 1/4になった もっと減 らせるのでは? 探索リストの初期化 探索リストから値xの削除 検索しなくて良いので 削除は高速 #define N 100 char slist[N] = {0}; slist[x] = 1; 探索リストで値xの判定 if (!slist[x]) { // x が 0 の時の処理 // x が探索リストにある場合の処理 }

エラトステネスのふるい フラグ配列による探索リスト(1bit版) 探索リストの消費メモリ 2以上N以下の数を配列に保存すると 初期状態で(N+8)/8バイト必要 1bitでも十分 charの場合から 更に1/8になった 探索リストの初期化 探索リストから値xの削除 検索しなくて良いので 削除は高速 #define N 100 char slist[(N+8)/8] = {0}; slist[x/8] |= 1<<(x%8); 訂正2014-06-20 誤:slist[x/7] 正:slist[x/8] bit毎のOR演算による bitマスクを用いて 狙ったビットをONにする 探索リストで値xの判定 if (!(slist[x/8] & (1<<(x%8)))) { // x が 0 の時の処理 // x が探索リストにある場合の処理 } bit毎のAND演算による bitマスクを用いて 狙ったビットのON/OFFを調べる

演習: print_prime_lt~.c エラストテネスのふるいによりN未満の素数を小さい順に全て表示せよ print_prime_lt_a1.c 通常の配列版(削除した値を詰めた場合) print_prime_lt_a2.c 通常の配列版(削除値を-1にした場合) print_prime_lt_b.c 一方向リスト版 print_prime_lt_c1.c フラグ配列int版 print_prime_lt_c2.c フラグ配列char版 print_prime_lt_c3.c フラグ配列1bit版

演習: print_prime_lt~.c 前頁で作成したプログラムについて速度を比較してみましょう Cygwin の場合 time コマンドを用いると実行実感が計測出来ます。例えば ./a の実行時間を計測するには以下のようにします。 mintty+bash+GNU C $ time ./a

参考文献 [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準拠、共立出版(1989)