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

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言語入門 第14週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)

関数の引数(値渡し、参照渡し) 復習

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 100 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 100 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 呼び出し元アドレス scopetest.c 22 行目 0x000000000023cb18 lo 300 0x000000000023cb20 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 100 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 lo 400 0x000000000023cb14 呼び出し元アドレス scopetest.c 22 行目 0x000000000023cb18 lo 300 0x000000000023cb20 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 101 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 lo 401 0x000000000023cb14 呼び出し元アドレス scopetest.c 22 行目 0x000000000023cb18 lo 300 0x000000000023cb20 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 101 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 lo 401 0x000000000023cb14 呼び出し元アドレス scopetest.c 22 行目 0x000000000023cb18 lo 300 0x000000000023cb20 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 102 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 呼び出し元アドレス scopetest.c 22 行目 0x000000000023cb18 lo 301 0x000000000023cb20 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 102 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 呼び出し元アドレス scopetest.c 22 行目 0x000000000023cb18 lo 301 0x000000000023cb20 lo 200 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 変数のスコープ(有効範囲) $ gcc scopetest.c && ./a 第8週資料pp.21-23. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 変数のスコープ(有効範囲) scopetest.c mintty + bash + GNU 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; gl 103 0x00000001004071c0 $ gcc scopetest.c && ./a sub : 14: gl=101, lo=401 sub : 16: gl=102, lo=301 main : 23: gl=103, lo=201 lo 201 0x000000000023cb24 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ gcc call_by_value.c && ./a lo=100 第8週資料pp.21-23. 教科書p.171. 関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す call_by_value.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; 引数で受け取った変数を変更しても 呼び出し元には反映されない mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ gcc call_by_value.c && ./a lo=100 第8週資料pp.21-23. 教科書p.171. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 値渡し: 呼出し元の値のコピーを渡す call_by_value.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; 引数で受け取った変数を変更しても 呼び出し元には反映されない lo 100 0x000000000023cb24 mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ gcc call_by_value.c && ./a lo=100 第8週資料pp.21-23. 教科書p.171. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 値渡し: 呼出し元の値のコピーを渡す 訂正2015-07-25 誤: 11行目 正: 12行目 call_by_value.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; 引数で受け取った変数を変更しても 呼び出し元には反映されない 呼び出し元アドレス call_by_value.c 12 行目 0x000000000023cb18 lo 100 0x000000000023cb20 mintty + bash + GNU C lo 100 0x000000000023cb24 $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ gcc call_by_value.c && ./a lo=100 第8週資料pp.21-23. 教科書p.171. 関数の引数(値渡し、参照渡し) 注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。 値渡し: 呼出し元の値のコピーを渡す 訂正2015-07-25 誤: 11行目 正: 12行目 call_by_value.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; 引数で受け取った変数を変更しても 呼び出し元には反映されない 呼び出し元アドレス cal_by_value.c 12 行目 0x000000000023cb18 lo 200 0x000000000023cb20 mintty + bash + GNU C lo 100 0x000000000023cb24 $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ gcc call_by_value.c && ./a lo=100 第8週資料pp.21-23. 教科書p.171. 関数の引数(値渡し、参照渡し) 注: 実際にはrbpレジスタの退避等もあるため もう少し余分な物もスタックに積まれます 値渡し: 呼出し元の値のコピーを渡す 訂正2015-07-25 誤: 11行目 正: 12行目 call_by_value.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; 引数で受け取った変数を変更しても 呼び出し元には反映されない 呼び出し元アドレス call_by_value.c 12 行目 0x000000000023cb18 lo 200 0x000000000023cb20 mintty + bash + GNU C lo 100 0x000000000023cb24 $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す $ gcc call_by_value.c && ./a lo=100 第8週資料pp.21-23. 教科書p.171. 関数の引数(値渡し、参照渡し) 値渡し: 呼出し元の値のコピーを渡す call_by_value.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; 引数で受け取った変数を変更しても 呼び出し元には反映されない mintty + bash + GNU C lo 100 0x000000000023cb24 $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 参照渡し: 呼出し元の値の格納場所を渡す $ gcc call_by_pointer.c && ./a これは正確には ポインタ渡しと言う 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; 引数で受け取った変数を変更すると 呼び出し元にも反映される scanf で見たことがある書き方! &: アドレス演算子 変数loのアドレスを 渡している mintty + bash + GNU C $ gcc call_by_pointer.c && ./a lo=200

関数の引数(値渡し、参照渡し) 参照渡し: 呼出し元の値の格納場所を渡す $ gcc call_by_pointer.c && ./a 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; 呼び出し元アドレス call_by_pointer.c 12 行目 0x000000000023cb14 lo 0x000000000023cb24 0x000000000023cb1c mintty + bash + GNU C lo 100 0x000000000023cb24 $ gcc call_by_pointer.c && ./a lo=200 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 参照渡し: 呼出し元の値の格納場所を渡す $ gcc call_by_pointer.c && ./a 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; ポインターを介して呼び出し元の lo を書き換え 呼び出し元アドレス cal_by_pointer.c 12 行目 0x000000000023cb18 lo 0x000000000023cb24 0x000000000023cb18 mintty + bash + GNU C lo 200 0x000000000023cb24 $ gcc call_by_pointer.c && ./a lo=200 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

関数の引数(値渡し、参照渡し) 参照渡し: 呼出し元の値の格納場所を渡す $ gcc call_by_pointer.c && ./a 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; 呼び出し元アドレス call_by_pointer.c 12 行目 0x000000000023cb14 lo 0x000000000023cb24 0x000000000023cb1c mintty + bash + GNU C lo 200 0x000000000023cb24 $ gcc call_by_pointer.c && ./a lo=200 呼び出し元アドレス 0x0000000180048551 0x000000000023cb28

標準ライブラリ関数を例にした実例 文字列操作とポインタ操作

ポインタを用いた文字列操作の例 strlen 関数の大まかな仕組み strlen_with_idx.c strlen_with_ptr1.c 文字列の長さは 先頭から終端文字('\0')の手前までの 文字数 size_t strlen(const char *s) { size_t len = 0; while (s[len] != '\0') len++; return len; } strlen_with_ptr1.c strlen_with_ptr2.c size_t strlen(const char *s) { const char *s0 = s; while (*s != '\0') s++; return s - s0; } size_t strlen(const char *s) { const char *s0 = s; while (*(s++) != '\0') ; return s - s0 - 1; }

ポインタを用いた文字列のコピーの例 strcpy 関数の大まかな仕組み strcpy_with_idx.c 文字列のコピーは 先頭から終端文字('\0')までを コピーすれば良い char *strcpy(char *dst, const char *src) { int i; for (i = 0; (dst[i] = src[i]) != '\0'; i++) ; return dst; } strcpy_with_ptr.c char *strcpy(char *dst, const char *src) { char *dst0 = dst; while ((*(dst++) = *(src++)) != '\0') ; return dst0; }

ポインタを用いた文字列のコピーの例 strncpy 関数の大まかな仕組み strncpy_with_idx.c strncpy は strcpy に加えて 終端文字('\0')以降を'\0'で埋める char *strncpy(char *dst, const char *src, size_t n) { size_t i = 0; for (; i < n && (dst[i] = src[i]) != '\0'; i++) ; for (; i < n; i++) dst[i] = '\0'; return dst; } 論理演算は左から右に評価され、 真偽値が確定すると評価を終了する。 つまり i < n や dst < dst0 + n が偽なら、 そこで真偽値が確定するので それより右にある (dst[i] = src[i]) != '\0' や (*(dst++) = *(src++)) != '\0' は 実行されない。 strncpy_with_ptr.c char *strncpy(char *dst, const char *src, size_t n) { char *dst0 = dst; while(0 < n-- && (*(dst++) = *(src++)) != '\0') ; while(0 < n--) *(dst++) = '\0'; return dst0; }

ポインタを用いた文字列の比較の例 strcmp 関数の大まかな仕組み strcmp_with_idx.c strcmp_with_ptr.c どちらかが終端文字('\0')になるか 異なる値が出てくるまで比較し 終了位置を比較すれば良い int strcmp(const char *s1, const char *s2) { size_t i; for (i = 0; s1[i] != '\0' && s2[i] != '\0' && s1[i] == s2[i]; i++) ; return s1[i] - s2[i]; } strcmp_with_ptr.c int strcmp(const char *s1, const char *s2) { while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) { s1++; s2++; } return *s1 - *s2;

ポインタを用いた文字列の比較の例 strncmp 関数の大まかな仕組み strncmp_with_idx.c strncmp は strcmp の 比較文字数を最大n文字に限定する int strncmp(const char *s1, const char *s2, size_t n) { size_t i; if (n <= 0) return 0; for (i = 0; i < n - 1 && s1[i] != '\0' && s2[i] != '\0' && s1[i] == s2[i]; i++) ; return s1[i] - s2[i]; } strncmp_with_ptr.c int strncmp(const char *s1, const char *s2, size_t n) { if (n <= 0) return 0; while (0 < --n && *s1 != '\0' && *s2 != '\0' && *s1 == *s2) { s1++; s2++; } return *s1 - *s2;

ポインタを用いた文字列の連結の例 strcat 関数の大まかな仕組み strcat_with_idx.c strcat_with_ptr.c dst の終端位置に src をコピーする char *strcat(char *dst, const char *src) { int i, len = strlen(dst); for (i = 0; (dst[len + i] = src[i]) != '\0'; i++) ; return dst; } strcat_with_ptr.c char *strcat(char *dst, const char *src) { char *dst0 = dst; dst += strlen(dst); while ((*(dst++) = *(src++)) != '\0') ; return dst0; }

ポインタを用いた文字列の連結の例 strncat 関数の大まかな仕組み strncat_with_idx.c strncat は strcat の 連結文字を最大n文字に限定する ただしsrcがn文字以上の場合 終端文字が+1文字され 合計n+1バイト追記される char *strncat(char *dst, const char *src, size_t n) { int i, len = strlen(dst); for (i = 0; i < n && src[i] != '\0'; i++) dst[len + i] = src[i]; dst[len + i] = '\0'; return dst; } strncat_with_ptr.c char *strncat(char *dst, const char *src, size_t n) { char *dst0 = dst; dst += strlen(dst); while (0 < n-- && *src != '\0') *(dst++) = *(src++); *dst = '\0'; return dst0; }

ポインタへのポインタ 関数の引数でポインタを返したい場合はポインタ変数へのポインタを用いる 教科書 pp.243-250. strtoui.c unsigned int strtoui(const char *s, char **endp, int base) { int v; unsigned int r = 0; while (0 <= (v = basetoint(*(s++), base))) { r = r * base + v; } if (endp != NULL) *endp = (char *) s; return r; この例だと endp に "z" へのポインタ つまり&s[2]が返ってくる main.c char s[] = "ffz"; char *endp; printf("strtoui(s, &endp, 16);

main 関数の引数 コマンドライン引数と文字列

コマンドライン引数 main 関数の引数として取得出来る。 教科書 pp.265-272., [1] pp.139-144., 第8週資料 p.4. コマンドライン引数 main 関数の引数として取得出来る。 arg_ex1.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; printf("argc = %d\n", argc); for (i = 0; i < argc; i++) { printf("argv[%d] = \"%s\"\n", i, argv[i]); } return EXIT_SUCCESS; main の引数名は 自由につけて良いが 以下の名前を使うのが 慣例になっている argc: ARGument Count argv: ARGument Vector argument は英語で 引数を意味する

コマンドライン引数 main 関数の引数として取得出来る。 教科書 pp.265-272., [1] pp.139-144., 第8週資料 p.4. コマンドライン引数 main 関数の引数として取得出来る。 コマンドプロンプト >arg_ex1 a b "c d" "e\"f" argc = 5 argv[0] = "C:\Users\kou\Desktop\CLangI2015S1\week14\arg_ex1.exe" argv[1] = "a" argv[2] = "b" argv[3] = "c d" argv[4] = "e"f" mintty + bash コマンドライン空白で分割されて argvに格納される。 argvに空白を含めたい場合は 「"」(ダブルクォーテーション)で囲む 「"」を含めたい場合は「\」でエスケープする argv[0]は実行中のコマンド名 $ ./a a b "c d" "e\"f" argc = 5 argv[0] = "./argtest" argv[1] = "a" argv[2] = "b" argv[3] = "c d" argv[4] = "e"f"

コマンドライン引数 char *argv[] は char* 型の配列 教科書 pp.265-272., [1] pp.139-144., 第8週資料 p.4. コマンドライン引数 char *argv[] は char* 型の配列 mintty + bash 正確には 関数の引数で最初の [] は * と同じだったので char *argv[] は char **argv と同じ つまり char 型へのポインタへのポインタ $ ./a a b "c d" "e\"f" argc = 5 argv[0] = "./argtest" argv[1] = "a" argv[2] = "b" argv[3] = "c d" argv[4] = "e"f" argv[1] argv[2] argv[3] argv[4] 'a' '\0' 'b' 'c' ' ' 'd' 'e' '"' f

文字列とポインタ 

ポインタ配列の初期化 char * の配列の初期化 教科書.pp.235-239., [1]pp.148-153. メモリ上のどこかに配置された 文字列 char * の配列の初期化 char *s[] = {"one", "two", "three"}; 0x~00 00 0x~01 ~ 0x~02 0x~03 0x~04 04 0x~05 0x~06 0x~07 0x~08 08 0x~09 0x~0a 0x~0b 0x~00 o 0x~01 n 0x~02 e 0x~03 \0 0x~04 t 0x~05 w 0x~06 0x~07 0x~08 0x~09 h 0x~0a r 0x~0b 0x~0c 0x~0d s は char* 型で要素数3の配列 s[x] は char* 型 *s[x] は char 型 s[0] s[0] は "one" s[1] は "two" s[1] s[0][0] は 'o' s[0][1] は 'n' s[0][2] は 'e' s[0][3] は '\0' s[2]

配列とポインタの初期値と文字列 配列とポインタで扱いが異なることに注意 教科書.pp.235-239., [1]pp.148-153. pointer_ex9.c 一般にポインタに初期値として与えた 文字列定数は書き変えてはいけない void sub() { char s[] = "hello"; char *p = "world"; ... .rdataセクションに用意されたデータは 書き変えてはいけない objdump の結果 sへは"hello"の文字コード 68,65,6c,6c,6fが代入されているが pへは.rdataセクションに予め 用意してある文字列"world"の アドレス0x403060が代入されている セクション .rdata の内容: ... 403060 776f726c 64007320 3d202225 73220a00 world.s = "%s".. void sub(void) { char s[] = "hello"; 401196: c7 45 ee 68 65 6c 6c movl $0x6c6c6568,-0x12(%ebp) 40119d: 66 c7 45 f2 6f 00 movw $0x6f,-0xe(%ebp) char *p = "world"; 4011a3: c7 45 f4 60 30 40 00 movl $0x403060,-0xc(%ebp)

配列とポインタの初期値と文字列 配列とポインタで扱いが異なることに注意 教科書.pp.235-239., [1]pp.148-153. pointer_ex9.c Cygwin + GNU C void sub(void) { char s[] = "hello"; char *p = "world"; printf("s = \"%s\"\n", s); printf("p = \"%s\"\n", p); s[0] = 'H'; p[0] = 'W'; } int main() sub(); return EXIT_SUCCESS; $ gcc pointer_ex9.c && ./a s = "hello" p = "world" Segmentation fault (コアダンプ) Borland C++ >bcc32 pointer_ex9.c && pointertest6 Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland pointer_ex9.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland s = "hello" p = "world" p = "World" sub()が実行された際、 sは毎回"hello"だが pは2回目以降"World"になってしまう もしくは.rdataへの不正な書き込みで 異常終了してしまう

数値を表す文字列を数値に変換する 演習

ASCII文字コード表 教科書 p.51., 第2週資料 p.67. 下位4ビット 1 2 3 4 5 6 7 8 9 A B C D E 1 2 3 4 5 6 7 8 9 A B C D E F NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC → ← ↑ ↓ SP ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ DEL 上位4ビット http://ja.wikipedia.org/wiki/ASCII 赤字は制御コード

10進法文字列を数値に変換する "1234" のような文字列があった時 1234 に変換したい。 "1234" は char 型の配列に'\0'で終端された文字コード {0x31, 0x32, 0x33, 0x34, 0x00} という値を持つ。 まず、先頭から数字('0'~'9')のみを取り出す {0x31, 0x32, 0x33, 0x34} を得る 各文字コードから 0x30(='0') を引く {0x31-0x30, 0x32-0x30, 0x61-0x30, 0x62-0x30} より {1, 2, 3, 4} が得られる 次に末尾から𝑛桁目(0≦𝑛)に 10 𝑛 を掛ける {1*1000, 2*100, 3*10, 4*1} より {1000, 200, 30, 4} が得られる 各値を加算する 1000+200+30+4=1234 が得られる

16進法文字列を数値に変換する "0x12ab" のような文字列があった時 0x12ab=(4779) に変換したい。 "0x12ab" は char 型の配列に'\0'で終端された文字コード {0x30, 0x78, 0x31, 0x32, 0x61, 0x62, 0x00} という値を持つ。 まず、先頭から16進ヘッダを取り除いて、16進法の数字('0'~'9','a'~'f')のみを取り出す {0x31, 0x32, 0x61, 0x62} を得る 各文字コードのうち'0'~'9'からは 0x30(='0') を引き、'a'~'f'からは 0x61(='a') を引き 0xa(=10) を足す {0x31-0x30, 0x32-0x30, 0x61-0x61+0xa, 0x62-0x61+0xa} より {1, 2, 10, 11} が得られる 次に末尾から𝑛桁目(0≦𝑛)に 16 𝑛 を掛ける {1*4096, 2*256, 10*16, 11*1} より {4096, 512, 160, 11} が得られる 各値を加算する 4096+512+160+11=4779 が得られる 訂正2015-07-17 誤:0x61-0x60+0xa 正:0x61-0x61+0xa

N進法文字列を数値に変換する "12ab" のような文字列があった時、これをN進法とみなして数値に変換したい。 "12ab" は char 型の配列に'\0'で終端された文字コード {0x31, 0x32, 0x61, 0x62, 0x00} という値を持つ。 まず、先頭からN進法の数字('0'~'9','a'~'z')のみを取り出す {0x31, 0x32, 0x61, 0x62} を得る 各文字コードのうち'0'~'9'からは 0x30(='0') を引き、'a'~'f'からは 0x61(='a') を引き 0xa(=10) を足す {0x31-0x30, 0x32-0x30, 0x61-0x61+0xa, 0x62-0x61+0xa} より {1, 2, 10, 11} が得られる 次に末尾から𝑛桁目(0≦𝑛)に 𝑁 𝑛 を掛ける {1* 𝑁 3 , 2* 𝑁 2 , 10* 𝑁 1 , 11* 𝑁 0 } が得られる 各値を加算する 1* 𝑁 3 +2* 𝑁 2 +10* 𝑁 1 +11* 𝑁 0 が得られる 訂正2015-07-17 誤:0x61-0x60+0xa 正:0x61-0x61+0xa 訂正2015-07-17 誤: {0x30, 0x78, 0x31, 0x32, 0x61, 0x62, 0x00} 正: {0x31, 0x32, 0x61, 0x62, 0x00} 結局10進の場合も、16進の場合も N進の場合で一般化出来る ↓ N進変換のルーチンさえ作れば 全て変換出来る

N進整数文字列の一般化 文字列による整数の表現は以下のようになるはず ここで 例: [符号][N進数ヘッダ]N進法表現による文字列 符号: '+', '-' の何れかで省略の場合は'+'扱い N進法ヘッダ: 基数が与えられていな場合(基数=0の場合)に利用 2,8,16進法に対して"0b","0","0x"の何れかで省略時は10進法扱い N進法表現による文字列: Nを2~36とすると1桁の数値は'0'~'9','a'~'z','A'~'Z'の何れかの文字 例: 2進法: "0b11"(=3), 8進法: "077"(=63), 10進法: "99", 16進法: "0xff"(=255), 36進法: "zz"(=1295) 符号の有無: "+0x123", "-0x123", "0x123"

N進整数文字列の数値化 N進整数の文字列sに対して 符号があれば読み飛ばし、+1 または -1 を得る 符号の処理 符号があれば読み飛ばし、+1 または -1 を得る N進法ヘッダの処理 N進法ヘッダがあれば読み飛ばし、基数を得る N進整数数値化処理本体 N進整数文字列を数値に変換する

N進整数文字列の数値化 N進整数の文字列sに対して 何らかの方法で呼び出し元に 決定した符号を返してやる必要がある 戻り値が2つ必要 符号の処理 *s は? 何らかの方法で呼び出し元に 決定した符号を返してやる必要がある 戻り値が2つ必要 '-' s++ 符号は-1 何らかの方法で呼び出し元に sの現在位置を返してやる必要がある '+' s++ その他 符号は+1

N進整数文字列の数値化 N進整数の文字列sに対して strtoi.c では この部分も必要となる strtobase.c はこの部分 基数の指示が ある? N *s は? *s は? Y '0' s++ 'b' s++ 2進 'x' s++ 16進 その他 10進 その他 8進

N進整数文字列の数値化 N進整数の文字列sに対して ヒント '0'~'9' から 0x30(='0')を引く 'A'~'Z' から 0x41(='A')を引き 0xa(=10)を足す 'a'~'z' から 0x61(='a')を引き 0xa(=10)を足す *s は N進文字か? N Y *s を数値化 変換済み数値に符号を付加 例えば "0x1234" なら基数 N=16 であり result = 0; result += result * 16 + 4; // result は 0x4 result += result * 16 + 3; // result は 0x34 result += result * 16 + 2; // result は 0x234 result += result * 16 + 1; // result は 0x1234 とすると result に 0x1234 が得られる N倍した変換済み数値に加算 s++ 変換済み数値を返して終了 訂正2015-07-17 1,2,3,4 の加算順が逆だった(次項参照)

N進整数文字列の数値化 N進整数の文字列sに対して ヒント '0'~'9' から 0x30(='0')を引く 訂正2015-07-25 誤: result += result * ... 正: result = result * ... N進整数数値化処理本体 ヒント '0'~'9' から 0x30(='0')を引く 'A'~'Z' から 0x41(='A')を引き 0xa(=10)を足す 'a'~'z' から 0x61(='a')を引き 0xa(=10)を足す *s は N進文字か? N Y *s を数値化 変換済み数値に符号を付加 例えば "0x1234" なら基数 N=16 であり result = 0; result = result * 16 + 1; // result は 0x1 result = result * 16 + 2; // result は 0x12 result = result * 16 + 3; // result は 0x123 result = result * 16 + 4; // result は 0x1234 とすると result に 0x1234 が得られる N倍した変換済み数値に加算 s++ 変換済み数値を返して終了 訂正2015-07-17 1,2,3,4 の加算順が逆だった(前頁参照)

例題: strtosign.c 文字列sの先頭1文字を確認し、符号の識別子('-'または'+')の有無に応じて-1,+1の何れかを返す関数 strtosign を作成せよ 関数のプロトタイプ宣言はmyfunc_week14.hに作成せよ strtosign_test.c と共にコンパイルして動作を確認せよ 引数 const char *s: 確認する文字列 char **endp: 未処理の文字列へのポインタを返すために用いる 戻り値 符号の識別子がある場合'-'なら-1、'+'なら+1、それ以外なら+1をint型で返す endp が NULL 以外の時は以下の値を*endpに返す 符号の識別子がなかった場合先頭文字(つまりs[0])へのポインタ 符号の識別子があった場合符号識別子の次の文字(つまりs[1])へのポインタ

例題: strtosign.c フローチャートから書き起こす strtosign.c 符号の処理 int strtosign(const char *s, char **endp) { int sign; switch (*s) { case '-': s++; sign = -1; break; case '+': default: sign = +1; } if (endp != NULL) *endp = (char *) s; return sign; *s は? '-' s++ 符号は-1 '+' s++ その他 符号は+1 mintty + bash + GNU C $ gcc strtosign_test.c strtosign.c && ./a s = ? -5 s = "-5"(0x22c710) strtosign(s, &endp) = -1 endp = "5"(0x22c711)

例題: strtosign.c ヒント: *endp には s[0] または s[1] へのポインタが入る s[0] へのポインタは s, s[1] へのポインタは、s++ した後の s でも良い mintty + bash + GNU C $ gcc strtosign_test.c strtosign.c && ./a s = ? -5 s = "-5"(0x22c710) strtosign(s, &endp) = -1 endp = "5"(0x22c711)

演習: strtobase.c 文字列sの先頭2文字を確認し、0b,0,0xなら2,8,16進数、それ以外なら10進数と判別する関数 strtobase を作成せよ 関数のプロトタイプ宣言はmyfunc_week14.hに作成せよ strtobase_test.c と共にコンパイルして動作を確認せよ 引数 const char *s : 確認する文字列 char **endp : 未処理の文字列へのポインタを返すために用いる 戻り値 文字列sの先頭2文字に応じて、2,8,10,16の何れかをint型で返す endp が NULL 以外の時は以下の値を*endpに返す 基数識別子(N進数ヘッダ: 0, 0b, 0x)がない場合、先頭文字(つまりs[0])へのポインタ 基数識別子がある場合、基数識別子の次の文字(つまりs[1]またはs[2])へのポインタ

演習: strtobase.c ヒント: 前出の「N進法ヘッダの処理」のフローチャートを見てみよう mintty + bash + GNU C $ gcc strtobase_test.c strtobase.c && ./a s = 0x123 s = "0x123"(0x22c710) strtobase(s, &endp) = 16 endp = "123"(0x22c712)

演習: base36toint.c 36進法で用いられる'0'~'9','A'~'Z','a'~'z' (文字コード: 0x30~0x39, 0x41~0x5a, 0x61~0x7a) までの文字をint型の数値0~35に変換する関数 base36toint を作成せよ 関数のプロトタイプ宣言は myfunc_week14.h に作成せよ エラーの際、DEBUG マクロが定義されていたら、標準エラー出力に警告メッセージを表示せよ base36toint_test.c と共にコンパイルして動作を確認する事 引数 int c : 数値に変換する文字コード 戻り値 cで与えられた文字コードに対応する数値0~35をint型で返す cが'0'~'9'を0~9,'A'~'Z'と'a'~'z'は共に10~35に変換し、そのいずれでもない場合はエラーとなる エラーの場合は-1を返す mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c && ./a c = ? z 35

演習: base36toint.c ヒント: cが'0'~'9'である場合、c-'0'とすると、0~9の数値に変換出来る cが'a'~'z'の場合、 c-'a'はいくらだろう? もし場合分けが面倒なら A~Z と a~z は tolower 関数または toupper 関数 で大文字か小文字に変換してしまうと大文字小文字の場合分けが必要なくなる mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c && ./a c = ? z 35

演習: base36toint.c ヒント: デバッグ出力は以下のようにすれば良い mintty + bash + GNU C #ifdef DEBUG fprintf(stderr, "Warning: in file %s line %d: invalid value: c = '%c'(=%#04x)\n", __FILE__, __LINE__, c, c); #endif mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c -DDEBUG && ./a c = ? @ Warning: in file base36toint.c line 15: invalid value: c = '@'(=0x40) -1

演習: basetoint.c 「0~9,A~Z,a~z」の文字をN進数表現の1桁としてint型の数値に変換する関数 basetointを 作成せよ 関数のプロトタイプ宣言はmyfunc_week14.hに作成せよ エラーの際、DEBUGマクロが定義されていたら、標準エラー出力に警告メッセージを表示せよ basetoint_test.cと共にコンパイルして動作を確認する事 引数 int c : 数値に変換する文字コード int base : N進数表現の基数(つまりN=base)、2~36 戻り値 cで与えられた文字コードに対応する数値0~base-1をint型で返す 変換結果やbaseの値が範囲外の場合はエラーとなる エラーの場合は-1を返す mintty + bash + GNU C $ gcc basetoint_test.c basetoint.c base36toint.c && ./a c = ? z base = ? 10 -1

演習: basetoint.c ヒント base36toint.c を用いると簡単に作成出来る base36toint の結果が -1 なら 36 進法で使えない数字 N 以上なら N 進法で使えない数字 訂正2015-07-17 誤: N 以下 正: N 以上

演習: strtoi.c N進整数を表現した文字列をint型の値に変換する関数 strtoi を作成せよ 関数のプロトタイプ宣言はmyfunc_week14.hに作成せよ strtoi_test.cと共にコンパイルして動作を確認する事 引数 const char *s : 変換する文字列 char **endp : 未処理の文字列へのポインタを返すために用いる int base : N進数表現の基数(つまりN=base)、2~36 戻り値 文字列sを基数baseとして数値に変換した結果をint型で返す 文字列先頭に符号識別子('-','+')がある場合、変換結果の±に反映される baseに0が与えられた場合、文字列先頭に0b,0,0xがあれば、2,8,16進数、それ以外なら10進数として扱う。 endp が NULL 以外の時は以下の値を*endpに返す 変換出来た最後の文字の次の文字へのポインタ

講義資料 第10週 p.62.から移動 演習: strtoi.c ヒント: strtosign.c, strtobase.c, basetoint.c を利用すると比較的簡単に作成できる mintty + bash + GNU C $ gcc strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c && ./a s = -0xff base = 0 s = "-0xff"(0x22a6c0) str(s, &endp, base) = -255 endp = ""(0x22a6c5)

演習: strtoi.c ヒント basetoint(*s, N) の結果が -1 なら N 進文字以外 -1 なら36進文字以外 N 以上なら N 進文字以外 N進整数数値化処理本体 符号の処理 *s は N進文字か? N base36toint(*s) の結果を そのまま使える N進法ヘッダの処理 Y *s を数値化 変換済み数値に符号を付加 N進整数数値化処理本体 N倍した変換済み数値に加算 全体が strtoi s++ 変換済み数値を返して終了

C言語の開発支援ツール

分割コンパイル ファイルが多くなるとコンパイルが大変 mintty + bash + GNU C cmd + Borland C++ $ gcc strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $ cmd + Borland C++ >bcc32 strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland strtoi_test.c: strtoi.c: strtosign.c: strtobase.c: basetoint.c: base36toint.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland 一度実行すれば カーソルキーの上下で コマンドの実行履歴から 選べるが、最初が面倒 1ファイルしか変更してないのに 全ファイルコンパイルし直すのは非効率

make コマンド 依存関係を記述し必要な処理だけ行う Makefile に依存関係と作成方法を記述する Makefile.cygwin.strtoi_test,1 all: strtoi_test.exe strtoi_test.exe: strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $(CC) -o $@ $^ clean: -rm strtoi_test.exe 作成するファイル: 材料のファイル ... タブ...→作成方法 Makefile.bcc32.strtoi_test all: strtoi_test.exe strtoi_test.exe: strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $(CC) strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c clean: -DEL strtoi_test.exe *.obj *.tds

make コマンド make と打つだけで自動的にコンパイル mintty + bash + GNU C cmd + Borland C++ $ make -f Makefile.cygwin.strtoi_test,1 cc -o strtoi_test.exe strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c cmd + Borland C++ >make -f Makefile.bcc32.strtoi_test MAKE Version 5.2 Copyright (c) 1987, 2000 Borland bcc32 strtoi_test.c strtoi.c strtosign.c strtobase.c basetoint.c base36t oint.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland strtoi_test.c: strtoi.c: strtosign.c: strtobase.c: basetoint.c: base36toint.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

make コマンド 依存関係の記述 作成するファイル: 材料のファイル ... タブ...→作成方法 Makefile.cygwin.strtoi_test,2 all: strtoi_test.exe strtoi_test.exe: strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o $(CC) -o $@ $^ strtoi_test.o: strtoi_test.c myfunc_week14.h strtoi.o: strtoi.c myfunc_week14.h strtosign.o: strtosign.c myfunc_week14.h strtobase.o: strtobase.c myfunc_week14.h basetoint.o: basetoint.c myfunc_week14.h base36toint.o: base36toint.c myfunc_week14.h clean: -rm strtoi_test.exe strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o 標準的な作成方法で良い場合は 作成方法は省略出来る 訂正2015-07-25 誤: myfunc_week10.h, myfunc_week10.h, myfunc_week12.h 正: myfunc_week14.h

make コマンド 依存関係の解決 コンパイルが完了しているので 改めてコンパイルする 必要がなかった mintty + bash + GNU C 直前に削除したため改めて コンパイルが必要になった ファイルだけ処理し直して てくれている $ make -f Makefile.cygwin.strtoi_test,2 cc -c -o strtoi_test.o strtoi_test.c cc -c -o strtoi.o strtoi.c cc -c -o strtosign.o strtosign.c cc -c -o strtobase.o strtobase.c cc -c -o basetoint.o basetoint.c cc -c -o base36toint.o base36toint.c cc -o strtoi_test.exe strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o $ make make: Nothing to be done for 'all'. $ rm strtosign.o

make コマンド 依存関係の解決 例: 必要に応じて適宜作成方法を実行する 材料のファイルが不足している場合 作成するファイル(旧)、材料のファイル(新)の場合

make コマンド 同じmakeという名前が付いていて基本は同じだが方言があり、細かい違いがある Wikipedia / make GNU Make Embarcadero / MAKE JM / make (1) FreeBSD 9.0-RELEASE-K / make (1) MSDN / NMAKE Reference

その他のビルドツール Autotools autoconf, automake, libtool の総称 UNIX 系のソフトウェアでは標準的なビルドツール 以下の標準的な手順でビルド出来るようになる 書籍 GNU AUTOCONF, AUTOMAKE, AND LIBTOOL https://sourceware.org/autobook/ (無料オンライン版) Wikipedia / Autotools mintty + bash + GNU C $ ./configure $ make $ make install

その他のビルドツール CMake - http://www.cmake.org/ Wikipedia / CMake マルチプラットフォームな Makefile 作成ツール Wikipedia / CMake

ライブラリの自作 標準ライブラリ関数はアーカイブやライブラリと呼ばれる複数のオブジェクトファイルを1つにまとめたファイルとして提供されている 教科書pp.203-206. ライブラリの自作 標準ライブラリ関数はアーカイブやライブラリと呼ばれる複数のオブジェクトファイルを1つにまとめたファイルとして提供されている cygwinでは/usr/lib/libc.a等 Borland C++ではC:\boland\bcc32\Lib\cw32.lib等 標準ライブラリはコンパイル時に自動的にリンクされる 但し <math.h> 等は -lm 等として明示的に /usr/lib/libm.aをリンクする必要がある場合もある

ライブラリの自作 複数のオブジェクトファイルを1つのファイルにまとめるにはアーカイバやライブラリアンと呼ばれるツールを用いる JM / ar (1) 作成方法: ar q ライブラリ名 オブジェクトファイル名 ... embarcadero / ライブラリマネージャ TLIB.EXE 作成方法: tlib ライブラリ名 -+オブジェクトファイル名 ...

ライブラリの自作(Cygwin) 複数のオブジェクトファイル(.oファイル)を1つの.aファイルにまとめる まとめたファイルをアーカイブ(archive)またはスタティックライブラリ(static library)と呼ぶ mintty + bash + GNU C $ gcc -c strtoi.c strtosign.c strtobase.c basetoint.c base36toint.c $ ar q myfunc.a strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o ar: myfunc.a を作成しています $ gcc strtoi_test.c myfunc.a 必要な .o ファイルを myfunc.a から探してリンクし 実行ファイルを作成 複数の .o ファイルをまとめた .a ファイルの作成

ライブラリの自作(Borland C++) 複数のオブジェクトファイル(.objファイル)を1つの.libファイルにまとめる まとめたファイルをライブラリと呼ぶ cmd + Borland C++ >bcc32 /c strtoi.c strtosign.c strtobase.cbasetoint.c base36toint.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland strtoi.c: strtosign.c: strtobase.c: basetoint.c: base36toint.c: >tlib myfunc.lib -+strtoi.obj -+strtosign.obj -+strtobase.obj -+basetoint.obj -+base36toint.obj TLIB 4.5 Copyright (c) 1987, 1999 Inprise Corporation >bcc32 strtoi_test.c myfunc.lib strtoi_test.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland 複数の .o ファイルをまとめた .lib ファイルの作成 必要な .obj ファイルを myfunc.lib から探してリンクし 実行ファイルを作成

ライブラリの自作 make によるアーカイブの作成 Makefile.cygwin.myfunc.a all: myfunc.a myfunc.a: strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o $(AR) q $@ $^ strtoi_test.o: strtoi_test.c myfunc_week14.h strtoi.o: strtoi.c myfunc_week14.h strtosign.o: strtosign.c myfunc_week14.h strtobase.o: strtobase.c myfunc_week14.h basetoint.o: basetoint.c myfunc_week14.h base36toint.o: base36toint.c myfunc_week14.h clean: -rm myfunc.a strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o 訂正2015-07-25 誤: myfunc_week10.h, myfunc_week10.h, myfunc_week12.h 正: myfunc_week14.h

ライブラリの自作 make によるアーカイブの作成 mintty + bash + GNU C $ make -f Makefile.cygwin.myfunc.a cc -c -o strtoi.o strtoi.c cc -c -o strtosign.o strtosign.c cc -c -o strtobase.o strtobase.c cc -c -o basetoint.o basetoint.c cc -c -o base36toint.o base36toint.c ar q myfunc.a strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o ar: myfunc.a を作成しています

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