プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機...

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

Upload: others

Post on 28-Sep-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門

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

報処理言語Ⅰ(実習を含む。) 第1週~第15週

1 CLangI2015S1

Page 2: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第1週

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

情報処理言語Ⅰ(実習を含む。)

2

Page 3: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

本日の内容

• 授業予定日の確認

• 授業教材の指示

• C言語用プログラミング環境の整備

• C言語プログラミングの導入部分

3

Page 4: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

授業予定日の確認

• 授業予定日の変更があります • 本来の授業予定日:

• 毎週金曜日 7,8,9,10 時限 4/10、 4/17、 4/24、 5/1、 5/15、 5/22、 5/29、 6/5、 6/12、 6/19、 6/26、 7/3、 7/10、 7/17、 7/24、 7/31 以上16回、最終日は期末試験

• ただし以下の授業予定日は出張のため、翌日または翌々日に変更になります。 • 金曜日: 4/24、5/22、6/19、7/10 休講 • 土曜日: 4/25、5/23、6/20、7/11 補講候補日1 • 日曜日: 4/26、5/24、6/21、7/12 補講候補日2

4

Page 5: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

授業変更日の確認

4月 日 月 火 水 木 金 土 1 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 5月 日 月 火 水 木 金 土 1 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

6月 日 月 火 水 木 金 土 1 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 7月 日 月 火 水 木 金 土 1 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

5

Page 6: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

教材のページ

• 修学支援システムの講義情報から Moodle【学内外版】へ

6

Page 7: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドプロンプト

• キーボードから直接命令を入力して実行する時に使います。本講義ではC言語によるプログラムのソースコードをコンパイル(=機械語に翻訳)する場合等に利用する。

Page 8: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドプロンプトを開く

• キーボードから「田」を押したまま「R」を押して「ファイル名を指定して実行」を開く。 「田+R」のように表記された場合、慣例として上記のような複数キー同時押しを意味する。

• 「ファイル名を指定して実行」 の「名前」の欄に「cmd」と入力し、 「ENTER」キーを押すか、「OK」ボタンをクリックする。

「スタート」ボタンから、「すべてのプログラム」→「アクセサリ」→「コマンドプロンプト」でも開ける。

Page 9: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドプロンプトの設定項目

• 「簡易編集モード」をONにしておくと、マウスの左右ボタンだけでコピペ出来る。

Page 10: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドプロンプトの設定

• ウインドウ左上のアイコンをクリックするとメニューが出る。

「プロパティ」で現在開いているプロンプトのみ、「規定値」で次回以降開くプロンプト全てに対する設定を変更出来ます。

Page 11: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドプロンプトと作業ディレクトリ

• 「作業ディレクトリ」とはコマンドプロンプトで作業した際に、ファイルが入出力されるディレクトリの事。

通常、コマンドプロンプトを開いた初期状態では、ユーザーのホームまたはプロファイルのディレクトリが作業ディレクトリ。

ディレクトリとはフォルダの別の言い方。 つまり「ディレクトリ=フォルダ」

Page 12: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

作業ディレクトリとコマンド

• コマンドプロンプトで「explorer .」と入力して ENTER キーを押す。

• 現在の作業ディレクトリが explorer で開く。

「explorer」とは、Windows上で、

いつもファイルを操作しているこのウインドウの事。

「explorer」がコマンド名(≒ プログラムの実行ファイル名)で、スペースで区切って与えた「.」はコマ

ンドライン引数と言います。この場合「.」は、現在の作業ディレクトリを表す。

Page 13: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

本来のディレクトリ名

• explorer 上では本来のディレクトリ名が日本語も用いて分かり易く(?)表示されている。

ここをクリックすると、コマンドプロンプト上の作業ディレクトリの表示と一致していることが確認出来る。

これが本来のディレクトリ名 explore 以外ではこちらを使う。

異なる名前に見える

「C:¥Users¥kou」は C ドライブの Users フォルダの中にある kou フォルダを意味する。

Page 14: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プログラミング言語、計算機言語、 情報処理言語とは?

• コンピュータに命令するための人工言語

• AWK, BASIC, C, C++, C#, D, ECMAScript, Erlang, Fortran, F#, Haskell, Java, JavaScript, Lisp, Objective-C, OCaml, Perl, PHP, Python, Ruby, Smalltalk, Tcl, 等々

14

Page 15: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プログラムとは?

• 値の保存・参照、各種演算、条件分岐等を組み合わせた計算の手順

処理

データ

保存

データ

参照

条件判定

処理

処理

処理

15

Page 16: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プログラムが出来ると 何が良いのか?

• コンピュータに仕事をやってもらえる!!! • ルーチンワークからの解放

• 工作の世界も広がる!!! • 最近は Arduino 等の安くて高機能なキットがある • http://thinkit.co.jp/story/2013/02/12/3960

• 楽しい!!! • 遊び方は遊ぶ人次第

• 仕事にもあぶれない? • Facebook元役員「プログラミングを学ぶのなら、生

涯仕事に困らないことを私が保証しよう。」 • http://goo.gl/I8nCDm

16

Page 17: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語

• AT&T の Bell 研で UNIX を作ってた Brian Wilson Kernighan と Dennis MacAlistair Ritchie らによって UNIX を作成するための言語として生まれた。

• K&R 「プログラミング言語C」がC言語のバイブルと言われる所以。

17

Page 18: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

世界で最も有名なプログラム

• K&R の最初に出て来るプログラム hello.c

18

hello.c #include <stdio.h> main() { printf("hello, world¥n"); }

1 2 3 4 5 6

mintty + bash + GNU C $ gcc hello.c && ./a hello, world

教科書 p.37., [1] p.8.

Page 19: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

世界で最も有名なプログラム

• K&R の最初に出て来るプログラム hello.c

19

hello.c #include <stdio.h> main() { printf("hello, world¥n"); }

1 2 3 4 5 6

ヘッダファイル(stdio.h)の取り込み

mintty + bash + GNU C $ gcc hello.c && ./a hello, world

プログラムのソースコードを コンパイルして実行

文字列の表示

main関数の定義

Page 20: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ヘッダファイル stdio.h

• 多くの入門書ではおまじないとして紹介

20

hello.c #include <stdio.h> main() { printf("hello, world¥n"); }

1 2 3 4 5 6

ヘッダファイル(stdio.h)の取り込み

mintty + bash + GNU C $ gcc hello.c && ./a hello, world

・C言語は言語本体だけでは、四則演算、条件分岐、繰り返し等の基本的な処理以外ほとんど何も出来ない。

・文字列の入出力や数学の関数等、基本的かつ必要性の高い機能は、標準ライブラリと呼ばれる、サブルーチン集として用意されている。 ・printf 関数は stdio.h (= STanDard Input Output Header file) で提供されている。

printf 関数の呼び出し

Page 21: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語のプログラム

• コンパイラにより実行形式に変換する

.c ファイル

.h ファイル .h ファイル

.h ファイル

.c ファイル .c ファイル

Source files

C compiler

Preprocessor

linker

.o ファイル

Object files

.o ファイル .o ファイル

実行ファイル

Executable file

21

Page 22: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C コンパイラによるコンパイル

• Cygwin の mintty で bash から gcc で行った例

mintty + bash + GNU C $ ls hello.c $ gcc hello.c $ ls a.exe hello.c $ ./a hello, world

ファイル一覧の表示

コンパイル

ファイル一覧の表示

作成した実行ファイルを実行

22

Page 23: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C コンパイラによるコンパイル

• コマンドプロンプトからBorland C++で行った例

コマンドプロンプト + Borland C++ >dir /B hello.c >bcc32 hello.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland hello.c: 警告 W8070 hello.c 6: 関数は値を返すべき(関数 main ) Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland >dir /B hello.c hello.obj hello.tds hello.exe >hello hello, world

ファイル一覧の表示

コンパイル

ファイル一覧の表示

作成した実行ファイルを実行

23

Page 24: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C/C++ リファレンス

• http://www.cppll.jp/cppreference/ Windows Help (.chm) 版を入

れておくと便利です。

24

Page 25: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C 言語の規則

• 各処理の末尾はセミコロン「;」で終端する。

25

hello.c #include <stdio.h> main() { printf("hello, world¥n"); }

1 2 3 4 5 6

これがないとコンパイル時にエラーとなる。

Page 26: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

セミコロン「;」を忘れたエラーの例

• 各処理の末尾はセミコロン「;」で終端する。

26

hello_err.c #include <stdio.h> main() { printf("hello, world¥n") }

1 2 3 4 5 6

本当はここに「;」が必要。

mintty + bash + GNU C $ gcc hello_err.c hello_err.c: 関数 ‘main’ 内: hello_err.c:6:1: エラー: expected ‘;’ before ‘}’ token } ^

Page 27: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

セミコロン「;」を忘れたエラーの例

• 各処理の末尾はセミコロン「;」で終端する。

27

hello_err.c #include <stdio.h> main() { printf("hello, world¥n") }

1 2 3 4 5 6

本当はここに「;」が必要。

コマンドプロンプト + Borland C++ >bcc32 hello_err.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland hello_err.c: エラー E2379 hello_err.c 6: ステートメントにセミコロン(;)がない(関数 main ) 警告 W8070 hello_err.c 6: 関数は値を返すべき(関数 main )

Page 28: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

エラーの例

• hello.c の 関数「main」の内にある 6 行目の1文字目にあるトークン「}」の前に「;」が(あることが)予想されますよ、と言っている。

28

mintty + bash + GNU C $ gcc hello_err.c hello_err.c: 関数 ‘main’ 内: hello_err.c:6:1: エラー: expected ‘;’ before ‘}’ token } ^

Page 29: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C 言語の規則

• { } で複数の処理をまとめる。

29

hello1.c #include <stdio.h> main() { printf("hello"); printf(", world¥n"); }

1 2 3 4 5 6 7

{ } の間に ; で終端

された複数の処理を書いてよい。

Page 30: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C 言語の規則

• " " で囲まれた部分は文字列

30

hello1.c #include <stdio.h> main() { printf("hello"); printf(", world¥n"); }

1 2 3 4 5 6 7

{ } の間に ; で終端

された複数の処理を書いてよい。

Page 31: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C 言語の構造

• プログラムは関数の形でまとめる。

31

関数定義の書式 戻り値の型 関数名(引数の宣言, ...) { // 処理; // ... // return 戻り値; }

1 2 3 4 5 6

関数は上記のように定義し、( ) の中に書かれた引数で(呼び出し元や呼び出し先の)他の関数と値の受け渡しを行う。

Page 32: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C 言語の規則

• プログラムは main 関数から実行される。

32

main.c main() { // ここに処理を書く }

1 2 3 4

mintty + bash + GNU C $ gcc main.c && ./a

これは何もしないで終わるだけのプログラム。

// から行末までと /* から */ までは プログラムとして解釈はされない。 コメントと呼ばれる要素で、

メモや覚書として主に人間が読む際の注釈を書くために使う他、一時的にプログラムの一部を無効にするために使う。

Page 33: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

宿題

• 次回までに以下の事をやっておくこと。

• 教科書の第1章までを読み、指示された操作を試して動作を確認する。

• 不明な点、疑問点についてメモし、次回の授業に持参する。または、本講義の Moodle コース上にある第1週宿題用フォーラムに書き込んでおく。

33

Page 34: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

34

Page 35: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第2週

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

情報処理言語Ⅰ(実習を含む。)

35

Page 36: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

先週の復習1

explorer の使い方

36

Page 37: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

explorer.exe

• ファイルの操作を行うソフト

• デスクトップもエクスプローラーの一部

ここに「explorer」と入力し ENTERキーを叩いても

explorer が表示できます

これが「explorer」 デスクトップも「explorer」

コントロールパネルも 「explorer」

37

Page 38: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポップアップ(popup)メニューの表示

• 表示させたい場所でマウス右クリック

• 例えばデスクトップの何もない場所で

• メニューの右にある三角印

• サブメニューが出る

ポップアップメニュー

サブメニュー

38

Page 39: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルの作成とオープン

• explorer の

• 作成したい場所で マウス右クリック

• ポップアップメニューが出る

• 新規作成→テキストドキュメント

• 出来たファイルは 適当に名前を付けても良い

• マウス左ダブルクリック →メモ帳で開かれる

39

Page 40: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

フォルダの作成

• 作成したい所で右クリック

• ポップアップメニューで

• →新規作成

• →フォルダ

• 「新しいフォルダ」ができた

40

Page 41: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

フォルダを開く

• フォルダアイコンの上で左ダブルクリック

• explorer が開く

開いているフォルダ名

41

Page 42: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルの移動

• 「テキストドキュメント」を

• 「新しいフォルダ」の中に移動

• 「ドラッグ&ドロップ」すれば良い

ドラッグ&ドロップ 移動しました

42

Page 43: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルのコピー

• Ctrl を押したまま 「ドラッグ&ドロップ」

コピーができました

43

Page 44: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルの選択

• ファイルを単純にクリック

• ファイル左側のチェックボックスをクリック

• CTRL キーを押したままクリック(複数選択)

• ファイルを囲むようにドラッグ(複数選択)

選択された

44

Page 45: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルの削除

• 選択したファイル上で右クリック

• →削除

• ファイルを選択して「Delete」キーでも良い

ファイルが消えた

45

Page 46: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

CUI作業環境 (端末: terminal)

• フォルダをSHIFT+右クリック

コマンドプロンプト

mintty + bash

46

右クリックしたフォルダを作業ディレクトリにして 端末(コマンドプロンプトやmintty)が開かれる

Page 47: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

cmd と bash の主なコマンド

cmd bash

マニュアルの表示 help [コマンド名] man [コマンド名]

ファイル一覧 dir ls

メッセージの表示 echo メッセージ echo メッセージ

ファイルの内容を表示 type ファイル名 cat [ファイル名]

作業ディレクトリの移動 cd ディレクトリ名 cd [ディレクトリ名]

作業ディレクトリの表示 cd pwd

ファイルコピー copy コピー元 コピー先 cp コピー元 コピー先

ファイル移動 move コピー元 コピー先 mv コピー元 コピー先

ファイル削除 del ファイル名 rm ファイル名

ディレクトリの作成 mkdir ディレクトリ名 mkdir ディレクトリ名

ディレクトリの削除 rmdir ディレクトリ名 rmdir ディレクトリ目

47

Page 48: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

cmd と bash の主なキー操作コマンド

48

cmd bash 動作

行頭へ移動

行末へ移動

行末まで削除

ファイル名の補完

コマンド履歴の再利用

tab |← →|

Home

END

Ctrl K

+ Shift End +

Ctrl E

+

Ctrl A

+

Page 49: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルの場所の記述方法(パス)

• 以下の図のフォルダ構成を仮定する

教科書 pp.30-31. 49

C:

Users

kou

Desktop

CLangI CLangII

week01 week01

hello.c hellogui.c

作業フォルダは CLangI

Page 50: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

作業フォルダ

• カレントディレクトリ(current directory)とも言う

ここに表示されているのが 作業フォルダ

50

コマンドプロンプト

mintty + bash

Page 51: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

Windows の絶対パス、相対パス

• フォルダの階層を ¥ で区切る

• 現在の作業フォルダは以下の場所 • C:¥Users¥kou¥Desktop¥CLangI

• 絶対パスはルートデバイスを基準に • C:¥Users¥kou¥Desktop¥CLangI¥week01¥hello.c

• C:¥Users¥kou¥Desktop¥CLangII¥week01¥hellogui.c

• 相対パスは現在の作業フォルダを基準に • week01¥hello.c

• ..¥CLangII¥week01¥hellogui.c

教科書 pp.30-31. 51

Page 52: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

Cygwin の絶対パス、相対パス

• ディレクトリの階層を / で区切る

• 現在の作業ディレクトリは以下の場所 • /cygdrive/c/Users/kou/Desktop/CLangI

• 絶対パスはルートディレクトリ / を基準に • /cygdrive/c/Users/kou/Desktop/CLangI/week01/hello.c

• /cygdrive/c/Users/kou/Desktop/CLangII/week01/hellogui.c

• 相対パスは現在の作業ディレクトリを基準に • week01/hello.c

• ../CLangII/week01/hellogui.c

52

Page 53: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

特別なフォルダ名

• 「..」

• 1つ親のディレクトリを意味する

• 「.」

• 現在のディレクトリを意味する

• UNIX では実行ファイルの検索パスに作業ディレクトリが含まれない

• 作業ディレクトリ内にある実行ファイルを実行する際 ./ を実行ファイル名の前に付ける必要がある

53

Page 54: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

補足

• フォルダとディレクトリは同じ概念 • Windows 流ではフォルダと呼ぶ • UNIX 流ではディレクトリと呼ぶ

• /cygdrive は cygwin 特有の仮想ディレクトリ • Windows のドライブが配置されている • 通常 UNIX ではパスに : (コロン)を使わないため

• ネットワークドライブもアクセス出来る • UNC 表記を用いる • ¥¥fs.cc.yamaguchi-u.ac.jp¥YUアカウント名 • //fs.cc.yamaguchi-u.ac.jp/YUアカウント名

54

Page 55: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドの検索パス

• 環境変数 PATH に設定されたパスからコマンドを探して実行する

• cmd での確認方法

• 複数のパスは ; (セミコロン)で区切って与える

• bash での確認方法

• 複数のパスは : (コロン)で区切って与える

> echo %PATH%

$ echo $PATH

55

Page 56: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイル拡張子の表示 Windows 8 以降

• explorer.exe から 「表示」→「ファイル名拡張子」→ON

ファイル名末尾に .○○○と表示される

教科書 p.27. 56

Page 57: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイル拡張子の表示 Windows 7 以前

• explorer.exe から

• 「Alt」→「ツール」→「オプション」→「表示」 →「登録されている拡張子は表示しない」→OFF

Alt叩くとメニュー出る

ファイル名末尾に .○○○と出る

教科書 p.27. 57

Page 58: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイル拡張子とは?

• ファイルの種類を表している • アプリケーションとの関連付けに用いられる

• 実行ファイルは .exe や .com • テキスト文書は .txt • Word2007以降は .docx それより前は .doc • Excel2007以降は .xlsx それより前は .xls • PowerPoint2007以降は .pptx それより前は .ppt • 圧縮ファイルは .zip .lzh .tgz .cab 等々 • 等々

• 変更すると開けなくなる • 普通は変更する必要はない • メール等で添付されて来たファイルには注意

• 文書ファイルに見えて実行ファイル(実はウィルス)ということも

58

Page 59: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C コンパイラによるコンパイル

• cmd.exe から bcc32 で行った例 コマンドプロンプト + Borland C++ C:¥Users¥kou¥Desktop¥CLangI2014>dir /B hello.c C:¥Users¥kou¥Desktop¥CLangI2014>bcc32 hello.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland hello.c: 警告 W8070 hello.c 6: 関数は値を返すべき(関数 main ) Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland C:¥Users¥kou¥Desktop¥CLangI2014>dir /B hello.c hello.exe hello.obj hello.tds C:¥Users¥kou¥Desktop¥CLangI2014>hello hello, world

ファイル一覧の表示

コンパイル

ファイル一覧の表示

作成した実行ファイルを実行

教科書 pp.36-42. 59

Page 60: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C コンパイラは何をしているのか?

• デバッグ情報付きコンパイルし逆アセンブル

• .rdata セクション部分 mintty + bash

$ gcc -g hello.c $ objdump -d -S -s a.exe a.exe: ファイル形式 pei-x86-64 ... セクション .rdata の内容: 100403000 63796767 636a2d31 342e646c 6c005f4a cyggcj-14.dll._J 100403010 765f5265 67697374 6572436c 61737365 v_RegisterClasse 100403020 73000000 00000000 00000000 00000000 s............... 100403030 68656c6c 6f2c2077 6f726c64 00000000 hello, world.... 100403040 4743433a 2028474e 55292034 2e382e31 GCC: (GNU) 4.8.1 ... セクション .text の逆アセンブル: ... 00000001004010d0 <main>: #include <stdio.h> 埋め込まれた文字データ 文字データの配置アドレス

文字データの16進表現

教科書 p.17. 60

Page 61: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C コンパイラは何をしているのか?

• .text セクション部分 セクション .text の逆アセンブル: ... 00000001004010d0 <main>: #include <stdio.h> main() { 1004010d0: 55 push %rbp 1004010d1: 48 89 e5 mov %rsp,%rbp 1004010d4: 48 83 ec 20 sub $0x20,%rsp 1004010d8: e8 73 00 00 00 callq 100401150 <__main> printf("hello, world¥n"); 1004010dd: 48 8d 0d 4c 1f 00 00 lea 0x1f4c(%rip),%rcx # 100403030 <.rdata> 1004010e4: e8 77 00 00 00 callq 100401160 <puts> } 1004010e9: 48 83 c4 20 add $0x20,%rsp 1004010ed: 5d pop %rbp 1004010ee: c3 retq 1004010ef: 90 nop ...

アセンブラコードを アセンブルして得られた マシン語のバイトコード

C言語を コンパイルして得られた アセンブラコード

配置アドレス

61

元々の C言語のコード

文字データ"hello, world¥n"の 配置アドレス(前項参照)

サブルーチン(printf)の 呼び出し

Page 62: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門(変数と定数)

62

Page 63: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

基礎知識

63

Page 64: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト編集系ソフトの種類

• テキストエディタ (メモ帳, 秀丸, etc,,,)

• 基本的にプレーンな文字情報のみ、装飾なし

• リッチテキストエディタ (ワードパッド, etc,,,)

• 字体、色、サイズ等の装飾が可能に

• ワードプロセッサ (Word, 一太郎, etc,,,)

• 更に高度な、文書作成支援機能

• DTPツール (InDesign, Publisher, etc,,,)

• 印刷用の版下作成、特に割付へ特化

64

Page 65: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プログラミング向け テキストエディタの機能

• 構文解析機能

• シンタックスハイライト機能

• 行番号表示機能

• 入力補完機能

• マクロ機能

• 正規表現対応の検索機能

• タグジャンプ機能

• 等々

65

Page 66: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキストエディタ

• 窓の杜 • オフィス / 文書作成 / テキストエディター • http://www.forest.impress.co.jp/library/nav/genre/offc/document_txteditor.html

• 学習・プログラミング / プログラミング / プログラム向けエディター • http://www.forest.impress.co.jp/library/nav/genre/stdy/program_progeditor.html

• Vector • Windows / 文書作成 / テキストエディタ • http://www.vector.co.jp/vpack/filearea/win/writing/edit/

66

Page 68: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

統合開発環境

• Microsoft Visual Studio

• http://www.visualstudio.com/ja-jp/

• Eclipse

• Pleiades - Eclipse プラグイン日本語化プラグイン

• http://mergedoc.sourceforge.jp/

• NetBeans

• https://ja.netbeans.org/

68

Page 69: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コメント

• プログラムとしては解釈されない

• 後で読む人用に注釈をしておく機能

• /* ~ */ の間がコメント

• // から行末までがコメント

教科書 p.46. 69

comment_test.c #include <stdio.h> main() { /* ここがコメント */ printf("hello, world¥n"); // ここもコメント }

1 2 3 4 5 6 7 8 9

緑の部分がコメントとして 扱われる

Page 70: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf 関数の初歩

• 括弧の中にカンマ「,」で区切って複数の引数(パラメータ)を与える。

• 1つ目の引数は書式

• 書式内の %d %f %s 等の箇所には2つ目以降の引数が順に埋め込まれる

70

printf("1 + 2 = %d¥n", 1 + 2);

1 + 2 = ¥n

ここには int 型の整数型データとして解釈した 2つ目の引数の値(上記の例では1+2の計算結果)が 符号付き10進数にして印字される

教科書 pp.61, 64-66, 98.

¥n は改行として機能する

%d は整数、 %f は実数、 %s は文字列の埋め込み用

Page 71: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 値を表示してみよう(1/2)

• printf の1つ目の引数に "%d¥n", "%f¥n", "%s¥n" を与え、2つ目の引数に、整数、実数、

文字列を与えて、それぞれの組み合わせで、どうなるか試してみよう。

71

printf_practice_11.c #include <stdio.h> void main() { printf("%d¥n", 123); }

1 2 3 4 5 6

コマンドプロンプト + Borland C++ >bcc32 printf_practice_11.c && printf_practice_11 Borland C++ 5.5.1 for Win32 Copyright (c) 1993, ... printf_practive_11.c: Turbo Incremental Link 5.00 Copyright (c) 1997, ... 123

mintty + bash + gcc $ gcc printf_practice_11.c && ./a 123

5行目を書き変えて 計9つのファイルを作りましょう。

Page 72: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 値を表示してみよう(2/2)

72

• 結果を調べて表にまとめてみよう。

• ファイル名は整理番号を用いて printf_practice_XY.c のように付けてください。

• 例えば※2の欄は printf_practice_32.c となります。

整理番号Y 1 2 3

整理番号X 第1引数\第2引数 123 123.456 "123.456"

1 "%d¥n" 123と表示

2 "%f¥n"

3 "%s¥n" ※2

Page 73: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

SI接頭辞

名前 記号 乗数

キロ(kilo) K 10001 =103

メガ(mega) M 10002=106

ギガ(giga) G 10003=109

テラ(tera) T 10004=1012

ペタ(peta) P 10005=1015

エクサ(exa) E 10006=1018

ゼタ(zetta) Z 10007=1021

ヨタ(yotta) Y 10008=1024

73

Page 74: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

2進接頭辞(IEC/IEEE)

名前 記号 乗数

キビ(kibi) Ki 10241=210

メビ(mebi) Mi 10242=220

ギビ(gibi) Gi 10243=230

テビ(tebi) Ti 10244=240

ペビ(pebi) Pi 10245=250

エクスビ(exbi) Ei 10246=260

ゼビ(zebi) Zi 10247=270

ヨビ(yobi) Yi 10248=280

74

Page 75: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

bit と byte

• b – bit

• 2進数 1 桁

• 通信速度や IC の容量表記等

• 例: • 100Mbps (100 Mega bits per seconds)

• B – Byte

• 8bit (半角英数1文字分に相当)

• 記憶メディアの容量表記等

• 例: • 32GB (32 Giga Bytes)

0

1

1bitの記憶素子には 2進数の1桁つまり 0 または 1 のみ 記憶できる

0 0 0 1 1 0 1 1

1bit毎では 単位が小さ過ぎて使い辛い 通常は 8桁を1まとめにして扱う

1bit

8bit = 1byte

8bit = 1byte は 28 = 256 通りの整数を表現可能 符号なし: 0~255 符号あり: −128~127

教科書 pp.50-55. 75

Page 76: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

16進数

2進数 10進数 16進数 2進数 10進数 16進数

0b0000 0 0x0 0b1000 8 0x8

0b0001 1 0x1 0b1001 9 0x9

0b0010 2 0x2 0b1010 10 0xa

0b0011 3 0x3 0b1011 11 0xb

0b0100 4 0x4 0b1100 12 0xc

0b0101 5 0x5 0b1101 13 0xd

0b0110 6 0x6 0b1110 14 0xe

0b0111 7 0x7 0b1111 15 0xf

2進数 4桁 → 16進数 1桁 2進数 8桁 → 16進数 2桁 2進数16桁 → 16進数 4桁 2進数32桁 → 16進数 8桁 2進数64桁 → 16進数16桁

2進数 4桁 → 16進数 1桁 に対応 2進数から変換するとキリが良い バイト単位のデータを表す際、読み易い 例: 0b0001001000110100 = 4660 = 0x1234

教科書 pp.50-55. 76

Page 77: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

8 bit 整数の N 進数の表現 2進数 符号なし10進数 符号あり10進数 16進数

0b00000000 0 0 0x00

0b00000001 1 1 0x01

0b00000010 2 2 0x02

0b00000011 3 3 0x03

: : : :

0b01111111 127 127 0x7f

0b10000000 128 -128 0x80

: : : :

0b11111100 252 -4 0xfc

0b11111101 253 -3 0xfd

0b11111110 254 -2 0xfe

0b11111111 255 -1 0xff

符号あり整数の場合は最上位ビットを符号ビットとして扱う(2の補数表現)

教科書 pp.50-55.

符号ありは ここで 正負が 入れ替わる

77

Page 78: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

16 bit 整数の N 進数の表現 2進数 符号なし10進数 符号あり10進数 16進数

0b0000000000000000 0 0 0x0000

0b0000000000000001 1 1 0x0001

0b0000000000000010 2 2 0x0002

0b0000000000000011 3 3 0x0003

: : : :

0b0111111111111111 32767 32767 0x7fff

0b1000000000000000 32768 -32768 0x8000

: : : :

0b1111111111111100 65532 -4 0xfffc

0b1111111111111101 65533 -3 0xfffd

0b1111111111111110 65534 -2 0xfffe

0b1111111111111111 65535 -1 0xffff

符号あり整数の場合は最上位ビットを符号ビットとして扱う(2の補数表現)

符号ありは ここで 正負が 入れ替わる

教科書 pp.50-55. 78

Page 79: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N bit 整数の最大値・最小値

Bit数 符号あり10進数最小値 符号あり10進数最大値 符号なし10進数最大値

8 -128 127 255

16 -32,768 32,767 65,535

32 -2,147,483,648 2,147,483,647 4,294,967,295

64 -9,223,372,036,854,775,808 9,223,372,036,854,775,807 18,446,744,073,709,551,615

𝑁 −2𝑁−1 2𝑁−1 − 1 2𝑁 − 1

79

Bit数 128

符号あり10進数最小値 170,141,183,460,469,231,731,687,303,715,884,105,727

符号あり10進数最大値 -170,141,183,460,469,231,731,687,303,715,884,105,728

符号なし10進数最大値 340,282,366,920,938,463,463,374,607,431,768,211,456

参考: 128bit の場合

Page 80: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

符号なし8bit整数の演算

• 整数オーバーフロー

11111111 = 255

+)00000001 = 1

100000000 = 0

• 整数アンダーフロー

100000000 = 0

-)00000001 = 1

11111111 = 255

有効桁の外に1が溢れた

有効桁外の外から1が溢れた

80

Page 81: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

符号あり8bit整数の演算

• 整数オーバーフロー

01111111 = 127

+)00000001 = 1

10000000 = -128

• 整数アンダーフロー

10000000 = -128

-)00000001 = 1

01111111 = 127

• 2の補数表現

100000000 = 0

-)00000001 = 1

11111111 = -1

11111111 = -1

+)00000001 = 1

100000000 = 0

有効桁の外から1を借りてくる

有効桁の外に1を捨てる

符号ビットに1が溢れた

符号ビットから1が溢れた

81

Page 82: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

RAM (Random Access Memory)

• コンピュータのメインメモリで利用されている

82

Page 83: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

メモリの構成

• 1byte単位でアドレスが振られている

• つまり各アドレスには1byteの値を格納出来る

0x00 0x00000000

0x00 0x00000001

0x00 0x00000002

0x00 0x00000003

0x00 0xffffffff

: :

: :

0x00 0x0000000000000000

0x00 0x0000000000000001

0x00 0x0000000000000002

0x00 0x0000000000000003

0x00 0xffffffffffffffff

: :

: :

32bitのOSは32bitのアドレス空間 最大232Bytes=4GiB

64bitのOSは64bitのアドレス空間 最大264Bytes=16EiB

アドレス 格納値 アドレス 格納値

教科書 pp.52-56. 83

Page 84: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

大きい値の扱い方

• 複数のアドレスをまとめて変数に割り当てる

0x00 0x~00

0x00 0x~01

0x00 0x~02

0x00 0x~03

: :

: :

0x00 0x~04

0x00 0x~05

0x00 0x~06

: :

: :

0x00 0x~07

0x00 0x~08

8bit 0x00 0x~00

0x00 0x~01

0x00 0x~02

0x00 0x~03

: :

: :

0x00 0x~04

0x00 0x~05

0x00 0x~06

: :

: :

0x00 0x~07

0x00 0x~08

16bit

84

Page 85: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

大きい値の扱い方

• 複数のアドレスをまとめて変数に割り当てる

0x00 0x~00

0x00 0x~01

0x00 0x~02

0x00 0x~03

: :

: :

0x00 0x~04

0x00 0x~05

0x00 0x~06

: :

: :

0x00 0x~07

0x00 0x~08

32bit

0x00 0x~00

0x00 0x~01

0x00 0x~02

0x00 0x~03

: :

: :

0x00 0x~04

0x00 0x~05

0x00 0x~06

: :

: :

0x00 0x~07

0x00 0x~08

64bit

85

Page 86: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の宣言、値の代入

• 変数は値を格納する箱のようなもの

int a; // (1) 変数の宣言 a = 10; // (2) 値の代入 // (3)

教科書 pp.59-61.

10

a

10

(1) (2)

a

?

a

?

(3)

int 型の変数を作り a という名前を付ける この時点では 中身は未定

変数 a に 10 を代入する

変数 a に 10 が 代入された状態に なっている

86

Page 87: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の宣言と初期化

• 宣言と同時に初期化することも出来る

a

10

int a = 10; // (1) 変数の宣言と初期化

(1)

int 型の変数を作り a という名前を付け 10 を代入する

教科書 pp.59-61. 87

Page 88: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数への値の代入

• 変数への代入は「=」を用います。C言語において「=」は「イコール」や「等号」ではなく、「代入」を意味する記号です。

• 代入は、右辺の計算結果を左辺の変数に格納します。(左辺には必ず単独の変数を書く)

a = 10; // (1) 値の代入 a = a + 1; // (2) 計算結果の代入

1

(2)

a

10

a

10

計算結果で左辺を 上書きする

まず右辺を 計算して

88

+

Page 89: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数

• 文法

データ型 変数名; // 変数の宣言 データ型 変数名=初期代入値; // 変数の宣言と初期化 データ型 変数名1, 変数名2; // 複数の変数の宣言 データ型 変数名1=初期代入値1, 変数名2=初期代入値2; // 複数の変数の宣言と初期化 変数名 = 値; // 値の代入

教科書 pp.59-61. 89

Page 90: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

リテラル

• ソースコードに直接記述された値

• 数値、文字列等

教科書 p.54. 90

wavetest.c int main(int argc, char *argv[]) { if (argc < 4) { printf("Usage: %s output_file micro_sec MIDI_note_No¥n¥n", argv[0]); return EXIT_FAILURE; } FILE *fp; if (fp = fopen(argv[1], "wb")) { fwrite_wav(44100, atoi(argv[2]), atoi(argv[3]), fp); fclose(fp); } return EXIT_SUCCESS; }

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

赤字で示したような部分が リテラルに当たる

Page 91: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

整数のデータ型

• signed char, unsigned char • 1バイト、局所的な文字セット内に1文字を保持し得る

• signed short, unsigned short • 少なくとも16ビット

• signed int, unsigned int • 少なくとも16ビット • 通常ホスト計算機の自然な整数サイズ • 現在は 32 or 64 ビットであることが多い

• signed long, unsigned long • 少なくとも32ビット

• 明確にビット数は定められていない • 割り当てビット数の大小関係は short <= int <=long

• 型の前に signed を付けると符号ありの型になる • 通常 signed は省略する(書かない)

• 型の前に unsigned を付けると符号なしの型になる

教科書 pp.53-55., [1] pp.44-45.

コンパイルする環境により 使える値の最大値・最小値が 異なる!

91

Page 92: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

整数のデータ型

サイズ 符号あり 符号なし 備考

1バイト signed char unsigned char 主に文字、文字列、バイナリデータ用

16bit以上 signed short unsigned short

16bit以上 signed int unsigned int 通常はこれを使う

32bit以上 signed long unsigned long

教科書 pp.53-55., [1] pp.44-45. 92

Page 93: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

整定数のリテラル

• 何も指定しないと int 型

• 末尾に接尾子(U, L)を付けると型指定される

int i = 1234; // int 型 long l = 1234L; // long 型 unsigned int ui = 1234U; // unsigned int 型 unsigned long ul = 1234UL; // unsigned long 型

93

Page 94: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語のN進数リテラル

• 0b~ 2進数リテラル(C++14の仕様*1)

• 0~ 8進数リテラル

• 0x~ 16進数リテラル

• *1: 少なくとも gcc4.3, Clang3.2 では実装済み

• 古いコンパイラでは2進数リテラルは使えない

• 例えばBorland C++ で 0b~ は使えない

int dec = 100; // 10進数の100 int bin = 0b100; // 2進数の100=10進数の 4 int oct = 0100; // 8進数の100=10進数の 64 int hex = 0x100; // 16進数の100=10進数の256

教科書 p.54. 94

2015-04-25追加

Page 95: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 値を表示してみよう(1/2)

• printf の1つ目の引数に "%d¥n" を与え、2つ目の引数に、前のページの dec, bin, oct, hex を与えてみよう。

• ファイルは dec, bin, oct, hex の4つ作る。

95

printf_practice_hex.c #include <stdio.h> void main() { int hex = 0x100; printf("%d¥n", hex); }

1 2 3 4 5 6 7

コマンドプロンプト + Borland C++ >bcc32 printf_practice_hex.c && printf_practice_hex Borland C++ 5.5.1 for Win32 Copyright (c) 1993, ... printf_practive_11.c: Turbo Incremental Link 5.00 Copyright (c) 1997, ... 256

mintty + bash + gcc $ gcc printf_practice_hex.c && ./a 256

5,6行目を書き変えて 計4つのファイルを作りましょう。

Page 96: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

浮動小数点数のデータ型

• float 単精度浮動小数点数

• double 倍精度浮動小数点数

• long double 拡張精度の浮動小数点数

教科書 pp.55-56. 96

Page 97: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

浮動小数点数とは

• IEEE754

• http://ja.wikipedia.org/wiki/IEEE_754

• 以下のようなに表現する方法

±仮数部 × 2指数部

ビット数 符号 指数部 仮数部

単精度 32bit 1bit 8bit 23bit

倍精度 64bit 1bit 11bit 53bit

四倍精度 128bit 1bit 15bit 112bit

指数部の値で 小数点の位置が移動するので 浮動小数点と呼ばれる

教科書 pp.55-56. 97

Page 98: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

浮動小数点数定数のリテラル

• 何も指定しないと double 型

• 末尾に接尾子(F, L)を付けると型指定される

• 1.234E5 のような書き方も出来る(指数表現)

• これは1.234 × 105を意味する

float f = 1234F; // float 型 double d = 1234; // double 型 long double ld = 1234L; // long double 型 double e = 1.234E5; // double 型の 123400

98

Page 99: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

固定小数点数

• 10進数8桁を4桁ずつに分けた例

• 2進数も8桁も同様に4桁ずつに分けてみる

備考 99

1 2 3 4 . 5 6 7 8

103 102 101 100 . 10−1 10−2 10−3 10−4 の桁

0 0 0 1 . 1 0 1 1

23 22 21 20 . 2−1 2−2 2−3 2−4 の桁

2015-04-25追加

0000.0000~9999.9999 まで表現可能

0b0000.0000~0b1111.1111 まで表現可能

Page 100: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

指数表示(浮動小数点数)

• 10進数8桁を4桁ずつに分けた例

• 2進数も8桁も同様に4桁ずつに分けてみる

備考 100

1 2 3 4 ×10^ 1 2 3 4

103 102 101 100 103 102 101 100 の桁

2015-04-25追加

0 0 0 1 ×2^ 0 0 0 1

23 22 21 20 23 22 21 20 の桁

0000×10^0000~9999×10^9999 まで表現可能

0b0000×2^0b0000~0b1111×2^0b1111 まで表現可能

Page 101: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ASCII文字コード表

0 1 2 3 4 5 6 7 8 9 A B C D E F 0 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI 1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC → ← ↑ ↓ 2 SP ! " # $ % & ' ( ) * + , - . / 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 4 @ A B C D E F G H I J K L M N O 5 P Q R S T U V W X Y Z [ ¥ ] ^ _ 6 ` a b c d e f g h i j k l m n o 7 p q r s t u v w x y z { | } ~ DEL 8 9 A B C D E F

上位4ビット

下位4ビット

赤字は制御コード

教科書 p.51.

http://ja.wikipedia.org/wiki/ASCII

101

Page 102: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

制御コード HEX Abbr ctrl eseq Name Hex Abbr ctrl eseq Name

0x00 NUL ^@ ¥0 Null 0x10 DLE ^P Data Link Escape

0x01 SOH ^A Start of Heading 0x11 DC1 ^Q Device Control 1

0x02 STX ^B Start of Text 0x12 DC2 ^R Device Control 2

0x03 ETX ^C End of Text 0x13 DC3 ^S Device Control 3

0x04 EOT ^D End of Transmission 0x14 DC4 ^T Device Control 4

0x05 ENQ ^E Enquiry 0x15 NAK ^U Negative Acknowledgement

0x06 ACK ^F Acknowledgement 0x16 SYN ^V Synchronous idle

0x07 BEL ^G ¥a Bell 0x17 ETB ^W End of Transmission Block

0x08 BS ^H ¥b Back Space 0x18 CAN ^X Cancel

0x09 HT ^I ¥t Horizontal Tab 0x19 EM ^Y End of Medium

0x0a LF ^J ¥n Line Feed 0x1a SUB ^Z Substitute

0x0b VT ^K ¥v Vertical Tab 0x1b ESC ^[ ¥e Escape

0x0c FF ^L ¥f Form Feed 0x1c FS ^¥ File Separator

0x0d CR ^M ¥r Carriage Return 0x1d GS ^] Group Separator

0x0e SO ^N Shift Out 0x1e RS ^^ Record Separator

0x0f SI ^O Shift In 0x1f US ^_ Unit Separator

0x20 SP Space 0x7f DEL ^? Delete

教科書 p.51. 102

Page 103: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

文字定数のリテラル

• 1文字を単一の引用符(')で囲む

• char型の値になる

char a = 'a'; //「a」の文字コード0x61 char lf = '¥012'; //改行の文字コード0x0aを8進数で char vt = '¥x0b'; //垂直タブの文字コード0x0bを16進数で char cr = '¥r'; //復帰の文字コード0x0dを //エスケープシーケ1ンスで

教科書 p.56. 103

単一の引用符(')は

↑Shift '

7 +

Page 104: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 値を表示してみよう3(1/2)

• printf_practice_hex.c を元にして以下の点を変更して動作を確認せよ。

• ファイル名をコピーして以下の4ファイルを通る。

• printf_practice_a.c

• printf_practice_lf.c

• printf_practice_vt.c

• printf_practice_cr.c

104 2015-04-25追加

Page 105: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 値を表示してみよう3(2/2)

• 5行目はファイル名と対応させて2ページ前のa, lf, vt, cr の宣言と初期化に書き換え。

• 6行目は %d を %x に書き換え。hex は、対応する a, lf, vt, cr に書き換え

105

printf_practice_a.c #include <stdio.h> void main() { char a = 'a'; printf("%x¥n", a); }

1 2 3 4 5 6 7

コマンドプロンプト + Borland C++ >bcc32 printf_practice_a.c && printf_practice_a Borland C++ 5.5.1 for Win32 Copyright (c) 1993, ... printf_practive_11.c: Turbo Incremental Link 5.00 Copyright (c) 1997, ... 61

mintty + bash + gcc $ gcc printf_practice_a.c && ./a 61

5,6行目の赤字部分を書き変え 計4つのファイルを作りましょう。

2015-04-25追加

Page 106: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

エスケープシーケンス

¥a 警告(ベル)文字

¥b バックスペース

¥f 改頁(フォームフィード)

¥n 改行

¥r 復帰

¥t 水平タブ

¥v 垂直タブ

¥¥ バックスラッシュ

¥? 疑問符

¥' 単一引用符

¥" 二重引用符

¥ooo 8進数 ooo (*1)

¥xhh 16進数 hh (*2)

教科書 p.56.

(*1) ooo は1桁ないし 3桁の8進数を取る

(*2) hh は1桁あるいは 2桁の16進数を取る

これらの表記は、 1文字(=1バイト)の値を表す。

106

Page 108: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

文字列定数のリテラル

• 0個以上の文字を二重引用符(")で囲む

• char型の配列になる(後述)

二重引用符(")は

↑Shift "

2 +

char emp[] = ""; // 空の文字列 char str[] = "I am a string"; // 文字列 char cat[] = "hello, " "world"; // "hello, world" と同じ // 連続した文字定数リテラルはコンパイル時に連結される

教科書 pp.44, 96-99. 108

Page 109: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

宿題

• 次回までに以下の事をやっておくこと。

• 教科書の第2章の終わりまで読み、指示された操作を試して動作を確認する。

• 不明な点、疑問点についてメモし、次回の授業に持参する。または、本講義の Moodle コース上にある第1週宿題用フォーラムに書き込んでおく。

109

Page 110: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第3週

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

情報処理言語Ⅰ(実習を含む。)

110

Page 111: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

先週の復習

リダイレクト

111

Page 112: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

出力のリダイレクト

• 書式: コマンド > ファイル

• コマンドの出力をファイルに繋ぐ

• コマンド実行時の出力をファイルに保存出来る。

• 例: 第1週の hello.c について

112

mintty + bash ./a > hello_result.txt

コマンドプロンプト hello > hello_result.txt

hello_result.txt hello, world

Page 113: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の表示

printf 関数

113

Page 114: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の表示

• printf 関数を使う

教科書 pp.61, 64-66, 98.

printftest.c #include <stdio.h> #include <stdlib.h> int main() { int i = 128; double d = 123e-3; char s[] = "hello, world"; printf("i: %d¥n", i); printf("d: %f¥n", d); printf("s: %s¥n", s); return EXIT_SUCCESS; }

mintty+bash+gcc $ gcc printftest.c && ./a i: 128 d: 0.123000 s: hello, world

いろんな値を表示できる。

114

1 2 3 4 5 6 7 8 9 10 11 12 13

Page 115: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf 関数

• int printf(const char *FORMAT, ...);

• 引数:

• FORMAT: 書式

• ...: 任意の数の引数

• 戻り値:

• 書き出された文字数。

• エラーの場合負の数。

教科書 pp.61, 64-66, 98.

参考: [1] pp.305-306.

115

Page 116: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf: 書式

• %~変換文字までをフィールドと呼ぶび、テンプレート(穴空き定規)ように扱われる

• フィールドは以下の要素から成る • %[フラグ][最小フィールド幅][.精度][長さ修飾子]変換文

字 printf("1 + 2 = %d¥n", 1 + 2);

1 + 2 = ¥n

ここに、 int型の整数型データとして解釈した 2つ目の引数の値(上記の例では1+2の計算結果)を 符号付き10進数にして印字する

教科書 pp.61, 64-66, 98.

参考: [1] pp.305-306.

116

Page 117: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf: フラグ

• -: 左揃えで印字

• +: 数を符号付きで印字

• スペース: 最初の文字が符号でない場合スペースを前に付ける

• 0: フィールド幅いっぱいに左側から0を詰める

• #: 別の出力形式を指定。

• o: 先頭の桁を0にする

• x: 0でない結果の先頭を0xにする

• e,f,g: 出力に必ず小数点を付ける

• g: 末尾の0を削除しない

教科書 pp.61, 64-66, 98.

参考: [1] pp.305-306.

117

Page 118: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf: 最小フィールド幅

• 変換された引数は少なくともこの幅になる。

• 必要ならもっと広い幅のフィールドに印字。

• 変換された引数がフィールド幅よりも短い場合padding(=詰め物)が行われる。

• paddingは通常はスペース。フラグに0が指定された場合は0が用いられる。

• *: 次の引数の値を用いる

教科書 pp.61, 64-66, 98.

参考: [1] pp.305-306.

118

Page 119: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf: .精度

• 「.」(ピリオド): フィールド幅と精度の分離子(separator)

• 文字列に対しては印字する最大文字数

• e,fの対しては小数点以下に印字すべき桁数

• gに対しては有効数字の桁数

• 整数に対しては印字すべき最小桁数(頭に0が付加される)

• *: 次の引数の値を用いる

教科書 pp.61, 64-66, 98.

参考: [1] pp.305-306.

119

Page 120: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf: 長さ修飾子

• h: short または float として扱う

• l: long として扱う

• L: long double として扱う

教科書 pp.61, 64-66, 98.

参考: [1] pp.305-306.

120

Page 121: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf: 変換文字

文字 変換後の引数の型

d, i int; 符号付き10進数

o int; 符号なし8進数

x, X int; 符号なし16進数

u int; 符号なし10進数

c int; unsigned char に変換された後の単一文字

s char *; 文字列を文字列終端('¥0')または指定された桁まで

f double; [-]mmm.dddddd 形の10進数。dの桁数は精度で指定

e, E double; [-]m.dddddde±xx型の10進数。dの桁数は精度で指定

g, G double; 指数が-4より小さいか精度以上の場合%e、それ以外は%f扱い

p void *; ポインタとして印字(処理系依存)

n int *; このprintfでここまでに書き出された文字数を引数に書き込む

% %を印字

参考: [1] pp.305-306.

教科書 pp.61, 64-66, 98. 121

Page 122: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf の詳細

• ここでは概略しか示せていないのと一部不正確な部分もあるので、詳細は bash から man コマンドを用いて以下の方法で確認すること

• 邦訳は以下のページ • http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/printf.3.html

mintty+bash man sprintf

122 教科書 pp.61, 64-66, 98.

mintty+bash man 3 printf

3 はマニュアルのセクション番号を意味する。 セクション 3 はサブルーチン (つまりライブラリ関数) 関連のマニュアル http://linuxjf.sourceforge.jp/JFdocs/Man-Page-2.html printf はセクション 1 にもあるので sprintf かセクション 3 の printf を引く必要がある。

2015-04-27 修正&追記

Page 123: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

printf のマニュアル導入

• printf のマニュアルが引けない場合、 以下のコマンドを mintty+bash から実行

123

cygwin-doc パッケージのインストール

mintty+bash apt-cyg install cygwin-doc

教科書 pp.61, 64-66, 98.

Page 124: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 円の面積を計算せよ(1)

• area_of_a_circle1.c をダウンロードして /*WYCH1*/ の部分を書き変えることで以下のプログラムを完成させなさい。/*WYCH2*/ /*WYCH3*/ の部分は次の演習で変更するので今はまだ書き変えない事。なお WYCH は Write Your Code Here を略している。 • double 型の変数 r に円の半径を代入する。 • 円の面積𝑆は公式𝑆 = 𝜋𝑟2を用いて計算し、結果は小数点以下2桁

まで出力する。出力には printf と "%f" を用いれば良いが、前述の精度を設定する必要がある。

• 円の面積を表示する前に、確認のため計算に用いる半径も表示する。

• r に代入する半径はソースコードにリテラル値として直接埋め込む。異なる半径面積を計算したい時は、ソースコードのリテラル値を書き変えてコンパイルし直すこととする。

• 半径を 1~10まで 1 刻みで増やして 計10 個の面積を計算せよ。

124

2015-04-27 追記

Page 125: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

マクロ

• preprocessor のキーワード置換機能

• 書式: #define マクロ名 置換内容

• 定数等に名前を付ける際に使う

125

macrotest1.c #include <stdio.h> #define MSG "world" void main() { printf("hello, %s¥n", MSG); }

教科書 p.68.

1 2 3 4 5 6 7 8

MSGはコンパイル前に "world"で置換される

2015-04-25修正 誤:area_of_a_circle1.c 正:macrotest1.c

Page 126: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

マクロ

• コンパイル時のオプション -D で外部から与えることも出来る。 macrotest2.c

#include <stdio.h> void main() { printf("hello, %s¥n", MSG); }

mintty+bash+gcc $ gcc -DMSG="¥"kou¥"" macrotest2.c && ./a hello, kou

126

1 2 3 4 5

コマンドプロンプト+Borland C++

>bcc32 -DMSG="¥"kou¥"" macrotest2.c && macrotest2 Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland macrotest.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland hello, kou

普通はこのままコンパイルしても MSGがないためエラーになる

2015-04-25修正 誤:extmacrotest2.c 正:macrotest2.c

Page 127: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

マクロ

• PI に関しては実は math.h で提供されている

127

mintty+bash $ grep M_PI /usr/include/math.h #define M_PI 3.14159265358979323846 #define M_PI_2 1.57079632679489661923 #define M_PI_4 0.78539816339744830962 #define M_TWOPI (M_PI * 2.0)

教科書 p.68.

Page 128: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

マクロ

• 先程の EXIT_SUCCESS や SCNd32 もマクロ

128

mintty+bash $ grep "#define.EXIT_" /usr/include/stdlib.h #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 $ grep SCNd32 /usr/include/inttypes.h #define SCNd32 "d"

それぞれの環境に 適切な数値や文字列等が設定されている

教科書 p.68.

Page 129: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルの包含

• preprocessor のファイル取り込み機能

• 別のファイルに記述されたプログラムやマクロ等を取り込む際に使う

• 書式: • #include <ファイル名>//システム提供ファイル

用 • /usr/include 等から探して取り込む

• #include "ファイル名"//ユーザー作成ファイル用 • 作業ディレクトリから探して取り込む

129 教科書 pp.203-206.

Page 130: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

grep コマンド

• grep [OPTIONS] PATTERN [FILE ...] • 検索文字列を含むファイルを検索する

• 引数 • PATTERN : 正規表現等による検索文字列 • FILE : 検索対象のファイルやディレクトリ

• OPTIONS • -R : ディレクトリ下のすべてのファイルを検索 • -n : 行番号を表示 • -A NUM : マッチ位置の後NUM行も表示 • -B NUM : マッチ位置の前NUM行も表示 • -C NUM : マッチ位置の前後NUM行も表示

• マニュアル邦訳 • http://linuxjm.sourceforge.jp/html/GNU_grep/man1/grep.1.html

備考: UNIX コマンド 130

Page 131: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

正規表現

表記 意味

c 文字c

¥c 文字¥c

. 任意の一文字

[...] []内の任意の一文字

[^...] []内に含まれない任意の一文字

* 直前のパターンが0回以上反復

+ 直前のパターンが1回以上反復

? 直線のパターンが0または1回出現

| 前後の正規表現の何れか

(...) ()内の正規表現をグループ化

^ 行頭にマッチ

$ 行末にマッチ

備考: UNIX コマンド 131

Page 132: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 円の面積を計算せよ(2)

• 先程完成させた area_of_a_circle1.c をコピーして area_of_a_circle2.c を作成し /*WYCH1*/ /*WYCH2*/ の部分を書き変えることで以下のプログラムを完成させなさい。 • r に代入する半径としてマクロ R を代入することで、異

なる半径面積を計算したい時は、コンパイル時に -D オプションを用いて 「-DR=1」 のよう外部から値を与えることで、ソースコードを変更なしに、コンパイルし直すだけで済むように変更せよ。

• 𝜋の値はリテラル値を直接書き込むのではなく math.h で定義されたマクロ M_PI を用いるように変更せよ。

• 半径を 1~10まで 1 刻みで増やして 計10 個の面積を計算せよ。

132

Page 133: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fprintf 関数

• int fprintf(FILE *fp, const char *FORMAT, ...);

• printfの結果をfpへ書き出す

• 引数: • fp: FILE 構造体へのポインタ

• FORMAT: 書式

• ...: 任意の数の引数

• 戻り値: • 書き出された文字数

• エラーの場合負の数

教科書 pp.61, 64-66, 98, 300.

参考: [1] pp.305-306.

133

Page 134: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準入出力と標準エラー出力

• 以下の入出力が利用できる • stdin : standard input : 標準入力

• stdout: standard output : 標準出力

• stderr: standard error output: 標準エラー出力

• scanf や getchar 等は stdin から入力している

• printf や putchar 等は stdout へ出力している

• stdin, stdout はパイプやリダイレクトの対象だが stderr は標準では対象外(指定すれば対象にすることも可能)

[1] pp.196, 199, 218. 134

Page 135: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準入出力と標準エラー出力

• パイプやリダイレクトで処理されたくない内容は stderr へ出力すると良い

• fprintf を使うと、出力先を変更出来る

[1] pp.196, 199, 218. 135

stdiotest.c printf("output to stdout with printf¥n"); fprintf(stdout, "output to stdout with fprintf¥n"); fprintf(stderr, "output to stderr with fprintf¥n"); mintty + bash

$ gcc stdiotest.c $ ./a > redirect.txt output to stderr with fprintf $ cat redirect.txt output to stdout with printf output to stdout with fprintf

6 7 8

← 標準出力(stdout)を redirect.txt へリダイレクト ← fprintf で明示的に stderr へ出力した結果(*1) ← redirect.txtに出力された内容を表示 ← printf で暗黙的に stdout へ出力した結果 ← fprintf で明示的に stdout へ出力した結果

以下の例では(*1)がファイルへ出力されず 画面に出力されている事が確認出来る。

Page 136: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準入出力と標準エラー出力

• stdin,stdout,stderrはstdio.hで定義されている

• stdio.h は standard input / output header

[1] pp.196, 199, 218. 136

Page 137: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の読み込み

scanf 関数

137

Page 138: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の読み込み

• scanf関数を使う

教科書 pp.80-83, 254.

mintty+bash+gcc

scanftest.c int i; double d; char s[16]; fprintf(stderr, "i = ?¥b"); scanf("%d", &i); fprintf(stderr, "d = ?¥b"); scanf("%lf", &d); fprintf(stderr, "s = ?¥b"); scanf("%s", s); printf("i: %d¥n", i); printf("d: %f¥n", d); printf("s: %s¥n", s);

$ gcc scanftest.c && ./a i = 1234 d = 1234e-5 s = hello, world i: 1234 d: 0.012340 s: hello,

キーボードから入力した値を 変数に保存して利用出来る

138

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Page 139: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf 関数

• int scanf(const char *FORMAT, ...);

• 引数:

• FORMAT: 書式

• ...: 任意の数の引数 値を格納する変数へのポインタ

• 戻り値:

• 変換され代入された入力項目の数。

• ファイル終端またはエラーの場合EOF。

教科書 pp.80-83, 254.

参考: [1] pp.307-309.

139

Page 140: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf: 書式

• スペース、タブ: 無視される

• (%でない)普通の文字: 入力の次の空白でない文字とマッチ

• 変換仕様: • %[*][最大フィールド幅][ターゲット幅]変換文字

int a; scanf("%d", &a);

教科書 pp.80-83, 254.

参考: [1] pp.250, 307-309.

140

入力文字列を10進数として扱い int型の整数型変数へ代入

スカラ変数の前には & を付ける 配列変数、ポインタ変数には不要

&: アドレス演算子 変数へのポインタを得る

Page 141: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf: 変換仕様

• *: 入力フィールドはスキップされる 代入抑止

• 最大フィールド幅: 読み込む最大文字数

• ターゲット幅:

• h: int を short に

• l: int を long に、float を double に

• L: float を long doubleに

教科書 pp.80-83, 254.

参考: [1] pp.307-309.

141

Page 142: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf: 変換文字

文字 入力データ; 引数の型

d 10進数; int *

i 整数; int * (頭に0,0xが付くと8,16進数とみなす)

o 8進数; int *

u 符号なし10進数; unsigned int *

x 16進数; int *

c 文字; char * (末尾に'¥0'を付加しない)

s 非空白文字の文字列; char * (末尾に'¥0'を付加)

e,f,g 浮動小数点数; float *

p printf("%p") で印字されるポインタ値; void *

n これまでに読み込まれた文字数; int *

[...] [...]+; char * (末尾に'¥0'を付加)

[^...] [^...]+; char * (末尾に'¥0'を付加)

% %; 参考: [1] pp.307-309.

教科書 pp.80-83, 254. 142

Page 143: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf の詳細

• ここでは概略しか示せていないのと一部不正確な部分もあるので、詳細は bash から man コマンドを用いて以下の方法で確認すること

• 邦訳は以下のページ • http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/scanf.3.html

教科書 pp.80-83, 254. 143

mintty+bash man scanf

Page 144: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf の引数とポインタ

• 値の代入するには変数のアドレスが必要

0x?? 0x~00

0x?? 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

32bit

int a; scanf("%d", &a);

a

0x????????

144

&a

&: アドレス演算子 変数が配置されているメモリ上のアドレスが得られる このアドレスのことをC言語ではポインタと呼ぶ

教科書 pp.80-83, 254.

scanf に値の格納先の アドレスを渡す

Page 145: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

scanf: C99 の stdint.h の場合

参考: [1] pp.307-309.

補足 145

• #include<inttypes.h> してSCN~を使う

• "%hd" → "%"SCNd16

• "%d" → "%"SCNd32

• "%u" → "%"SCNu32

実装依存なので 欲しい桁数が扱えないかも?

使う bit 数を確実に保証出来る

Page 146: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

buffer overflow の脆弱性

• 確保した配列よりも長い文字列を入力

備考 146

mintty+bash+gcc $ gcc scanftest.c && ./a i = 1234 d = 1234e-5 s = 0123456789abcdefg@@@@@@@@@@@@@@@@ i: 1077952576 d: 32.501961 s: 0123456789abcdefg@@@@@@@@@@@@@@@@

他の変数の領域を 侵食してしまう

Page 147: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

buffer overflow の脆弱性の仕組み

• メモリ上の変数の割り当て 0x?? 0x~00

0x?? 0x~0f

0x?? 0x~10

: :

: :

0x?? 0x~17

0x?? 0x~1c

char s[16];

147

0x?? 0x~1f

: :

: :

: :

: :

double d;

int i;

確保したサイズ以上の データを書き込むと 他の変数のデータを 上書きしてしまう。

備考

Page 148: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

buffer overflow の脆弱性の対策

• 最大フィールド幅を明記する!

• "%s" → "%15s"

148

終端文字列'¥0'も格納する必要があるため、 最大フィールド幅は 確保したバイト数 -1 以下にする必要がある。 char s[16]; なら最大15文字まで

備考

Page 149: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 円の面積を計算せよ(3)

• 先程完成させた area_of_a_circle2.c をコピーして area_of_a_circle3.c を作成し /*WYCH1*/ /*WYCH2*/ /*WYCH3*/ の部分を書き変えることで以下のプログラムを完成させなさい。 • r に代入する半径を実行時にキーボードから入力する

ことで、コンパイルし直さなくても半径を変更出来るように変更せよ。scanf と "%lf" を利用すれば良い。

• r の入力を求める際は "r = ?¥b" を標準エラー出力に予め表示せよ。なお ¥b はバックスペースを表すエスケープシーケンスである。

• 半径を 1~10まで 1 刻みで増やして 計10 個の面積を計算せよ。

149

Page 150: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演算子

150

Page 151: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

sizeof 演算子

• コンパイル時に変数やデータ型の割り当てバイト数を求める演算子

• sizeof オブジェクト

• sizeof(型名)

教科書 p.78, 84, 195. 151

Page 152: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

sizeof 演算子の例1

• 例)各データ型の割り当てバイト数

教科書 p.78, 84, 195.

sizeof_ex1.c printf("sizeof(char) : %2d¥n", sizeof(char)); printf("sizeof(wchar_t) : %2d¥n", sizeof(wchar_t)); printf("sizeof(short) : %2d¥n", sizeof(short)); printf("sizeof(int) : %2d¥n", sizeof(int)); printf("sizeof(long) : %2d¥n", sizeof(long)); #ifndef __BORLANDC__ printf("sizeof(long long) : %2d¥n", sizeof(long long)); #endif printf("sizeof(float) : %2d¥n", sizeof(float)); printf("sizeof(double) : %2d¥n", sizeof(double)); printf("sizeof(long double): %2d¥n", sizeof(long double));

152

7 8 9 10 11 12 13 14 15 16 17

Page 153: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各データ型のサイズ(1/5)

• sizeof_ex1.c による比較

32 bit 版 Cygwin + GNU C

64 bit 版 Cygwin + GNU C

$ gcc sizeof_ex1.c && ./a sizeof(char) : 1 sizeof(wchar_t) : 2 sizeof(short) : 2 sizeof(int) : 4 sizeof(long) : 4 sizeof(long long) : 8 sizeof(float) : 4 sizeof(double) : 8 sizeof(long double) : 12

$ gcc sizeof_ex1.c && ./a sizeof(char) : 1 sizeof(wchar_t) : 2 sizeof(short) : 2 sizeof(int) : 4 sizeof(long) : 8 sizeof(long long) : 8 sizeof(float) : 4 sizeof(double) : 8 sizeof(long double): 16

コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

153

Page 154: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各データ型のサイズ(2/5)

• sizeof_ex1.c による比較

Borland C++ 5.5

>bcc32 sizeof_ex1.c && sizeof_ex1 Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland sizeof_ex1.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland sizeof(char) : 1 sizeof(wchar_t) : 2 sizeof(short) : 2 sizeof(int) : 4 sizeof(long) : 4 sizeof(float) : 4 sizeof(double) : 8 sizeof(long double): 10

コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

154

Page 155: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各データ型のサイズ(3/5)

• sizeof_ex1.c による比較

Visual Studio 2013 Express Desktop Windows 32 bit 版 >cl sizeof_ex1.c && sizeof_ex1 Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. sizeof_ex1.c Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:sizeof_ex1.exe sizeof_ex1.obj sizeof(char) : 1 sizeof(wchar_t) : 2 sizeof(short) : 2 sizeof(int) : 4 sizeof(long) : 4 sizeof(long long) : 8 sizeof(float) : 4 sizeof(double) : 8 sizeof(long double): 8

コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

155

Page 156: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各データ型のサイズ(4/5)

• sizeof_ex1.c による比較

Visual Studio 2013 Express Desktop Windows 64 bit 版 >cl sizeof_ex1.c && sizeof_ex1 Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved. sizeof_ex1.c Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:sizeof_ex1.exe sizeof_ex1.obj sizeof(char) : 1 sizeof(wchar_t) : 2 sizeof(short) : 2 sizeof(int) : 4 sizeof(long) : 4 sizeof(long long) : 8 sizeof(float) : 4 sizeof(double) : 8 sizeof(long double): 8

コンパイルする環境により 割り当てビット数や 最大値と最小値が異なる可能性がある

156

Page 157: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各データ型のサイズ(5/5)

gcc 32bit gcc 64bit bcc32 cl 32bit cl 64bit

char 1 1 1 1 1

wchar_t 2 2 2 2 2

shor 2 2 2 2 2

int 4 4 4 4 4

long 4 8 4 4 4

long long 8 8 - 8 8

float 4 4 4 4 4

double 8 8 8 8 8

long double 12 16 10 8 8

157

Page 158: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

データ型のサイズ C99における解決方法

• stdint.h ヘッダファイルを使う

#include <stdint.h> // ... int8_t i8; // 符号付き 8bit整数 uint8_t ui8; // 符号なし 8bit整数 int16_t i16; // 符号付き16bit整数 uint16_t ui16; // 符号なし16bit整数 int32_t i32; // 符号付き32bit整数 uint32_t ui32; // 符号なし32bit整数 int64_t i64; // 符号付き64bit整数 uint64_t ui64; // 符号なし64bit整数

第1週のサンプルプログラム • wavtest.c • bmptest.c でも使っています。

注: Boarland C++ 5.5 は C99 非対応なので stdint.h が使えない。

補足 158

Page 159: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

sizeof 演算子の例2

• 例)変数やリテラルの割り当てバイト数

教科書 p.78, 84, 195.

mintty+bash+gcc $ gcc sizeof_ex2.c && ./a sizeof(i) : 4 sizeof(d) : 8 sizeof(s) : 13 sizeof( 1 ): 4 sizeof( 1.): 8 sizeof("1"): 2

sizeof_ex2.c int i = 128; double d = 123e-3; char s[] = "hello, world"; printf("sizeof(i) : %2d¥n", sizeof(i)); printf("sizeof(d) : %2d¥n", sizeof(d)); printf("sizeof(s) : %2d¥n", sizeof(s)); printf("sizeof( 1 ): %2d¥n", sizeof( 1 )); printf("sizeof( 1.): %2d¥n", sizeof( 1.)); printf("sizeof(¥"1¥"): %2d¥n", sizeof("1"));

159

6 7 8 9 10 11 12 13 14

Page 160: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

sizeof 演算子の例3

• 例)配列変数の割り当てバイト数

教科書 p.78, 84, 195.

sizeof_ex3.c int a[10]; printf("sizeof(int) : %2d¥n", sizeof(int)); printf("sizeof(a) : %2d¥n", sizeof(a)); printf("sizeof(a[0]) : %2d¥n", sizeof(a[0])); printf("sizeof(a)/sizeof(a[0]) : %2d¥n", sizeof(a)/sizeof(a[0]));

160

mintty+bash+gcc $ gcc sizeof_ex3.c && ./a sizeof(int) : 4 sizeof(a) : 40 sizeof(a[0]) : 4 sizeof(a)/sizeof(a[0]) : 10

7 8 9 10 11 12 13

← int型の割り当てバイト数 ← 配列変数a の割り当てバイト数 ← 変数a[0]の割り当てバイト数 ← 配列変数a の要素数

Page 161: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

型変換(cast)演算子

• (変換したい型) 値

教科書 p.70, 84.

casttest.c int a = 1; int b = 2; double x = a / b; double y = a / (double) b; printf("%f¥n", x); printf("%f¥n", y);

mintty+bash+gcc $ gcc casttest.c && ./a 0.000000 0.500000

整数同士の割り算だと 1/2 が 0 になっている。

int型の b の値を double 型に変換

161

cast 演算子 (type) 値 type: 任意のデータ型

6 7 8 9

10 11 12

Page 162: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

暗黙の算術変換 (概略)

• 二項演算子の両辺が異なる型の場合 以下の手順で型を変換(符号ありの場合)

• 基本的には大きい方へと型をそろえて行く処理

1. 片方がlong double: 他方をlong doubleに変換

2. 片方がdouble: 他方を doubleに変換

3. 片方がfloat: 他方をfloatに変換

4. char, shortをintに変換

5. 片方がlong: 他方をlongに変換

[1] pp.52-57, 240-244. 162

Page 163: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

算術演算子

算術演算子 演算子の機能 書式

単項演算子 + 被演算数の値 + expr

- 被演算数の符号反転 - expr

二項演算子 + 加算 expr1 + expr2

- 減算 expr1 – expr2

* 乗算 expr1 * expr2

/ 除算 expr1 / expr2

% 剰余算 expr1 % expr2

163 教科書 p.69, 84.

Page 164: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

代入演算子、複合代入演算子

代入演算子 演算子の機能 書式

代入演算子 = 代入 var = expr

複合代入演算子

+= 加算 var += expr

-= 減算 var –= expr

*= 乗算 var *= expr

/= 除算 var /= expr

%= 剰余算 var %= expr

&= ビット毎のAND var &= expr

^= ビット毎のXOR var ^= expr

|= ビット毎のOR var |= expr

<<= 左シフト var <<= expr

>>= 右シフト var >>= expr

164 教科書 pp.75-79, 84.

複合代入演算子はvar=var+exprのような演算と代入を同時に行う

Page 165: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

bit演算子

算術演算子 演算子の機能

単項演算子 ~ 1の補数 ~ expr

二項演算子 << 左シフト expr1 << expr2

>> 右シフト expr1 >> expr2

& ビット毎のAND expr1 & expr2

^ ビット毎のXOR expr1 ^ expr2

| ビット毎のOR expr1 | expr2

165 教科書 pp.78-79, 84.

Page 166: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 利用可能 bit の外側には 0が充填される

bitシフト(論理シフト) (符号なし整数の場合)

166

0 0 1 1 1 0 0 1 0 0

1 0 0 1 0 0 0 0

<< 2

0 0 1 1 1 0 0 1 0 0

0 0 1 1 1 0 0 1

>> 2

0xe8

0x90

0xe8

0x3a

論理シフトであれば 左シフト、右シフト共に 符号付き、符号なしで結果は共通

教科書 pp.78-79, 84.

Page 167: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 最上位ビットより上位は符号拡張される

• 符号ビットが0なら0、1なら1が充填される

bitシフト(算術シフト) (符号付き整数の場合?)

167

1 1 1 1 1 0 0 1 0 0

1 1 1 1 1 0 0 1

>> 2

0 0 0 0 0 1 1 0 1 1

0 0 0 0 0 1 1 0

>> 2 0x1b

0x06

0xe8

0xfa

右シフトは最上位ビットの値により 符号付き、符号なしで結果が異なる

環境依存なので、環境によっては 論理シフトになる可能性も 考慮しておくこと。

左シフトは 符号付き、符号なしで結果は共通

教科書 pp.78-79, 84.

Page 168: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 実際の環境はどうなっているのか?

右シフト

168 教科書 pp.78-79, 84.

bitshifttest.c unsigned int uc = 0xe8000000; // == 0b11101000... signed int sc = 0xe8000000; // == 0b11101000... uc >>= 2 + 8 * 3; sc >>= 2 + 8 * 3; printf("%02x¥n", uc & 0xff); // 0b00111010 == 0x3a printf("%02x¥n", sc & 0xff); // 0b11111010 == 0xfa ?

6 7 8 9 10 11 12 13

2015-05-15修正 誤:0b11100100 正:0b11101000

2015-05-15修正 誤:0b00111001 正:0b00111010

2015-05-15修正 誤:0b11111001 正:0b11111010

Page 169: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 算術シフトになっている環境が多い?

右シフト

169 教科書 pp.78-79, 84.

64bit 版 cygwin + GNU C 4.8.2

Borland C++ 5.5

Visual Studio 2013 Express Desktop Windows 64bit 版

$ gcc bitshifttest.c && ./a 3a fa

>bcc32 bitshifttest.c && bitshifttest ... 3a fa

>cl bitshifttest.c && bitshifttest ... 3a fa

Page 170: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

論理演算

X Y X AND Y X OR Y X XOR Y NOT X

0 0 0 0 0 1

0 1 0 1 1 1

1 0 0 1 1 0

1 1 1 1 0 0

170

論理演算子 ビット毎の論理演算子 意味 英語表記

&& & 論理積 AND

|| | 論理和 OR

^ 排他的論理和 XOR (exclusive or)

! ~ 論理反転 NOT

教科書 pp.78-79, 84.

論理演算子による演算結果は真(=1)または偽(=0)となる

Page 171: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語の論理値(真偽値)

• 数値を論理値として用いている

• 論理演算とビット毎の論理演算に注意

171

論理値 数値 真偽値判定時

偽 0 0のみが偽として扱われる

真 1 0以外はすべて真として扱われる

logictest.c int x = 1; // = 0b01 int y = 2; // = 0b10 printf("x && y = %d¥n", x && y); printf("x || y = %d¥n", x || y); printf("x & y = %d¥n", x & y); printf("x | y = %d¥n", x | y);

mintty+bash+gcc $ gcc logictest.c && ./a x && y = 1 x || y = 1 x & y = 0 x | y = 3

教科書 pp.78-79, 84.

6 7 8 9 10 11

Page 172: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

論理演算とビット毎の論理演算

• 論理演算を行う単位が違う

172

1 1 1 0 0 1 0 0

論理演算子

0 0 0 0 0 0 0 1

1 1 1 0 0 1 0 0

ビット毎の論理演算子

0 0 0 0 0 1 0 0

論理演算では 全体を1つの論理値として扱う

ビット毎の論理演算では 各ビットを個別に扱う

教科書 pp.78-79, 84.

Page 173: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

bit 毎の AND による bit mask

• bit毎にANDを取った結果が得られる

173

1 1 1 0 0 1 0 0

0 0 0 0

0 0 0 0 0 1 0 0

& 0 0 0 0 1 1 1 1

X & Y で 右辺の値をマスクとして用いた場合 0: 0でクリア 1: 元の値をそのまま通過

教科書 pp.78-79., p.84.

Page 174: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

bit 毎の OR による bit mask

• bit毎にORを取った結果が得られる

174

1 1 1 0 0 1 0 0

1 1 1 1

1 1 1 1 0 1 0 0

| 1 1 1 1 0 0 0 0

X | Y で 右辺の値をマスクとして用いた場合 0: 元の値をそのまま通過 1: 1でクリア

教科書 pp.78-79., p.84.

Page 175: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

bit 毎の XOR による bit 反転

• bit毎にXORを取った結果が得られる

175

1 1 1 0 0 1 0 0

@ @ @ @

0 0 0 1 0 1 0 0

^ 1 1 1 1 0 0 0 0

X ^ Y で 右辺の値をマスクとして用いた場合 0: 元の値をそのまま通過 1: bit を 0⇔1 反転

同じ値で再度 XOR を取ると元に戻るので 簡易暗号的な使い方も出来る

教科書 pp.78-79., p.84.

Page 176: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1の補数演算子

• 要は単なるビット毎の論理反転

176

1 1 1 0 0 1 0 0

ビット毎の論理反転

0 0 0 1 1 0 1 1

教科書 pp.78-79., p.84.

~

Page 177: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

補数とは

• 基数𝑏(𝑏進数) 𝑛桁で表現可能な整数𝑎に対し

• 𝑏𝑛 − 𝑎 : 基数(𝑏)の補数

• 𝑏𝑛 − 𝑎 − 1 : 減基数(𝑏 − 1)の補数

• 例: 2進数8桁で表す1について

• 2の補数

• 0b100000000 – 0b00000001 = 0b11111111

• 1の補数(単なるビット毎の論理反転)

• 0b100000000 – 0b00000001 - 1 = 0b11111110

177

Page 178: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

インクレメント、デクレメントの演算子

算術演算子 演算子の機能

前置演算子 ++ インクレメント ++expr

-- デクレメント --expr

後置演算子 ++ インクレメント expr++

-- デクレメント expr--

178

前置演算子は演算後に値を取り出す。 後置演算子は演算前に値を取り出す。

incrtest.c int i = 5; printf("%d¥n", ++i); printf("%d¥n", --i); printf("%d¥n", i++); printf("%d¥n", i--);

mintty+bash+gcc $ gcc incrtest.c && ./a 6 5 5 6

教科書 pp.73-74., p.84.

6 7 8 9 10

Page 179: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

比較演算子 (関係演算子、等値演算子) 演算子 比較の意味

関係演算子 < 左辺が小 expr1 < expr2

<= 左辺が小または等しい expr1 <= expr2

> 左辺が大 expr1 > expr2

>= 左辺が大または等しい expr1 >= expr2

等値演算子 == 等しい expr1 == expr2

!= 等しくない expr1 != expr2

179 教科書 pp.117-118, 147.

演算結果は真(=1)または偽(=0)となる

Page 180: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ演算子

• アドレス演算子

• 書式 : &オブジェクト

• オブジェクトの配置されたアドレスを得る。

• 間接演算子

• 書式 : *ポインタ

• ポインタが指すアドレスに配置されたオブジェクトを得る。

180 教科書 pp.213-218.

Page 181: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 書式:

• 条件式 ? 式1 : 式2

条件演算子 三項演算子(?:)

181 [1] pp.63-66, 256-257.

条件式 真 偽

式1 式2

condexprtest.c #include <stdio.h> void main() { int i; fprintf(stderr, "i = ?¥b"); scanf("%d", &i); printf("%s¥n", i ? "not zero" : "zero"); }

1 2 3 4 5 6 7 8 9

mintty+bash+gcc $ gcc condexprtest.c && ./a i = 1 not zero $ ./a i = 0 zero

2015-05-01追加修正

Page 182: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演算子の優先度

演算子 結合規則 備考

( ) [ ] -> . 左から右→

! ~ ++ -- + - * & (type) sizeof 右から左← 単項演算子

* / % 左から右→ 二項演算子

+ - 左から右→ 二項演算子

<< >> 左から右→ bitシフト

< <= > >= 左から右→ 関係演算子

== != 左から右→ 等値演算子

& 左から右→ bit毎のAND

^ 左から右→ bit毎のXOR

| 左から右→ bit毎のOR

&& 左から右→ 論理演算子(AND)

|| 左から右→ 論理演算子(OR)

?: 右から左← 三項演算子

= += -= *= /= %= &= ^= |= <<= >>= 右から左← 代入演算子

, 左から右→

[1] p.65. より

優先度

182

Page 183: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

183

Page 184: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 同じ変数名で複数の要素を管理する

char a[10]; // 要素数10のchar型変数の宣言

教科書 pp.85-108.

a[0]

?

a[1]

?

a[2]

?

a[3]

?

a[9]

?

...

要素数10の添え字付き変数

初期値式が与えられなかった場合、値は不定

[1] pp.103-104., p.273.

184

Page 185: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 配列変数の要素への代入

char a[10]; // 要素数10のchar型変数の宣言 a[0] = 'a'; // 0番目の要素へ代入

教科書 pp.85-108.

a[0]

'a'

a[1]

?

a[2]

?

a[3]

?

a[9]

?

...

要素数10の添え字付き変数

初期値式が与えられなかったので、値は不定 宣言後の代入

[1] pp.103-104., p.273.

185

Page 186: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 添え字は値が取れれば変数や数式でも良い

int i = 1; char a[10]; // 要素数10のchar型変数の宣言 a[i + 1] = 'a'; // 2番目の要素へ代入

教科書 pp.85-108.

a[0]

?

a[1]

?

a[2]

'a'

a[3]

?

a[9]

?

...

要素数10の添え字付き変数 [1] pp.103-104., p.273.

186

Page 187: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 確保した領域外はアクセスは禁止

char a[10]; // 要素数10のchar型変数の宣言 short b = 0x1234; a[10] = 'a';// 宣言された領域外へのアクセス

教科書 pp.85-108.

a[0]

?

a[1]

?

a[2]

?

a[3]

?

a[9]

?

...

要素数10の添え字付き変数 [1] pp.103-104., p.273.

187

b

0x1234

a[10]

'a'

他の変数が使っていたらその値を壊してしまう

ここに書き込むと何が起こるか分からない

Page 188: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 初期値式による配列変数の初期化

char a[10] = {'a', 'b'}; //初期値式付きの //要素数10のchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

a[2]

0

a[3]

0

a[9]

0

...

要素数10の添え字付き変数

初期値式が要素数より少ない場合、残りは0で初期化 初期値式による初期化

[1] pp.103-104., p.273.

188

Page 189: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 初期値式による配列変数の初期化

char a[] = {'a', 'b'}; //初期値式付きで //要素数を省略したchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

初期値式の要素数分確保される

初期値式による初期化

[1] pp.103-104., p.273.

189

Page 190: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 文字列による初期化(要素数指定)

char a[10] = "ab"; //文字列による初期値付きの //要素数10のchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

a[2]

0

a[3]

0

a[9]

0

...

要素数10の添え字付き変数

初期値式が要素数より少ない場合、残りは0で初期化 文字列と文字列終端の'¥0'

[1] pp.103-104., p.273.

190

Page 191: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 文字列による初期化(要素数自動決定)

char a[] = "ab";//文字列による初期値付きで //要素数を省略したchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

a[2]

0

文字列の文字数+文字列終端'¥0'の1文字分の要素

文字列と文字列終端の'¥0'

[1] pp.103-104., p.273.

191

Page 192: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の初期化

• 明示的な初期化がない場合

• 外的変数、静的変数→0

• 自動変数、レジスタ変数→不定

• 初期化する場合

• 外的変数、静的変数←定数式でのみ初期化可

• コンパイル時に1度だけ初期化される

• 自動変数、レジスタ変数←任意の式で初期化可

• 実行時にブロック毎に初期化される

192

[1] pp.103-104., p.273.

Page 193: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数の初期化

• 要素数を与えない場合

• 初期値式の数で配列のサイズが決まる

• 要素数を与えた場合

• 初期値式を与えない場合

• 値は不定

• 初期値式を与える場合

• 要素数を超えるとエラー

• 要素数に足りない部分は0で初期化される

193

[1] pp.103-104., p.273.

Page 194: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

制御構造

条件分岐と繰り返し

194

Page 195: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐

if 文と switch 文

195

Page 196: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐 (if 文)

• 真偽値による場合分け

196

if (条件式) { // 条件式が真の場合の処理1 }

条件式

処理1

真 偽

教科書 pp.130-133.

Page 197: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐 (if, else 文)

• 真偽値による場合分け

197

if (条件式) { // 条件式が真の場合の処理1 } else { // 条件式が偽の場合の処理2 }

条件式

処理1 処理2

真 偽

教科書 pp.130-133.

Page 198: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

入れ子の条件分岐 (if, else 文)

• 真偽値による場合分け

198

if (条件式1) { // 条件式1が真の場合の処理1 } else { if (条件式2) { // 条件式1が偽かつ // 条件式2が真の場合の処理2 } else { // 条件式1が偽かつ // 条件式2が偽の場合の処理3 } }

条件式1

処理1

真 偽

条件式2

処理2 処理3

真 偽

if は任意の数入れ子に出来ます。

教科書 pp.130-133.

Page 199: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐 (if, else if, else 文)

• 真偽値による場合分け

199

if (条件式1) { // 条件式1が真の場合の処理1 } else if (条件式2) { // 条件式1が偽かつ // 条件式2が真の場合の処理2 } else { // 条件式1が偽かつ // 条件式2が偽の場合の処理3 }

条件式1

処理1

真 偽

条件式2

処理2 処理3

真 偽

else if は任意の数追加出来ます。

教科書 pp.130-133.

Page 200: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多分岐判断機構 (switch 文)

• 値による場合分け

200

switch (式) { case 値1: // 式が値1の場合の処理1 case 値2: // 式が値2の場合の処理2 default: // 他の条件に // 当てはまらない場合の処理N };

処理1 値1

値2

break 文を入れておかないと 次の条件の処理を 連続して実行するので注意。

処理2

処理N default

break

break

break

教科書 pp.134-140.

Page 201: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

繰り返し(ループ)

for文, while文, do-while 文によるループと continue 文、break 文によるループの再開と脱出

201

Page 202: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの再開と脱出

• continue 文 • while, do while, for 文内で使用可能

• 以降の処理を中断してループ末尾から再開する

• for文では後処理(第3パラメータ)も実行する

• break 文 • while, do while, for, switch 文内で使用可能

• 以降の処理を中断してループを脱出する

• switch文の場合はswitch文から脱出する

202

Page 203: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

後判定ループ (do while 文)

• 真偽値による繰り返し

203

do { // 条件式 が真の場合の処理 } while (条件式);

条件式

処理

do while 文は、ループ内の処理を 最低1回は実行する。

教科書 p.123.

continue break

Page 204: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

前判定ループ (while 文)

• 真偽値による繰り返し

204

while (条件式) { // 条件式が真の場合の処理 }

教科書 pp.119-122.

式2

処理 continue break

Page 205: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

初期化・更新処理付きループ (for 文)

• 真偽値による繰り返し

205

for (式1; 式2; 式3) { // 式2が真の場合の処理 }; 式2

式1

前判定ループだが 式1による初期化と 式3による更新処理を ひとまとめにして書ける。

処理

式3

教科書 pp.124-129.

continue break

Page 206: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

for文とwhile文 (前判定ループ)

• 以下のループは等価

• continue時の式3の扱いに注意

206

for (式1; 式2; 式3) { // 式2が真の場合の処理 };

式2

式1

処理

式3

教科書 pp.123-129.

for文の continue

break

式1; while (式2) { // 式2が真の場合の処理 式3; };

while文の continue

Page 207: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

for文とwhile文 (前判定ループ)

• 以下のループは等価

• continue時の式3の扱いに注意

207

for (i = 0; i < 10; i++) { // ループ内の処理 };

教科書 pp.123-129.

i = 0; while (i < 10) { //ループ内の処理 i++; };

i < 10

i = 0

処理

i++

for文の continue

break

while文の continue

Page 208: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

後判定ループ (do while 文)

• continue, break 後の処理(iの値)に注目

208

looptest_dowhile.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); do { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); i++; } while (i < n);

教科書 pp.119-122.

mintty + bash $ ./looptest_dowhile n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break

mintty + bash $ ./looptest_dowhile n = 0 0, 1: 1st 2nd 3rd

do while 文は、 ループ内の処理を 最低1回は実行する。

Page 209: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

前判定ループ (while 文)

• continue, break 後の処理(iの値)に注目

209

looptest_while.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); while (i < n) { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); i++; }

教科書 p.123.

mintty + bash $ ./looptest_while n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break

mintty + bash $ ./looptest_while n = 0

Page 210: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

初期化・更新処理付きループ (for 文)

• continue, break 後の処理(iの値)に注目

210

looptest_for.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); for (i = 0; i < n; i++) { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); }

教科書 pp.124-129.

mintty + bash $ ./looptest_for n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 2, 3: 1st 2nd 3rd 3, 4: 1st 2nd break

mintty + bash $ ./looptest_for n = 0

Page 211: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

continue 文

• 以下のループ内に更に小さなループが含まれない場合の continue は goto contin と同義

211

for (...) { // ... contin: ; }

[1] p.281.

do { // ... contin: ; } while (...);

while (...) { // ... contin: ; }

Page 212: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

goto文

• 指定した名札付き文へ移動(ジャンプ)する

• 名札(label)は以下のように設定出来る

212

ラベル名: 文

[1] p.281.

do while 文相当

while 文相当

for 文相当 loop: ;

{ // something to do contin: ; } if (expr) goto loop; brk: ;

loop: ; if (expr) { // something to do contin: ; goto loop; } brk: ;

expr1; loop: ; if (expr2) { // something to do contin: ; expr3; goto loop; } brk: ;

goto 文は 余程理由がない限り使わないこと

Page 213: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

213

Page 214: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

宿題

• 次回までに以下の事をやっておくこと。

• 教科書の第3章の終わりまで読み、指示された操作を試して動作を確認する。

• 不明な点、疑問点についてメモし、次回の授業に持参する。または、本講義の Moodle コース上にある第3週宿題用フォーラムに書き込んでおく。

214

Page 215: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第4週

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

情報処理言語Ⅰ(実習を含む。)

215

Page 216: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

Visual Studio Code https://code.visualstudio.com/

• Microsoft 製プログラミング用テキストエディタ

216

2015-04-29 にリリースされたばかりのテキストエディタ。Windows 以外にも Mac, Linux 用もある。

News

Page 217: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

制御構造

条件分岐と繰り返し

217

Page 218: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

流れ図(フローチャート)

• プログラムの処理の流れを図示する方法

218 教科書 pp.112-116.

条件分岐

処理

端子

定義済み処理

表示

手操作入力

プログラムの開始と終了

代入や演算等 各ステップにおける処理

サブルーチンや関数等

処理の振り分け

画面等への出力

キーボード等からの入力

各部品を矢印で繋ぐ事で処理の流れを視覚的に表現する。

各部品の内部にはそれぞれのステップで行う内容に書き換えて使う。

結合子 別のフローチャートと結合 2015-05-12追加

Page 219: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐

if 文と switch 文

219

Page 220: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐 (if 文)

• 真偽値による場合分け

220

if (条件式1) { // 条件式1が真の場合の処理1 }

教科書 pp.130-133.

条件式1 真 偽

処理1

if 文を使うと特定の条件下で実行する処理を指定出来る。

Page 221: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件分岐 (if, else 文)

• 真偽値による場合分け

221

if (条件式1) { // 条件式1が真の場合の処理1 } else { // 条件式1が偽の場合の処理2 }

教科書 pp.130-133.

条件式1 真 偽

処理1 処理2

if, else 文を使うと特定の条件下で別の処理を指定出来る。

Page 222: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

入れ子の条件分岐 (if, else 文)

• 真偽値による場合分け

222

if (条件式1) { if (条件式2) { // 条件式1が真かつ // 条件式2が真の場合の処理1 } else { // 条件式1が真かつ // 条件式2が偽の場合の処理2 } } else { // 条件式1が偽の場合の処理3 }

条件式1 真 偽

教科書 pp.130-133.

処理3 条件式2 真 偽

処理1 処理2

if, else 文は任意の数入れ子に出来る。 だだし、入れ子が深くなると読み難くなるので注意。

2015-05-15修正 誤:処理2,3,1 正:処理1,2,3

Page 223: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

入れ子の条件分岐 (if, else 文)

• 真偽値による場合分け

223

if (条件式1) { // 条件式1が真の場合の処理1 } else { if (条件式2) { // 条件式1が偽かつ // 条件式2が真の場合の処理2 } else { // 条件式1が偽かつ // 条件式2が偽の場合の処理3 } }

条件式1 真 偽

条件式2 真 偽

if, else 文は任意の数入れ子に出来る。 else 側の if は else if で置き換ると入れ子を防げる。

教科書 pp.130-133.

処理1

処理2 処理3

Page 224: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

複数条件の条件分岐 (if, else if, else 文)

• 真偽値による場合分け

224

if (条件式1) { // 条件式1が真の場合の処理1 } else if (条件式2) { // 条件式1が偽かつ // 条件式2が真の場合の処理2 } else { // 条件式1が偽かつ // 条件式2が偽の場合の処理3 }

else if は任意の数追加出来る。 入れ子を作らずに複数の条件を追加出来る。

教科書 pp.130-133.

条件式1 真 偽

条件式2 真 偽

処理1

処理2 処理3

Page 225: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多分岐判断機構 (switch 文)

• 値による場合分け

225

switch (式) { case 値1: // 式が値1の場合の処理1 case 値2: // 式が値2の場合の処理2 default: // 他の条件に // 当てはまらない場合の処理N };

教科書 pp.134-140.

break 文を入れておかないと 次の条件の処理を 連続して実行するので注意。

break

break

break

値1 処理1

処理2

default

値2

処理N

Page 226: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

平方根の計算

条件分岐の例題

226

Page 227: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

sqrt 関数

• 書式: #include <math.h> double sqrt(double x);

• 引数: • x: 求める平方根の2乗

• 戻り値: • 0 ≤ 𝑥 の場合 𝑥 を返す。 • 0 ≤ 𝑥 でない場合は処理系依存?

• x が負なら、nan (=非数) を返し、グローバル変数 errno に EDOM を代入する(errno は errno.h を include すると参照出来る)。

• x が 0 なら 0 を、inf (=∞) なら inf を返す。 • x が nan なら nan を返す。

227

Page 228: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

平方根の計算

• sqrt() 関数は引数が負の場合計算出来ない。

228

sqrt_practice_1.c #include <stdio.h> #include <math.h> void main() { double x; fprintf(stderr, "x = ?¥b"); scanf("%lf", &x); printf("x: %f¥n", x); printf("sqrt(x): %f¥n", sqrt(x)); }

1 2 3 4 5 6 7 8 9

10 11

mintty+bash+gcc $ gcc sqrt_practice_1.c && ./a x = 2 x: 2.000000 sqrt(x): 1.414214 $ ./a x = -2 x: -2.000000 sqrt(x): nan

Page 229: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 平方根の計算(if文)

• sqrt_practice_1.c を参考に 0 ≤ 𝑥 の場合は実数の平方根 𝑥を、 𝑥 < 0 の場合は虚数の平方根 −𝑥𝑖 を if 文で場合分けして表示する sqrt_practice_if.c を完成させよ。虚数は数値の後に i を表示する事で表現すれば良い。

• 例えば x=-2 の場合は以下のようになる。

229

mintty+bash+gcc $ gcc sqrt_practice_if.c && ./a x = -2 x: -2.000000 sqrt(x): 1.414214i

Page 230: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 平方根の計算(if文) ヒント

• sqrt_practice_1.c の 10 行目は 𝑥 を表示している。これを if 文で場合分けしてやれば良い。

230

条件式 真 偽

𝑥 −𝑥 𝑖

sqrt_practice_1.c printf("sqrt(x): %f¥n", sqrt(x)); 10 𝑥

sqrt_practice_if.c if (条件式) { // 𝑥 を表示 } else { // −𝑥 と 𝑖 を表示 }

10 11 12 13 14

Page 231: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 書式:

• 条件式 ? 式1 : 式2

条件演算子 三項演算子(?:)

231 [1] pp.63-66, 256-257.

条件式 真 偽

式1 式2

condexprtest.c #include <stdio.h> void main() { int i; fprintf(stderr, "i = ?¥b"); scanf("%d", &i); printf("%s¥n", i ? "not zero" : "zero"); }

1 2 3 4 5 6 7 8 9

mintty+bash+gcc $ gcc condexprtest.c && ./a i = 1 not zero $ ./a i = 0 zero

Page 232: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 平方根の計算(条件演算子)

• 先程の負の数の平方根の計算を条件演算子を用いて解決してみよう。

• 10行目の printf では 2 つ目の引数が %f に 3 つ目の引数が %s へ埋め込まれる。

232

sqrt_practice_condexpr.c double x; fprintf(stderr, "x = ?¥b"); scanf("%lf", &x); printf("x: %f¥n", x); printf("sqrt(x): %f%s¥n", sqrt(/*WYCH*/), /*WYCH*/);

6 7 8 9 10

Page 233: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

奇数と偶数の判定

条件分岐の例題

233 2015-05-18追加

Page 234: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

奇数と偶数

• 整数のうち 2 で割り切れるのが偶数、2 で割り切れないのが奇数

• 2 で割り切れるとは?

• 整数を 2 で割った余り(剰余)が 0

• 2 で割り切れないとは

• 整数を 2 で割った余り(剰余)が 0 以外

234

Page 235: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語の剰余

• 剰余は二項演算子 %

• i % 2 で 2 で割った余りが求まる

• 同じかどうか比較するのは二項演算子 == や !=

• i % 2 == 0 は i を 2 で割った余りが 0 なら真、それ以外は偽

• i % 2 != 0 は i を 2 で割った余りが 0 以外なら真、それ以外は偽

• i % 2 != 0 は単項演算子 ! を用いて !(i % 2 == 0) としても同じ意味になる

235

Page 236: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演算子の優先度

演算子 結合規則 備考

( ) [ ] -> . 左から右→

! ~ ++ -- + - * & (type) sizeof 右から左← 単項演算子

* / % 左から右→ 二項演算子

+ - 左から右→ 二項演算子

<< >> 左から右→ bitシフト

< <= > >= 左から右→ 関係演算子

== != 左から右→ 等値演算子

& 左から右→ bit毎のAND

^ 左から右→ bit毎のXOR

| 左から右→ bit毎のOR

&& 左から右→ 論理演算子(AND)

|| 左から右→ 論理演算子(OR)

?: 右から左← 三項演算子

= += -= *= /= %= &= ^= |= <<= >>= 右から左← 代入演算子

, 左から右→

[1] p.65. より

優先度

236

Page 237: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 偶数かどうか判定する

• 標準入力から入力された整数値が奇数かどうか判別して、奇数であれば入力された数値に続けて " is even number¥n" そうでなければ " is not even number¥n" と表示するプログラ

ムを作成せよ。奇数でない場合は何も表示しなくて良い。

• if_practice_even.c の /*WYCH*/ の個所を修正すれば良い。

237

Page 238: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 奇数かどうか判定する

• 標準入力から入力された整数値が奇数かどうか判別して、奇数であれば入力された数値に続けて " is odd number¥n" そうでなければ " is not odd number¥n" と表示するプログラム

を作成せよ。奇数でない場合は何も表示しなくて良い。

• if_practice_odd.c の /*WYCH*/ の個所を修正すれば良い。

238

Page 239: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 奇数か偶数か判定する

• 標準入力から入力された整数値が奇数かどうか判別して、奇数であれば入力された数値に続けて " is odd number¥n"、偶数であれば入力された数値に続けて "is even number¥n" と表示するプログラムを作成せよ。

• if_practice_evenodd.c の /*WYCH*/ の個所を修正すれば良い。

239

Page 240: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年の判定

入れ子の条件分岐の例題

240

Page 241: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年(leap year)とは

• 地球の平均回帰年は365日+約1/4日であるため1年を356日にしているとカレンダー上の日付と季節が4年で1日ずつずれてしまう。これを防ぐのが4年に1回設ける2月29日(閏日)。

• 閏年の求め方

• 西暦を4で割り切れるなら閏年?

241

閏年 判定式

閏年 平年

真 偽

Page 242: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年(leap year)の判定

• 4で割り切れる(割れる)とは?

• 4で割った余りが0ということ

• 4で割り切れる : year % 4 == 0

• 4で割り切れない : year % 4 != 0

• C言語では0は偽、0以外は真だったから

• 以下のようにも書けるが・・・

• 4で割り切れる : !(year % 4)

• 4で割り切れない : (year % 4)

242

ぱっと見て意味の分かり易い書き方をしましょう

% : 剰余算演算子

等値演算子 == : 等しい != : 等しくない

! : 論理否定演算子

Page 243: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演算子の優先度

演算子 結合規則 備考

( ) [ ] -> . 左から右→

! ~ ++ -- + - * & (type) sizeof 右から左← 単項演算子

* / % 左から右→ 二項演算子

+ - 左から右→ 二項演算子

<< >> 左から右→ bitシフト

< <= > >= 左から右→ 関係演算子

== != 左から右→ 等値演算子

& 左から右→ bit毎のAND

^ 左から右→ bit毎のXOR

| 左から右→ bit毎のOR

&& 左から右→ 論理演算子(AND)

|| 左から右→ 論理演算子(OR)

?: 右から左← 三項演算子

= += -= *= /= %= &= ^= |= <<= >>= 右から左← 代入演算子

, 左から右→

[1] p.65. より

優先度

243

Page 244: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 4 で割り切れるか表示する

• leap_year_practice_1.c の /*WYCH*/ を書き換えて、year が 4 で割り切れる場合 "can be divided by 4."、割り切れない場合 "can not be divided by 4." と表示するプログラムを完成せよ。

244

mintty+bash+gcc $ gcc leap_year_practice_1.c && ./a year = 2015 2015 can not be divided by 4. $ ./a year = 2016 2016 can be divided by 4.

2015-05-11修正 誤:dividec 正:divided

Page 245: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年(leap year)の定義

• グレゴリオ暦における閏年の定義

• 判定したい年を西暦で表した際

• 4で割り切れる場合は閏年 (条件1)

• 但し100で割り切れる場合は平年 (条件2)

• 但し400で割り切れる場合は閏年 (条件3)

• 地球の平均回帰年は約365.242199日であるため、上記ルールだと約3320年で1日ずれる程度で済む。

245

Page 246: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年(leap year)の判定

246

4で 割れる

平年

真 偽

閏年

条件1

Page 247: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年(leap year)の判定

247

4で 割れる

平年

真 偽

100で 割れる

閏年

真 偽

平年

条件1 +条件2

Page 248: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年(leap year)の判定

248

4で 割れる

平年

真 偽

100で 割れる

閏年

真 偽

400で 割れる

閏年 平年

真 偽

条件1 +条件2 +条件3

完成

Page 249: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 閏年(leap year)の判定

• leap_year_practice_2.c の /*WYCH*/ の部分を書き換えて閏年か判定するプログラムを完成せよ。

• /*WYCH*/ の部分には year に格納された西暦が閏年であれば変数 leap_year_flag に 1 を閏年でなければ 0 を代入するコード作成すれば良い。これは前のページのフローチャートを参考に if 文を 3 重の入れ子にすれば出来る。

• なおここでは紀元前については考慮する必要はない。

249

Page 250: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 閏年(leap year)の判定

• ヒント1

• 前述の条件1~3のフローチャートをif,else文で書くと以下のようになる。

250

条件1 if (/*条件1*/) { /*閏年*/ } else { /*平年*/ }

条件1+条件2 if (/*条件1*/) { if (/*条件2*/) { /*平年*/ } else { /*閏年*/ } } else { /*平年*/ }

条件1+条件2+条件3 if (/*条件1*/) { if (/*条件2*/) { /*条件3のif,else文*/ } else { /*閏年*/ } } else { /*平年*/ }

Page 251: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 閏年(leap year)の判定

• ヒント2

• 閏年なら leap_year_flag に 1 そうでなければ 0 を代入すれば良い。

251

条件1 if (/*条件1*/) { leap_year_flag = 1; /*閏年*/ } else { /*平年*/ }

Page 252: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

月の名前

多分岐の例題

252

Page 253: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 月の名前の表示

• monthname_practice_1.c の /*WYCH*/ の部分を変更し、入力した月 month に対応する英語の月名(January, February, March, April, June, July, August, September, October, November, December )を表示せよ。

253

mintty+bash+gcc $ gcc monthname_practice_1.c && ./a month = 1 January

Page 254: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

繰り返し(ループ)

for文, while文, do-while 文によるループと continue 文、break 文によるループの再開と脱出

254

Page 255: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの再開と脱出

• continue 文 • while, do while, for 文内で使用可能

• 以降の処理を中断してループ末尾から再開する

• for文では後処理(第3パラメータ)も実行する

• break 文 • while, do while, for, switch 文内で使用可能

• 以降の処理を中断してループを脱出する

• switch文の場合はswitch文から脱出する

255

Page 256: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

後判定ループ (do while 文)

• 真偽値による繰り返し

256

do { // 条件式 が真の場合の処理 } while (条件式);

教科書 p.123.

条件式

処理

continue break

do while 文は、ループ内の処理を 1回以上実行する(=最低1回は実行する)。

Page 257: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

前判定ループ (while 文)

• 真偽値による繰り返し

257

while (条件式) { // 条件式が真の場合の処理 }

教科書 pp.119-122.

条件式

処理 continue break

while 文は、ループ内の処理を 0回以上実行する(=実行しない場合もある) 。

2015-06-04修正 誤:式2 正:条件式

Page 258: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

初期化・更新処理付きループ (for 文)

• 真偽値による繰り返し

258

for (式1; 式2; 式3) { // 式2が真の場合の処理 }; 式2

式1

処理

式3

教科書 pp.124-129.

continue break

for 分は前判定ループで 式1による初期化と 式3による更新処理を ひとまとめにしてコンパクトに書ける。

Page 259: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

for文とwhile文 (前判定ループ)

• 以下のループは等価

• ただしcontinue時の式3の扱いに注意

259

for (式1; 式2; 式3) { // 式2が真の場合の処理 };

式2

式1

処理

式3

教科書 pp.123-129.

for文の continue

break

式1; while (式2) { // 式2が真の場合の処理 式3; };

while文の continue

Page 260: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

for文とwhile文 (前判定ループ)

• 以下のループは等価

• continue時の式3の扱いに注意

260

for (i = 0; i < 10; i++) { // ループ内の処理 };

教科書 pp.123-129.

i = 0; while (i < 10) { // ループ内の処理 i++; };

i < 10

i = 0

処理

i++

for文の continue

break

while文の continue

Page 261: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

後判定ループ (do while 文)

• continue, break 後の処理(iの値)に注目

261

looptest_dowhile.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); do { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); i++; } while (i < n);

教科書 pp.119-122.

mintty + bash $ ./looptest_dowhile n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break

mintty + bash $ ./looptest_dowhile n = 0 0, 1: 1st 2nd 3rd

do while 文は、 ループ内の処理を 最低1回は実行する。

Page 262: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

前判定ループ (while 文)

• continue, break 後の処理(iの値)に注目

262

looptest_while.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); while (i < n) { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); i++; }

教科書 p.123.

mintty + bash $ ./looptest_while n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break

mintty + bash $ ./looptest_while n = 0

Page 263: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

初期化・更新処理付きループ (for 文)

• continue, break 後の処理(iの値)に注目

263

looptest_for.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); for (i = 0; i < n; i++) { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); }

教科書 pp.124-129.

mintty + bash $ ./looptest_for n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 2, 3: 1st 2nd 3rd 3, 4: 1st 2nd break

mintty + bash $ ./looptest_for n = 0

Page 264: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

continue 文

• 以下のループ内に更に小さなループが含まれない場合の continue は goto contin と同義

264

for (...) { // ... contin: ; }

[1] p.281.

do { // ... contin: ; } while (...);

while (...) { // ... contin: ; }

Page 265: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

goto文

• 指定した名札付き文へ移動(ジャンプ)する

• 名札(label)は以下のように設定出来る

265

ラベル名: 文

[1] p.281.

do while 文相当

while 文相当

for 文相当 loop: ;

{ // something to do contin: ; } if (expr) goto loop; brk: ;

loop: ; if (expr) { // something to do contin: ; goto loop; } brk: ;

expr1; loop: ; if (expr2) { // something to do contin: ; expr3; goto loop; } brk: ;

goto 文は 余程理由がない限り使わないこと

Page 266: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

簡易版 seq コマンドの作成

前判定ループの演習

2015-05-15追加

Page 267: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

seq コマンド

• UNIX系のOSに標準で搭載されているコマンド

• 書式:

• seq FIRST LAST

• 機能:

• FIRST から LAST までの整数を 1 刻みで小さい順に表示する。

• 他にも詳細な機能があるが、ここでは省略

JM / seq (1)

Page 268: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: while 文による簡易 seq コマンド

• seq_practice_1_while.c の /*WYCH*/ の部分を修正して以下のプログラムを完成させよ。

• 標準入力から int 型の変数 first, last に整数値を読み取り、first 以上、last 以下の整数を1刻みで小さい順に表示せよ。

mintty + bash $ gcc seq_practice_1_while.c && ./a first = 5 last = 9 5 6 7 8 9

Page 269: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: for 文による簡易 seq コマンド

• seq_practice_1_for.c の /*WYCH*/ の部分を修正して以下のプログラムを完成させよ。

• 標準入力から int 型の変数 first, last に整数値を読み取り、first 以上、last 以下の整数を1刻みで小さい順に表示せよ。

mintty + bash $ gcc seq_practice_1_for.c && ./a first = 5 last = 9 5 6 7 8 9

Page 270: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

素数判定

条件分岐とループの例題

270 2015-05-18追加

Page 271: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

素数

• 1と自分以外に正の約数を持たない自然数(正整数)で1でない数

• 調べたい数をiとすると、2以上i/2以下の整数jの全てについてiが割り切れないことを確認すれば良い。

• ※厳密には2以上 𝑖以下の整数jについて調べれば良いが、平方根の計算は除算に比べかなり遅いのでここではi/2以下について確認する。

271

Page 272: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 素数判定

• 標準入力から入力された正整数が素数かどうか判定するプログラムを作成せよ。

• isprime_practice_1.c の /*WYCH*/ の箇所を修正すれば良い。

272

mintty + bash $ gcc is_prime_practice_1.c $ ./a i = 1 1 is not prime number $ ./a i = 2 2 is prime number $ ./a i = 3 3 is prime number $ ./a i = 4 4 is not prime number

Page 273: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 素数判定(ヒント)

• 作成すべきプログラムの素数判定部分のフローチャートは以下の通りである

素数判定部分

273

jを2からi/2の範囲で繰り返し

iがjで 割切れる

非素数

break

iは2以上

素数と仮定

1

1

非素数

j++

Page 274: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

274

Page 275: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第4週 補足資料

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

情報処理言語Ⅰ(実習を含む。)

275

Page 276: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

条件判定の簡略化

閏年の判定を例に

276

Page 277: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 条件1を実装

閏年(leap year)の判定

277

if (year % 4 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; }

真 偽 4で割れる

平年 閏年

Page 278: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 条件2を追加

閏年(leap year)の判定

278

if (year % 4 == 0) { if (year % 100 == 0) { leap_year_flag = 0; } else { leap_year_flag = 1; } } else { leap_year_flag = 0; }

真 偽 4で割れる

平年 100で割れる 真 偽

閏年 平年

Page 279: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 条件3を追加して完成

閏年判定の整理

ごちゃごちゃしていて 分かり難い

もっと分かり易く 書けないか?

is_leap_year_1_1.c if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; }

279

真 偽 4で割れる

平年 100で割れる

平年

400で割れる

閏年

偽 閏年

Page 280: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 平年フラグを外に追い出してみる

閏年判定の整理

真 偽 4で割れる

280

平年 100で割れる

平年

400で割れる

閏年

偽 閏年

平年

leap_year_flag = 0; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; }

Page 281: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 平年フラグを外に追い出してみる

閏年判定の整理

真 偽 4で割れる

281

平年 100で割れる

平年

400で割れる

閏年

偽 閏年

平年

leap_year_flag = 0; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } } else { leap_year_flag = 1; } }

少し短くなったが 対称性が崩れていて

少し美しくない

Page 282: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 逆に閏年フラグを外に追い出してみる

閏年判定の整理

真 偽 4で割れる

282

平年 100で割れる

平年

400で割れる

閏年

偽 閏年

閏年

leap_year_flag = 1; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; }

Page 283: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 閏年フラグを外に追い出してみる

閏年判定の整理

真 偽 4で割れる

283

平年 100で割れる

平年

400で割れる

閏年

偽 閏年

閏年

leap_year_flag = 1; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { ; } else { leap_year_flag = 0; } } else { leap_year_flag = 0; }

やはり 対称性が崩れていて

少し美しくない

真の場合の処理が 空になっているのも 格好が良くない

Page 284: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重のif-else文による実装

• 例外時に結果を随時上書きしてみる

閏年判定の整理 真 偽

4で割れる

284

平年

100で割れる

平年

400で割れる

偽 閏年

leap_year_flag = 0; if (year % 4 == 0) { leap_year_flag = 1; if (year % 100 == 0) { leap_year_flag = 0; if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; }

閏年

平年

閏年

平年

Page 285: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

leap_year_ex2_1.c

• 3重のif-else文による実装

• 例外時に結果を随時上書きしてみる

閏年判定の整理

285

leap_year_flag = 0; if (year % 4 == 0) { leap_year_flag = 1; if (year % 100 == 0) { leap_year_flag = 0; if (year % 400 == 0) { leap_year_flag = 1; } } }

真 偽 4で割れる

平年

100で割れる

平年

400で割れる

偽 閏年

閏年

平年

閏年

平年

短く対称性も取れていて 比較的美しい?

Page 286: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

西暦と閏年の集合

• 包含の関係 • 西暦⊃X⊃Y⊃Z

X

Y

Z

286

Page 287: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 分解してみると

閏年判定の整理

287

真 偽 4で割れる 100で割れる 400で割れる

真 真 偽 偽

閏年 平年 閏年 平年

100 or 400で 割れる場合

400で 割れる場合

1

1

2

2

3

3

100 or 400で 割れない場合

400で 割れない場合

Page 288: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 展開したif文による実装

• 100 と 400 は 4 の倍数 400 は 100 の倍数 である点に着目すると ネスト(入れ子)を展開可能

閏年判定の整理

288

leap_year_ex2_1.c leap_year_flag = 0; if (year % 4 == 0) { leap_year_flag = 1; } if (year % 100 == 0) { leap_year_flag = 0; } if (year % 400 == 0) { leap_year_flag = 1; }

if文のロジック以外に 各条件間の数学的関係による 暗黙の前提が分からないと 読めないコードになるかも? そういう意味では 良くないコード?

year % 4 != 0 の場合には影響を与えない

year % 4 != 0 および year % 100 != 0 の場合には影響を与えない

適切なコメント等が必要?

Page 289: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 展開したif文による実装

• 前頁のコードから省略可能な { } を省略

閏年判定の整理

289

leap_year_ex2_2.c int leap_year_flag = 0; if (year % 4 == 0) leap_year_flag = 1; if (year % 100 == 0) leap_year_flag = 0; if (year % 400 == 0) leap_year_flag = 1;

短くすっきりしていて見易い。 しかし、定義通りになっていないため、 100で割り切れた場合、4で割り切れなかった場合に影響を与えない 400で割り切れた場合、4,100で割り切れなかった場合に影響を与えない 事がわかっていないと混乱するかもしれない?

実行する処理が 1つだけの場合は 省略出来る。

Page 290: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重の条件演算子による実装

• 条件1を実装

• 条件2を追加

• 条件3を追加して完成

閏年判定の整理

290

leap_year_flag = year % 4 == 0 ? 1 : 0;

leap_year_flag = year % 4 == 0 ? (year % 100 == 0 ? 0 : 1) : 0;

leap_year_ex3_1.c leap_year_flag = year % 4 == 0 ? (year % 100 == 0 ? (year % 400 == 0 ? 1 : 0) : 1) : 0;

条件演算子は便利だけど 下手に多用すると読み難くなるので注意

ネスト(入れ子)が深くなると if-else文以上に読み難い

Page 291: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 3重の条件演算子による実装

• 条件1を実装

• 条件2を追加

• 条件3を追加して完成

閏年判定の整理

291

leap_year_flag = year % 4 == 0 ? 1 : 0;

leap_year_flag = year % 4 == 0 ? 1 : 0; leap_year_flag = year % 100 == 0 ? 0 : leap_year_flag;

leap_year_ex3_2.c leap_year_flag = year % 4 == 0 ? 1 : 0; leap_year_flag = year % 100 == 0 ? 0 : leap_year_flag; leap_year_flag = year % 400 == 0 ? 1 : leap_year_flag;

これなら leap_year_ex2_2.c の方が読み易いかも?

leap_year_ex2_2.c と同じ方法で 入れ子の条件を展開する例

Page 292: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

論理演算

• AND, OR, NOT

• 条件を論理演算する場合に使う

• AND: X && Y

• OR: X || Y

• NOT: !X

X Y X && Y X || Y !X

FALSE FALSE 0 0 1

FALSE TRUE 0 1

TRUE FALSE 0 1 0

TRUE TRUE 1 1

292

Page 293: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 西暦全体の集合のうち

• X: 4で割り切れる集合(Y,Z を包含)

• Y: 100で割り切れる集合(Z を包含)

• Z: 400で割り切れる集合 X

Y

Z

!Y Y

293

Page 294: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 論理演算で 考えると

X

Y

Z

Z X && !Y

(X && !Y) || Z

C言語の演算子の優先度的には X && !Y || Z でも良いが ( ) を付けた方が理解が容易かつ 誤解の余地が生じない

!X Y && !Z

!X || (Y && !Z)

294

Page 295: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• if-else文と論理演算による実装

• 論理演算による実装

閏年判定の整理

295

leap_year_ex4_1.c if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; }

leap_year_ex4_2.c leap_year_flag = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;

Page 296: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 全ての条件が網羅出来ているか?

• 条件に漏れはないか?

296

year % 4 == 0

year % 100 == 0 year % 400 == 0 閏年

year % 400 != 0 平年

year % 100 != 0 year % 400 == 0 ×

year % 400 != 0 閏年

year % 4 != 0

year % 100 == 0 year % 400 == 0 ×

year % 400 != 0 ×

year % 100 != 0 year % 400 == 0 ×

year % 400 != 0 平年

× の個所は 条件を満たす year が存在しない

2_1, 2_2, 3_2 の例で year % 100 != 0 や year % 400 != 0 が 考慮不要なことが確認出来る。

Page 297: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 全ての条件が網羅出来ているか?

• 条件に漏れはないか?

297

year % 4 == 0

year % 100 == 0 year % 400 == 0 閏年

year % 400 != 0 平年

year % 100 != 0 year % 400 == 0

閏年 year % 400 != 0

year % 4 != 0

year % 100 == 0 year % 400 == 0

平年 year % 400 != 0

year % 100 != 0 year % 400 == 0

year % 400 != 0

今の場合前の条件への追加条件なので 全ての組み合わせを考える必要はない

Page 298: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 全ての条件が網羅出来ているか?

• 条件に漏れはないか?

298

year % 4 == 0 year % 4 != 0

year % 100 == 0 year % 400 == 0 閏年 ×

year % 400 != 0 平年 ×

year % 100 != 0 year % 400 == 0 × ×

year % 400 != 0 閏年 平年

× の個所は 条件を満たす year が存在しない

長くなる場合は横に展開しても良い

Page 299: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 全ての条件が網羅出来ているか?

• 条件に漏れはないか?

299

year % 4 == 0 year % 100 == 0 year % 400 == 0 閏年

year % 4 == 0 year % 100 == 0 year % 400 != 0 平年

year % 4 == 0 year % 100 != 0 year % 400 == 0 ×

year % 4 == 0 year % 100 != 0 year % 400 != 0 閏年

year % 4 != 0 year % 100 == 0 year % 400 == 0 ×

year % 4 != 0 year % 100 == 0 year % 400 != 0 ×

year % 4 != 0 year % 100 != 0 year % 400 == 0 ×

year % 4 != 0 year % 100 != 0 year % 400 != 0 平年

× の個所は 条件を満たす year が存在しない

この書き方は Excel 等で sort して調べるのに向いている

Page 300: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

閏年判定の整理

• 真偽値による文字列の切り替え

300

is_leap_year_template.c if (leap_year_flag) { printf("%d is leap year.¥n", year); } else { printf("%d is not leap year.¥n", year); }

printf("%d is%s leap year.¥n", year, leap_year_flag ? "" : " not");

leap_year_flag の値を見て直接 %s に埋め込む文字列を変更

Page 301: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

同じ処理でも実装は様々

• 同じ処理でも複数の異なる実装が可能

• 効率や可読性等、何を重視するか?

• 読み易い、理解しやすいコードを推奨

301

Page 302: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第5週

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

情報処理言語Ⅰ(実習を含む。)

302

Page 303: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

入れ子の繰り返し(多重ループ)

303

Page 304: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多重ループとは?

• ループの中に別のループを入れた 入れ子構造のループ

304

mul99_ex1.c for (i = 1; i <= 9; i++) { //行ループ for (j = 1; j <= 9; j++) {//列ループ printf(" %2d", i * j); //掛算九九 } printf("¥n"); //行末尾で改行 }

mintty + bash $ gcc mul99_ex1.c && ./a 1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81

7 8 9

10 11 12

上記は掛算九九を計算して表を作成する例

Page 305: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

掛算九九の例

• 見出し行と見出し列、見出し区切り(-+|)を付けた例

305

mul99_ex2.c printf(" |"); //見出しの区切り for (j = 1; j <= 9; j++) { printf(" %2d", j); //見出し } printf("¥n"); //見出しの改行 printf("--+"); //見出しの区切り for (j = 1; j <= 9; j++) { printf("---"); //見出しの区切り } printf("¥n"); //見出しの区切りの改行

mintty + bash $ gcc mul99_ex2.c && ./a | 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

7 8 9

10 11 12 13 14 15 16 17

Page 306: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

掛算九九の例

• 見出し行と見出し列、見出し区切り(-+|)を付けた例

306

mul99_ex2.c for (i = 1; i <= 9; i++) {//行ループ printf("%2d|", i); //見出しと区切り for (j = 1; j <= 9; j++) {//列ループ printf(" %2d", i * j); //掛算九九 } printf("¥n"); //行末尾で改行 }

mintty + bash $ gcc mul99_ex2.c && ./a | 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

19 20 21 22 23 24 25

Page 307: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

while 文の2重ループの例

307

2重ループ while (条件式1) { // 処理1-1 while (条件式2) { // 処理2 // ... // ... // ... } // 処理1-2 }

偽 条件式1

処理1-1

処理1-1

1

2

1

2

処理2

条件式2

ループは基本的にいくつでも 入れ子に出来る。

Page 308: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

while 文の3重ループの例

308

3重ループ while (条件式1) { // 処理1-1 while (条件式2) { // 処理2-1 while (条件式3) { // 処理3 } // 処理2-2 } // 処理1-2 }

偽 条件式1

処理1-1

処理1-1

1

4

偽 条件式2

処理2-1

処理2-1

2

3

2

3

処理2

条件式2

1

4

入れ子があまり深くなると 分かり辛くなるので注意

Page 309: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

異なるループ文で多重ループ

• do-while, while, for ループを必要に応じて組み合わせて入れ子にする

309

異なるループ文で3重ループ for (式1-1; 式1-2; 式1-3) { // 処理1-1 while (条件式2) { // 処理2-1 do { // 処理3 } while (条件式3); // 処理2-2 } // 処理1-2 }

異なるループ文で3重ループ do { // 処理1-1 for (式2-1; 式2-2; 式2-3){ // 処理2-1 while (条件式3) { // 処理3 } // 処理2-2 } // 処理1-2 } while (条件式1);

Page 310: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

掛算九九の表

多重ループの例題

310

Page 311: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 掛算九九(範囲指定)

• 標準入力から掛算九九の表の表示範囲 i1 i2 j1 j2 を読み取り、指定された範囲のみ表示する mul99_practice_1.c を作成せよ(/*WYCH*/ の個所を修正すれば良い)。

311

mintty + bash $ gcc mul99_practice_1.c && ./a i1 i2 j1 j2 = 2 5 4 8 | 4 5 6 7 8 --+--------------- 2| 8 10 12 14 16 3| 12 15 18 21 24 4| 16 20 24 28 32 5| 20 25 30 35 40

値が3桁やマイナスになると 表示が破綻する場合があるが、 以下で行う一連の演習では 3桁やマイナスの値は考慮しなくて良い。

Page 312: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 掛算九九(行の反転)

• 完成した mul99_practice_1.c をコピーしてファイル名を mul99_practice_2.c とし、行の見出しが逆順となるよう修正せよ。

312

mintty + bash $ gcc mul99_practice_2.c && ./a i1 i2 j1 j2 = 2 5 4 8 | 4 5 6 7 8 --+--------------- 5| 20 25 30 35 40 4| 16 20 24 28 32 3| 12 15 18 21 24 2| 8 10 12 14 16

Page 313: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 掛算九九(見出しの移動)

• 完成した mul99_practice_2.c をコピーしてファイル名を mul99_practice_3.c とし、列の見出しを表の下に表示するよう修正せよ。

313

mintty + bash $ gcc mul99_practice_3.c && ./a i1 i2 j1 j2 = 2 5 4 8 5| 20 25 30 35 40 4| 16 20 24 28 32 3| 12 15 18 21 24 2| 8 10 12 14 16 --+--------------- | 4 5 6 7 8

Page 314: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 掛算九九(表示値の制限)

• 完成した mul99_practice_3.c をコピーしてファイル名を mul99_practice_4.c とし、i*j<=99の場合以外は結果を "##" と表示するよう修正せよ。

314

mintty + bash $ gcc mul99_practice_4.c && ./a i1 i2 j1 j2 = 8 14 5 15 14| 70 84 98 ## ## ## ## ## ## ## ## 13| 65 78 91 ## ## ## ## ## ## ## ## 12| 60 72 84 96 ## ## ## ## ## ## ## 11| 55 66 77 88 99 ## ## ## ## ## ## 10| 50 60 70 80 90 ## ## ## ## ## ## 9| 45 54 63 72 81 90 99 ## ## ## ## 8| 40 48 56 64 72 80 88 96 ## ## ## --+--------------------------------- | 5 6 7 8 9 10 11 12 13 14 15

Page 315: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

画像の生成

多重ループの例題

315

Page 316: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

BMP, DIB

• Wikipedia / Windows bitmap

• Windows 標準の画像形式

• 書くのは比較的簡単

• 例: 第1週の bmptest.c 等

• 読むのは、フォーマットがいくつもあるので、全部対応するのは面倒

316

Page 317: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

PNM(Portable aNyMap)

• Wikipedia / PNM (画像フォーマット)

• シンプルなフォーマットで読み書きが簡単

317

ファイル識別子 画像形式 データ形式

P1 PBM: Portable Bit Map テキスト

P2 PGM: Portable Gray Map テキスト

P3 PPM: Portable Pix Map テキスト

P4 PBM: Portable Bit Map バイナリ

P5 PGM: Portable Gray Map バイナリ

P6 PPM: Portable Pix Map バイナリ

f.pbm P1 # f.pbm 6 7 0 0 0 0 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0

Page 318: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト形式の PBM Format

• 2値(白黒)画像用

318

feep.pbm P1 # feep.pbm 24 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

ファイル識別子

画像サイズ(幅と高さ)

コメント

2値画像データ本体 0または1のデータ

Page 319: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト形式の PGM Format

• 濃淡値(グレイスケール)画像用

319

feep.pgm P2 # feep.pgm 24 7 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

ファイル識別子

画像サイズ(幅と高さ)

コメント

濃淡値画像データ本体 数値が大きいものほど明るい

明るさの最大値

Page 320: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト形式の PPM Format

• カラー画像用

320

feep.ppm P3 # feep.ppm 4 4 15 0 0 0 0 0 0 0 0 0 15 0 15 0 0 0 0 15 7 0 0 0 0 0 0 0 0 0 0 0 0 0 15 7 0 0 0 15 0 15 0 0 0 0 0 0 0 0 0

カラー画像データ本体 RGBを1組にして書く

ファイル識別子

画像サイズ(幅と高さ)

コメント

明るさの最大値

Page 321: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

PNMからBMPへの変換

• netpbm または ImageMagick を使うと楽

• Wikipedia / netpbm

• Wikipedia / ImageMagick

• インストールは以下

321

mintty + bash apt-cyg install netpbm apt-cyg install ImageMagick

Page 322: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

PNMからBMPへの変換

• ImageMagick を使った場合

322

mintty + bash $ ./a | convert - image.bmp

変換結果を保存する BMP ファイル名

パイプした結果を 標準入力から読み込む

pnm を テキスト出力する プログラム

Page 323: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 円の描画(1/2)

• pbm_practice_1.c の /*WYCH*/ の箇所を修正し、中心座標(0,0)半径rの円の内部を0外部を1とし x1,x2,y1,y2 の範囲について P1 形式の PBM 画像を出力するプログラムを作成せよ。

• ここでは円の内部をx2 + y2 < r2を定義し、境界部分は内部に含めない事とする。またx座標は右向き、y座標は下向きを正の方向とする。

323

Page 324: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 円の描画(2/2)

• 出力結果の例

324

mintty + bash $ gcc pbm_practice_1A.c && ./a x1 x2 y1 y2 r = -5 5 -5 5 4 P1 11 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

mintty + bash $ gcc pbm_practice_1A.c && ./a | convert - result.bmp x1 x2 y1 y2 r = -5 5 -5 5 4

r

x1 x2

y2

y1

y2-y1+1 (0,0)

Page 325: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

発展問題

• pbm_practice_1.c を改造して■▲★等を描いてみよう

325

Page 326: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

326

Page 327: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第6週

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

情報処理言語Ⅰ(実習を含む。)

327

Page 328: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列

第3週資料の復習

328

Page 329: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 同じ変数名で複数の要素を管理する

char a[10]; // 要素数10のchar型変数の宣言

教科書 pp.85-108.

a[0]

?

a[1]

?

a[2]

?

a[3]

?

a[9]

?

...

要素数10の添え字付き変数

初期値式が与えられなかった場合、値は不定

[1] pp.103-104., p.273.

329

Page 330: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 配列変数の要素への代入

char a[10]; // 要素数10のchar型変数の宣言 a[0] = 'a'; // 0番目の要素へ代入

教科書 pp.85-108.

a[0]

'a'

a[1]

?

a[2]

?

a[3]

?

a[9]

?

...

要素数10の添え字付き変数

初期値式が与えられなかったので、値は不定 宣言後の代入

[1] pp.103-104., p.273.

330

Page 331: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 添え字は値が取れれば変数や数式でも良い

int i = 1; char a[10]; // 要素数10のchar型変数の宣言 a[i + 1] = 'a'; // 2番目の要素へ代入

教科書 pp.85-108.

a[0]

?

a[1]

?

a[2]

'a'

a[3]

?

a[9]

?

...

要素数10の添え字付き変数 [1] pp.103-104., p.273.

331

Page 332: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 確保した領域外はアクセスは禁止

char a[10]; // 要素数10のchar型変数の宣言 short b = 0x1234; a[10] = 'a';// 宣言された領域外へのアクセス

教科書 pp.85-108.

a[0]

?

a[1]

?

a[2]

?

a[3]

?

a[9]

?

...

要素数10の添え字付き変数 [1] pp.103-104., p.273.

332

b

0x1234

a[10]

'a'

他の変数が使っていたらその値を壊してしまう

ここに書き込むと何が起こるか分からない

Page 333: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 初期値式による配列変数の初期化

char a[10] = {'a', 'b'}; //初期値式付きの //要素数10のchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

a[2]

0

a[3]

0

a[9]

0

...

要素数10の添え字付き変数

初期値式が要素数より少ない場合、残りは0で初期化 初期値式による初期化

[1] pp.103-104., p.273.

333

Page 334: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 初期値式による配列変数の初期化

char a[] = {'a', 'b'}; //初期値式付きで //要素数を省略したchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

初期値式の要素数分確保される

初期値式による初期化

[1] pp.103-104., p.273.

334

Page 335: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 文字列による初期化(要素数指定)

char a[10] = "ab"; //文字列による初期値付きの //要素数10のchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

a[2]

0

a[3]

0

a[9]

0

...

要素数10の添え字付き変数

初期値式が要素数より少ない場合、残りは0で初期化 文字列と文字列終端の'¥0'

[1] pp.103-104., p.273.

335

Page 336: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数

• 文字列による初期化(要素数自動決定)

char a[] = "ab";//文字列による初期値付きで //要素数を省略したchar型変数の宣言

教科書 pp.85-108.

a[0]

'a'

a[1]

'b'

a[2]

0

文字列の文字数+文字列終端'¥0'の1文字分の要素

文字列と文字列終端の'¥0'

[1] pp.103-104., p.273.

336

Page 337: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の初期化

• 明示的な初期化がない場合

• 外的変数、静的変数→0

• 自動変数、レジスタ変数→不定

• 初期化する場合

• 外的変数、静的変数←定数式でのみ初期化可

• コンパイル時に1度だけ初期化される

• 自動変数、レジスタ変数←任意の式で初期化可

• 実行時にブロック毎に初期化される

337

[1] pp.103-104., p.273.

Page 338: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数の初期化

• 要素数を与えない場合

• 初期値式の数で配列のサイズが決まる

• 要素数を与えた場合

• 初期値式を与えない場合

• 値は不定

• 初期値式を与える場合

• 要素数を超えるとエラー

• 要素数に足りない部分は0で初期化される

338

[1] pp.103-104., p.273.

Page 339: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列の初期化についての確認

配列の初期値と配列の初期化の範囲

339

Page 340: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認: a の値はどうなるか?(1/5)

• array_ex1.cを実行し以下の事を確認しなさい • s1: そのまま実行するとどうなるか?

• s2: 6行目の初期化だけアンコメント(途中の/*と*/を削除)するとどうなるか?

• s3: 7行目だけアンコメント(先頭の//を削除)するとどうなるか?

• s4: 上記6行目7行目の両方をアンコメントするとどうなるか

• 上記4つの場合において bcc32 の場合は -O2 オプション gcc の場合は -O3 をオプションを付けてコンパイルすると結果はどう変わるか?

340

-O2, -O3 は最適化(optimization) を施すためのオプションである。

Page 341: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認: a の値はどうなるか? (2/5)

• 以下の4通りの場合について確認

• 以下の4通りの場合について確認

341

array_ex1.c char a[4]/* = {'a', 'b'}*/; //a[0] = 'c';

6 7

array_ex1.c char a[4] = {'a', 'b'}; //a[0] = 'c';

6 7

array_ex1.c char a[4]/* = {'a', 'b'}*/; a[0] = 'c';

6 7

array_ex1.c char a[4] = {'a', 'b'}; a[0] = 'c';

6 7

mintty + bash + GNU C $ gcc array_ex1.c && ./a

mintty + bash + GNU C $ gcc -O3 array_ex1.c && ./a

cmd + BorlandC++ > bcc32 array_ex1.c && array_ex1

cmd + BorlandC++ > bcc32 -O2 array_ex1.c && array_ex1

全部で 4 * 4 = 16 パターン

s1 s2

s3 s4

c1 c2

c3 c4

Page 342: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認: a の値はどうなるか?(3/5)

• 例えばs3s3,s4c3の場合以下のようになる

342

mintty + bash + GNU C $ gcc -O3 array_ex1.c && ./a a[0]: 0x63: 'c' a[1]: 0xcb: '▒' a[2]: 0x22: '"' a[3]: 0x00: ''

s3c3

s3 の状態ではa[1]~a[3] に対し初期

化も代入もされていないので、たまたまこの値になっただけである点に注意。 つまりこの値は未定である。

mintty + bash + GNU C $ gcc -O3 array_ex1.c && ./a a[0]: 0x63: 'c' a[1]: 0x62: 'b' a[2]: 0x00: '' a[3]: 0x00: ''

s4c3 s4 の状態でも一見 a[2], a[3] に対し

初期化も代入もされていないように見えるが「初期値式が要素数より少ない場合、残りは0で初期化」という

ルールが適用されるためたため実際には確実に 0x00 となる事が保証される。

Page 343: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認: a の値はどうなるか?(4/5)

• 例えばs3s3,s3c1の場合以下のようになる

343

mintty + bash + GNU C $ gcc -O3 array_ex1.c && ./a a[0]: 0x63: 'c' a[1]: 0xcb: '▒' a[2]: 0x22: '"' a[3]: 0x00: ''

s3c3

mintty + bash + GNU C $ gcc array_ex1.c && ./a a[0]: 0x63: 'c' a[1]: 0x00: '' a[2]: 0x00: '' a[3]: 0x00: ''

s3c1

ソースコードは同じs1の状態なのにコ

ンパイル時のオプションの有無で値が変わっている点に注意。

このように未定の値は実行してみるまでどうなっているか分からない。

Page 344: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認: a の値はどうなるか?(5/5)

s 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

c 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4

a[0] 0x63 0x63 0x63

a[1] 0x00 0xcb 0x62

a[2] 0x00 0x20 0x00

a[3] 0x00 0x00 0x00

344

上記で赤字で示した箇所は本来未定となる箇所。

つまりたまたまその値になっただけに過ぎない点に注意。

Page 345: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ベクトルの演算

一次元配列の演習

345

Page 346: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: ベクトルの演算

• 𝒂, 𝒃 を𝑥, 𝑦, 𝑧の3次元ベクトルとしたときに以下の計算を行うプログラム作ってみましょう。

• 加算(add)、減算(sub)、 内積(dot product)、外積(cross product) 𝒂 + 𝒃 = 𝑎𝑥 + 𝑏𝑥 , 𝑎𝑦 + 𝑏𝑦 , 𝑎𝑧 + 𝑏𝑧

𝒂 − 𝒃 = 𝑎𝑥 − 𝑏𝑥 , 𝑎𝑦 − 𝑏𝑦 , 𝑎𝑧 − 𝑏𝑧𝒂 ⋅ 𝒃 = 𝑎𝑥𝑏𝑥 + 𝑎𝑦𝑏𝑦 + 𝑎𝑧𝑏𝑧

𝒂 × 𝒃 = 𝑎𝑦𝑏𝑧 − 𝑎𝑧𝑏𝑦 , 𝑎𝑧𝑏𝑥 − 𝑎𝑥𝑏𝑧, 𝑎𝑥𝑏𝑦 − 𝑎𝑦𝑏𝑥

346

Page 347: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: ベクトルの演算

• 結果は result[0] または result[0~2] に格納しましょう。numresult を適宜設定してください。

• 雛形(vector_xxx_practice_1.c)をダウンロードして指定された箇所に実装してください。

• ファイル名は、以下の名前にしましょう。 • 加算: vector_add_practice_1.c

• 減算: vector_sub_practice_1.c

• 内積: vector_dot_practice_1.c

• 外積: vector_cross_practice_1.c

347

Page 348: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: ベクトルの演算

• 動作テスト用のスクリプト

• 加算: vector_add_practice_1_test.sh

• 減算: vector_sub_practice_1_test.sh

• 内積: vector_dot_practice_1_test.sh

• 外積: vector_cross_practice_1_test.sh

348

Page 349: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: ベクトルの演算

• ヒント: 書き方はいろいろある。

349

ループを用いない add result[0] = a[0] + b[0]; result[1] = a[1] + b[1]; result[2] = a[2] + b[2];

ループを用いた add for (i = 0; i < M; i++) { result[i] = a[i] + b[i]; }

Page 350: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

350

Page 351: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第7週

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

情報処理言語Ⅰ(実習を含む。)

351

Page 352: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多次元配列

352

Page 353: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多次元の値も扱いたい

• 例えば行列の演算(1,2次元混合) 𝐴𝑥 = 𝑏

𝑎1,1 … 𝑎1,𝑛⋮ ⋱ ⋮𝑎𝑚,1 … 𝑎𝑚,𝑛

𝑥1⋮𝑥𝑛 =𝑏1⋮𝑏𝑚

行列は2次元 ベクトルは1次元

353

Page 354: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多次元の値も扱いたい

• 例えば白黒や濃淡画像(2次元)

354

0 32 64 128

32 64 128 192

128 128 192 255

0 32 64 128

32 64 128 192

128 128 192 255

x,y座標の各点をマス目で表し 各マス目の明るさを 256段階(8bit)の数値で表す 輝度値や明度値と言う

それぞれのマス目の数値に応じて 光らせる明るさを調整すると 絵が描ける

Page 355: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多次元の値も扱いたい

• 例えば白黒や濃淡画像(3次元)

355

255 0 0 255 255 0 0 255 0

255 0 255 0 0 255 0 255 255

x,y座標の各点の 光の三原色 赤緑青の明るさ(RGB値)を 数値で表す

画面を虫眼鏡で見ると こんな感じに 光っているのが見える

Page 356: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

多次元の値も扱いたい

• 例えば白黒や濃淡画像(3次元)

356

255 0 0 255 255 0 0 255 0

255 0 255 0 0 255 0 255 255

遠目で見た場合や ソフトウェア上では 色が混ざって このように見える

Page 357: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

画面表示の仕組み

• 方眼紙のような構造

• 光の三原色(RGB=赤緑青)で加法混色

• 通常、各色8bit(256段階)で電圧調整して明暗表現

• 計24bit(16,777,216色)=8bit×3(256×256×256 段階)

357

Page 358: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

混色

• 加法混色

• 画面、光

• RGBカラーモデル • Red, Green, Blue

• 減法混色

• 印刷、絵の具

• CMYカラーモデル • Cyan, Magenta, Yellow

M

C

Y R

G B

Bk

R

G B

M

C

Y

W

358

Page 359: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

メモリの構成

• メモリのアドレスは1次元でした

0x00 0x00000000

0x00 0x00000001

0x00 0x00000002

0x00 0x00000003

0x00 0xffffffff

: :

: :

0x00 0x0000000000000000

0x00 0x0000000000000001

0x00 0x0000000000000002

0x00 0x0000000000000003

0x00 0xffffffffffffffff

: :

: :

32bitのOSは32bitのアドレス空間 最大232Bytes=4GiB

64bitのOSは64bitのアドレス空間 最大264Bytes=16EiB

アドレス 格納値 アドレス 格納値

教科書 pp.52-56. 359

Page 360: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

二次元配列変数

• 1次元のメモリを折り畳んで2次元にして使う

char a[3][4]; // 要素数3*4のchar型変数の宣言

教科書 pp.85-108.

a[0][0]

?

a[0][1]

?

a[0][2]

?

a[0][3]

?

1行分のデータ メモリのアドレスは1次元なので 実際には2行目以降も 直線状に並んでいる

[1] pp.135-137.

360

a[1][0]

?

a[1][1]

?

a[2][3]

?

...

Page 361: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

二次元配列変数

• 要素数4の配列を3つ並べた例

char a[3][4]; // 要素数3*4のchar型変数の宣言

教科書 pp.85-108.

a[0][0]

?

a[0][1]

?

a[0][2]

?

a[0][3]

?

論理的には 2次元的に並んでいると 考えて使えば良い。

[1] pp.135-137.

361

a[1][0]

?

a[1][1]

?

a[1][2]

?

a[1][3]

?

a[2][0]

?

a[2][1]

?

a[2][2]

?

a[2][3]

?

Page 362: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

行列の行と列

• m行n列の行列

𝑎1,1 … 𝑎1,𝑛⋮ ⋱ ⋮𝑎𝑚,1 … 𝑎𝑚,𝑛

1列 ・・・ n列

1行 : :

m行

362

Page 363: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

Row-major と Column-major

• 本来1次元のメモリをどう区切って使うか?

• 行を連続にするか?列を連続にするか?

𝑎1,1 … 𝑎1,𝑛⋮ ⋱ ⋮𝑎𝑚,1 … 𝑎𝑚,𝑛

𝑎1,1 … 𝑎1,𝑛⋮ ⋱ ⋮𝑎𝑚,1 … 𝑎𝑚,𝑛

1列 ・・・ n列

1行 : :

m行

1列 ・・・ n列

Row-major は行方向の要素が メモリ上で連続に並ぶ C言語はこのタイプ

Column-major は列方向の要素が メモリ上で連続に並ぶ Fortran等はこのタイプ

363

Page 364: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

a[0][0]

a[0][1]

a[0][2]

a[0][3]

:

a[1][0]

a[1][1]

a[1][2]

a[2][3]

a[0][0]

a[1][0]

a[2][0]

a[0][1]

a[1][1]

a[2][1]

a[0][2]

a[1][2]

a[2][2]

a[0][3]

a[1][3]

a[2][3]

メモリ上の配列と二次元配列(行列)

• Row-major は同じ行が繋がっている

a[0][0]

a[0][1]

a[0][2]

a[0][3]

:

a[1][0]

a[1][1]

a[1][2]

a[2][3]

a[0][0]

a[1][0]

a[2][0]

a[0][1]

a[1][1]

a[2][1]

a[0][2]

a[1][2]

a[2][2]

a[0][3]

a[1][3]

a[2][3]

: : :

C言語はこのタイプ

364

Row-major int a[m * n]; a[n * i + j];

二次元配列 int a[m][n]; a[i][j];

訂正: 2015-06-20 誤: a[m * i + j] 正: a[n * i + j]

Page 365: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

a[0][0]

a[1][0]

a[2][0]

a[0][1]

:

a[1][1]

a[2][1]

a[0][2]

a[2][3]

a[0][0]

a[1][0]

a[2][0]

a[0][1]

a[1][1]

a[2][1]

a[0][2]

a[1][2]

a[2][2]

a[0][3]

a[1][3]

a[2][3]

メモリ上の配列と二次元配列(行列)

• Column-major は同じ列が繋がっている

a[0][0]

a[1][0]

a[2][0]

a[0][1]

a[1][1]

a[2][1]

a[0][0]

a[1][0]

a[2][0]

a[0][1]

a[1][1]

a[2][1]

a[0][2]

a[1][2]

a[2][2]

a[0][3]

a[1][3]

a[2][3]

a[0][2]

: :

a[2][3] Fortran等はこのタイプ

365

Column-major int a[m * n]; a[i + j * m];

二次元配列 int a[m][n]; a[i][j];

訂正: 2015-06-20 誤: a[i + j * n] 正: a[i + j * m]

Page 366: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

二次元配列のメモリ上の配置

• Row-major と Column-major

教科書 pp.85-108.

a[0][0]

?

a[0][1]

?

a[0][2]

?

a[0][3]

?

1列分のデータ

[1] pp.135-137.

366

a[1][0]

?

a[1][1]

?

a[2][3]

?

...

a[0][0]

?

a[1][0]

?

a[2][0]

?

a[0][1]

?

a[1][1]

?

a[2][1]

?

a[2][3]

?

...

1行分のデータ

Row-major は行方向の要素が連続に並ぶ C言語はこのタイプ

Column-major は列方向の要素が連続に並ぶ Fortran等はこのタイプ

Page 367: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

三次元配列変数

• 1次元のメモリを折り畳んで3次元にして使う

char a[2][3][4]; // 要素数2*3*4のchar型変数の宣言

教科書 pp.85-108.

[0][0][0]

?

[0][0][1]

?

[0][0][2]

?

[0][0][3]

?

1行分のデータ メモリのアドレスは1次元なので 実際には2行目以降も 直線状に並んでいる

[1] pp.135-137.

367

[0][1][0]

?

[0][1][1]

?

[1][2][3]

?

...

Page 368: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

三次元配列変数

• 要素数3*4の配列を2つ並べた例

char a[2][3][4]; // 要素数2*3*4のchar型変数の宣言

教科書 pp.85-108.

[0][0][0]

?

[0][0][1]

?

[0][0][2]

?

[0][0][3]

?

[1] pp.135-137.

368

[0][1][0]

?

[0][1][1]

?

[0][1][2]

?

[0][1][3]

?

[0][2][0]

?

[0][2][1]

?

[0][2][2]

?

[0][2][3]

?

[1][0][0]

?

[1][0][1]

?

[1][0][2]

?

[1][0][3]

?

[1][1][0]

?

[1][1][1]

?

[1][1][2]

?

[1][1][3]

?

[1][2][0]

?

[1][2][1]

?

[1][2][2]

?

[1][2][3]

?

Page 369: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列変数の使用例

• 同じ次元・要素数でもいろんな解釈で使える

char a[3][4];

教科書 pp.85-108. 369

char a[2][3][4];

a[ch][t];

a[t][x];

a[y][x];

a[t][y][x];

a[z][y][x];

Page 370: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

行列の演算

二次元配列の演習

370

Page 371: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 行列とベクトルの演算

• 𝐴 を3×3の行列、 𝒃, 𝒙 を3次元のベクトルとしたときに以下の計算を行うプログラム作ってみましょう。

• 積(matrix_vector_mul_practice_1.c)

𝒃 = 𝐴𝒙: 𝑏𝑖 = 𝑎𝑖,𝑗𝑥𝑗

𝑛

𝑗=1

371

Page 372: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 行列の演算

• 𝐴, 𝐵 を3×3の行列としたときに以下の計算を行うプログラム作ってみましょう。

• 加算(add)、減算(sub)、要素単位の乗算(times)、行列乗算(mtimes)、 転置(transpose) • 加算: 𝐶 = 𝐴 + 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑗 + 𝑏𝑖,𝑗

• 減算: 𝐶 = 𝐴 − 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑗 − 𝑏𝑖,𝑗

• 要素単位の乗算: 𝐶 = 𝐴.∗ 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑗𝑏𝑖,𝑗

• 行列乗算: 𝐶 = 𝐴 ∗ 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑘𝑏𝑘,𝑗𝑚𝑘=1

• 転置: 𝐶 = 𝐴𝑇: 𝑐𝑖,𝑗 = 𝑎𝑗,𝑖

372

訂正: 2015-06-20 誤: 𝐶 = 𝐴 + 𝐵 正: 𝐶 = 𝐴.∗ 𝐵

訂正: 2015-06-20 誤: 𝐶 = 𝐴 + 𝐵 正: 𝐶 = 𝐴 ∗ 𝐵

Page 373: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 行列の演算

• matrix_vector_xxx_practice_1.c を元にして以下のファイル名で作成せよ

• 加算: matrix_vector_add_practice_1.c

• 減算: matrix_vector_sub_practice_1.c

• 要素単位の乗算: matrix_vector_times_practice_1.c

• 行列乗算: matrix_vector_mtimes_practice_1.c

• 転置: matrix_vector_transpose_practice_1.c

373

Page 374: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て

重複した処理をループにまとめる

数式をループに変換する

374

Page 375: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 重複した処理をまとめる

375

sum = 1 + 1 + 1 + 1 + 1;

追加: 2015-06-20

sum = 1 + 1 + 1 + 1 + 1;

sum = 1; sum += 1; sum += 1; sum += 1; sum += 1;

演算を構成する項を縦に並べる

各項を単文で書き直す sum = 0; // 初期化 sum += 1; sum += 1; sum += 1; sum += 1; sum += 1;

5回繰り返している

sum = 0; // 初期化 for (i = 0; i < 5; i++) { sum += 1; }

積算の場合 初期値を与えて 各単文を 全く同じ処理の 繰り返しにする

Page 376: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 重複した処理をまとめる

376

sum = 1 + 2 + 3 + 4 + 5;

追加: 2015-06-20

sum = 1 + 2 + 3 + 4 + 5;

sum = 1; sum += 2; sum += 3; sum += 4; sum += 5;

演算を構成する項を縦に並べる

ループカウンタを活用する

sum = 0; // 初期化 sum += 1; sum += 2; sum += 3; sum += 4; sum += 5;

1~5まで増えている

sum = 0; // 初期化 for (i = 1; i <= 5; i++) { sum += i; }

積算の場合 初期値を与えて 各単文を 全く同じ処理の 繰り返しにする

各項を単文で書き直す

Page 377: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 重複した処理をまとめる

377

sum = a[0]*b[0]+a[1]*b[1]+・・・+a[N-1]*b[N-1];

追加: 2015-06-20

sum = a[0]*b[0] + a[1]*b[1] ⋮ ⋮ + a[N-1]*b[N-1];

sum = a[0]*b[0]; sum += a[1]*b[1]; ⋮ ⋮ sum += a[N-1]*b[N-1];

演算を構成する項を縦に並べる

各項を単文で書き直す sum = 0; // 初期化 sum += a[0]*b[0]; sum += a[1]*b[1]; ⋮ ⋮ sum += a[N-1]*b[N-1];

積算の場合 初期値を与えて 各単文を 全く同じ処理の 繰り返しにする

sum = 0; // 初期化 for (i = 0; i < N; i++) { sum += a[i]*b[i]; }

0~N-1 まで 増えて いる

ループカウンタを活用する

Page 378: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 数式とC言語の対応を考える

• 数式

• C言語

378

𝑖の積算 s = 0; for (i = 1; i <= n; i++) { s += i; }

𝑠 = 𝑖

𝑛

𝑖=1

1の積算 s = 0; for (i = 1; i <= n; i++) { s += 1; }

𝑠 = 1

𝑛

𝑖=1

積算項: 1 ↔ 𝑖

定石の書き方から変形

追加: 2015-06-20 加筆: 2015-06-26

Page 379: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 数式とC言語の対応を考える

• 数式

• C言語

379

𝑎𝑖,𝑗𝑥𝑗の積算

b[i] = 0; for (j = 1; j <= n; j++) { b[j] += a[i][j] * x[j]; }

𝑏𝑖 = 𝑎𝑖,𝑗𝑥𝑗

𝑛

𝑗=1

𝑖の積算 s = 0; for (i = 1; i <= n; i++) { s += i; }

𝑠 = 𝑖

𝑛

𝑖=1

結果: 𝑠 → 𝑏𝑖 カウンタ: 𝑖 → 𝑗 積算項: 𝑖 → 𝑎𝑖,𝑗𝑥𝑗

定石の書き方から変形

追加: 2015-06-20 加筆: 2015-06-26

Page 380: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 数式とC言語の対応を考える

• 数式

• C言語

380

𝑎𝑖,𝑗𝑥𝑗の積算

b[i] = 0; for (j = 0; j < n; j++) { b[j] += a[i][j] * x[j]; }

追加: 2015-06-20 加筆: 2015-06-26

𝑏𝑖 = 𝑎𝑖,𝑗𝑥𝑗

𝑛−1

𝑗=0

要素数𝑛個の数列や配列は 数学では 𝑎1⋯𝑎𝑛 と書く場合が多いが C言語では a[0]⋯a[n-1] になる

C言語に合わせて 添え字を1つずらす

単純に置きかえ 範囲: 1: 𝑛 → 0: 𝑛 − 1 → 0: 𝑛

𝑎𝑖,𝑗𝑥𝑗の積算

b[i] = 0; for (j = 1; j <= n; j++) { b[j] += a[i][j] * x[j]; }

𝑏𝑖 = 𝑎𝑖,𝑗𝑥𝑗

𝑛

𝑗=1

Page 381: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ループの組み立て 数式とC言語の対応を考える

• 数式

• C言語

381

𝑎𝑖,𝑗𝑥𝑗の積算

b[i] = 0; for (j = 0; j < n; j++) { b[j] += a[i][j] * x[j]; }

追加: 2015-06-20 加筆: 2015-06-26

𝑏𝑖 = 𝑎𝑖,𝑗𝑥𝑗

𝑛−1

𝑗=0

全ての𝑏𝑖についてループして計算

𝑎𝑖,𝑗𝑥𝑗の積算

for (i = 0; i < m; i++) { b[i] = 0; for (j = 0; j < n; j++) { b[j] += a[i][j] * x[j]; } }

Page 382: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

382

Page 383: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第8週

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

情報処理言語Ⅰ(実習を含む。)

383

Page 384: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義と関数呼び出し

384

Page 385: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数の宣言・定義・利用

• 書式:

385

関数の定義 戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 }

関数の宣言 戻り値の型 関数名(引数の宣言, ...);

関数の利用 変数名 = 関数名(引数, ...);

.h ファイルへ書き出す

.c ファイルへ書き出す

適宜呼び出す

教科書 pp.149-160.

Page 386: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数(サブルーチン)

• C 言語は処理を関数にしてまとめる

• main も関数

386

c_template.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { // Here is a main routine. return EXIT_SUCCESS; }

フルセットの main 関数

関数名、引数、戻り値の定義

関数の本体

コマンドライン引数の数

コマンドライン引数を格納した 複数の文字列へのポインタ

教科書 pp.149-160.

Page 387: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

(ユーザー定義)関数

• 関数は自分で作ることが出来る

• 機能、分量等、ある程度まとまった処理は 関数にまとめる

• 可読性が向上する

• 再利用が容易になる

• 関数の定義の書式:

387

戻り値の型 関数名(引数の宣言, ...) { // 関数に行わせる処理 // ... return 戻り値; // 戻り値の型がvoidの場合は不要 }

教科書 pp.149-160.

C言語の関数は 0個以上の引数と 0または1個の戻り値を持つ。 引数や戻り値が不要な場合は void を宣言するよう 推奨されている。

Page 388: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

return 文

return 戻り値;

• 関数から抜けて呼び出し元へ戻り値を渡す return_ex1.c int sub() { return 123; printf("hello¥n"); } void main() { int x = sub(); printf("%d¥n", x); }

return文に与えた値が 関数の戻り値になり 演算に使用される return文を実行すると

呼び出し元に戻るので それ以降の文は 実行されない

mintty + bash + GNU C $ gcc return_ex1.c && ./a 123

Page 389: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

return 文

• 戻り値の型は必要に応じて適切な型を選ぶ

return_ex2.c int sub() { return 1.23; } void main() { double x = sub(); printf("%f¥n", x); }

この例では戻り値の型はintなので return文にdoubleを与えても 戻り値はint型にキャストされるので 整数になる

mintty + bash + GNU C $ gcc return_ex2.c && ./a 1.000000

例えばもし 浮動小数点数の値を 戻したいなら 戻り値の型は doubleでないといけない

訂正2015-06-26 誤: double = sub(); 正: double x = sub();

Page 390: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数のプロトタイプ宣言

• 関数は使う前に宣言されている必要がある prototype_ex1_err.c void main() { double x = sub(); printf("%f¥n", x); } double sub() { return 1.23; }

mintty + bash + GNU C $ gcc prototype_ex1_err.c prototype_ex1_err.c:9:8: エラー: ‘sub’ と型が競合しています double sub() ^ prototype_ex1_err.c:5:14: 備考: 前の ‘sub’ の暗黙的な宣言はここです double x = sub(); ^

異なる引数や戻り値で同名の関数は 関数名が競合するため利用出来ない

未宣言の関数の引数や戻り値は int型を仮定して暗黙的に宣言される

Page 391: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数のプロトタイプ宣言

• 関数は使う前に宣言されている必要がある prototype_ex1.c

double sub(); void main() { double x = sub(); printf("%f¥n", x); } double sub() { return 1.23; }

int型以外の引数や戻り値を持つ関数は あらかじめプロトタイプ宣言されていなければならない

mintty + bash + GNU C $ gcc prototype_ex1.c && ./a 1.230000

Page 392: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

(ユーザー定義)関数の例

• 閏年の判定を関数にまとめてみる

392

leap_year_func_ex4_2.c #include <stdio.h> #include <stdlib.h> int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } int main() { int year; fprintf(stderr, "year = ?¥b"); scanf("%d", &year); printf("%d is%s leap year.¥n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; }

関数の定義

自分で作成した関数を サブルーチンとして呼ぶ

教科書 pp.149-160.

Page 393: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

(ユーザー定義)関数の例

• 関数を使う前にはパラメータの型と数が 分かっている必要がある(コンパイラの都合)

393

#include <stdio.h> #include <stdlib.h> int main() { int year; fprintf(stderr, "year = ?¥b"); scanf("%d", &year); printf("%d is%s leap year.¥n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; } int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; }

使う時点で不明な戻り値の型はintを仮定される。 引数については何も仮定しない。 もし、実際に定義されている関数の型が異なると 型が競合してエラーになる。

教科書 pp.153-160.

型が不明なので、このタイミングで int is_leap_year(int); が仮定される。

[1] pp.86-89.

Page 394: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数のプロトタイプ宣言

• 関数は使う前にプロトタイプ宣言する

394

#include <stdio.h> #include <stdlib.h> int is_leap_year(int year); int main() { int year; fprintf(stderr, "year = ?¥b"); scanf("%d", &year); printf("%d is%s leap year.¥n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; }

関数のプロトタイプ宣言さえしておけば 関数の定義はどこにあっても良い。 例えば外部のファイルにあっても良い。

教科書 pp.149-160.

関数のプロトタイプ宣言 戻り値の型、引数の数と型を宣言する

Page 395: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数をファイルに分離する

• 再利用性が高まる(コピペしなくて良くなる)

395

is_leap_year_func_ex4_2.c #include "is_leap_year_func.h" int is_leap_year(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; }

is_leap_year_func.h #ifndef IS_LEAP_YEAR_FUNC_H #define IS_LEAP_YEAR_FUNC_H int is_leap_year(int year); #endif

ヘッダファイル

関数の宣言 他所から使う際に、 関数名、引数、戻り値の 情報を得るために必要

include ガード(二重includeを防ぐ)

関数本体のソースファイル

教科書 pp.203-206.

関数本体の定義

Page 396: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルに分離した関数の利用

• main 関数の部分

396

is_leap_year_main.c #include <stdio.h> #include <stdlib.h> #include "is_leap_year_func.h" int main() { int year; fprintf(stderr, "year = ?¥b"); scanf("%d", &year); printf("%d is%s leap year.¥n", year, is_leap_year(year) ? "" : " not"); return EXIT_SUCCESS; }

ヘッダファイルの include

外部ファイルで定義した 関数を呼び出し

教科書 pp.203-206.

Page 397: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• コンパイルする複数のCのソースファイルを コンパイラに与えれば良い

分割コンパイル

397

mintty + bash + GNU C $ gcc is_leap_year_main.c is_leap_year_func_ex4_2.c

コマンドプロンプト + Borland C++ >bcc32 is_leap_year_main.c is_leap_year_func_ex4_2.c

与えるのはCのソースファイルのみ ヘッダファイルは #include 文により 自動的に取り込まれる

Page 398: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プリプロセッサ

• 条件付きコンパイル

398

#if 定数式 #elif 定数式 #else #endif #if 0 // ここはコンパイルされない #endif #if defined(__BORLANDC__) // __BORLANDC__ という名前のマクロが // 定義されていた場合のみコンパイルされる #endif #if defined(__BORLANDC__) && 0x0551 <= __BORLANDC__ // ... #endif

条件に合った箇所のみを コンパイラに渡す構文

定数式の結果は0と非0の真偽値

定数式なら 演算も可能

Page 399: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プリプロセッサ

• 条件付きコンパイル

399

#ifdef __BORLANDC__ // ... #endif #ifndef __BORLANDC__ // ... #endif

#if defined( ) の短縮表記

#if !defined( ) の短縮表記

Page 400: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

プリプロセッサ

• 定義済みマクロ

400

__LINE__ 現在の行番号 __FILE__ 現在のファイル名 __func__ 現在の関数名(C99) __FUNC__ 現在の関数名(Borland C++) #ifdef __BORLANDC__ #define __func__ __FUNC__ #endif

Borland C++ で C99互換の定義済みマクロが 使えるようにする 条件付きコンパイル

Page 401: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数をファイルに分離する

• 作業用変数を用いる場合

401

is_leap_year_func_ex1_1.c #include "is_leap_year_func.h" int is_leap_year(int year) { int leap_year_flag; if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { leap_year_flag = 1; } else { leap_year_flag = 0; } } else { leap_year_flag = 1; } } else { leap_year_flag = 0; } return leap_year_flag; }

教科書 pp.203-206.

ここは leap_year_practice_2.c そのまま

結果を戻り値として返す

ローカル変数の宣言

ローカル変数 ブロック内の作業用。 ブロック外に 同じ名前の変数があっても 競合せず安全に使える。

ブロック(複文) { } で囲まれた領域の事

Page 402: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

• 関数のプロトタイプ宣言が同じなら関数は差し替えて使える。

関数の差し替え

402

mintty + bash + GNU C $ gcc is_leap_year_main.c is_leap_year_func_ex4_2.c

mintty + bash + GNU C $ gcc is_leap_year_main.c is_leap_year_func_ex1_1.c

実装は異なるが プロトタイプ宣言が同じ関数を 定義したファイルで差し替え

Page 403: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数のスコープ(有効範囲)

• 大域(グローバル)変数

• プログラム全体からアクセス可能

• 局所(ローカル)変数

• ブロック内からのみアクセス可能

403 教科書 pp.161-169.

C言語では { } で 囲まれた部分がブロック

Page 404: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数のスコープ(有効範囲)

• ローカル変数は{}の中のみで有効

404

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

関数外で宣言するとグローバル変数

教科書 pp.161-169.

関数の引数はローカル変数

ブロックを作成するとローカル変数の有効範囲を制限出来る

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

Page 405: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数のスコープ(有効範囲)

• ローカル変数は{}の外側に影響していない

405

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

教科書 pp.161-169.

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

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

Page 406: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数の演習

• is_leap_year_func_ex1_1.c、is_leap_year_func_ex4_2.c を参考に以下のファイルの処理を関数にしてファイルに分離してみましょう。 • leap_year_ex1_2.c → is_leap_year_func_ex1_2.c

• leap_year_ex2_1.c → is_leap_year_func_ex2_1.c

• leap_year_ex2_2.c → is_leap_year_func_ex2_2.c

• leap_year_ex3_1.c → is_leap_year_func_ex3_1.c

• leap_year_ex3_2.c → is_leap_year_func_ex3_2.c

• leap_year_ex4_1.c → is_leap_year_func_ex4_1.c

• is_leap_year_main.c と一緒にコンパイルしてみて動作を確認してみましょう。

406 教科書 pp.203-206.

Page 407: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

407

Page 408: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第9週

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

情報処理言語Ⅰ(実習を含む。)

408

Page 409: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数の設計

409

Page 410: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 1~nの和

• 1~nの和

𝑖

𝑛

𝑖=1

= 1 + 2 +⋯+ 𝑛

を求めるプログラムを考える。

• 知っているやり方 • ループを使ってi=1~nまで増やしながら足す • 和の公式を計算する

𝑖

𝑛

𝑖=1

=𝑛 𝑛 + 1

2

410 教科書 pp.190-197.

Page 411: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 1~nの和

• まず、何も考えずにループで書いてみる

411

sum_ex1_for.c #include <stdio.h> void main() { int i, n; int sum = 0; fprintf(stderr, "n = ?¥b"); scanf("%d", &n); for (i = 1; i <= n; i++) { sum += i; } printf("%d¥n", sum); }

教科書 pp.190-197.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

mintty + bash + GNU C $ gcc sum_ex1_for.c && ./a <<<10 n = 55

main 関数の中に すべての処理を入れた状態

Page 412: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 1~nの和

• main 関数と sum 関数に分割してみる

412

sum_ex2_for.c #include <stdio.h> int sum(int n) { int i; int sum = 0; for (i = 1; i <= n; i++) { sum += i; } return sum; }

教科書 pp.190-197.

sum_ex2_for.c void main() { int n; fprintf(stderr, "n = ?¥b"); scanf("%d", &n); printf("%d¥n", sum(n)); }

1 2 3 4 5 6 7 8 9 10 11 12

14 15 16 17 18 19 20 21 22

ファイルはまだ、1ファイルのまま 分けてない状態

mintty + bash + GNU C $ gcc sum_ex2_for.c && ./a <<<10 n = 55

Page 413: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 1~nの和

• main と sum を 2 ファイルに分割してみる

413

sum_ex3_for.c int sum(int n) { int i; int sum = 0; for (i = 1; i <= n; i++) { sum += i; } return sum; }

教科書 pp.190-197.

sum_ex3_main.c #include <stdio.h> int sum(int n); void main() { int n; fprintf(stderr, "n = ?¥b"); scanf("%d", &n); printf("%d¥n", sum(n)); }

1 2 3 4 5 6 7 8 9 10

1 2 3 4 5 6 7 8 9 10 11 12 13

mintty + bash + GNU C $ gcc sum_ex3_main.c sum_ex3_for.c && ./a <<<10 n = 55

Page 414: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 1~nの和

• ヘッダファイルも作ってみる

414

sum_ex4_for.c include "sum_ex4.h" int sum(int n) { int i; int sum = 0; for (i = 1; i <= n; i++) { sum += i; } return sum; }

教科書 pp.190-197.

sum_ex4_main.c #include <stdio.h> #include "sum_ex4.h" void main() { int n; fprintf(stderr, "n = ?¥b"); scanf("%d", &n); printf("%d¥n", sum(n)); }

1 2 3 4 5 6 7 8 9 10 11 12

1 2 3 4 5 6 7 8 9 10 11 12

mintty + bash + GNU C $ gcc sum_ex4_main.c sum_ex4_for.c && ./a <<<10 n = 55

sum_ex4.h #ifndef SUM_EX4_H #define SUM_EX4_H int sum(int n); #endif//SUM_EX4_H

1 2 3 4

訂正2015-06-26 追加: 2行目: #define SUM_EX4_H

Page 415: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 1~nの和

• 別の方法で関数を実装し直してみる

415

sum_ex4_formula.c #include "sum_ex4.h" int sum(int n) { return n * (n + 1) / 2; }

教科書 pp.190-197.

sum_ex4_main.c #include <stdio.h> #include "sum_ex4.h" void main() { int n; fprintf(stderr, "n = ?¥b"); scanf("%d", &n); printf("%d¥n", sum(n)); }

1 2 3 4 5 6

1 2 3 4 5 6 7 8 9 10 11 12

sum_ex4.h #ifndef SUM_EX4_H #define SUM_EX4_H int sum(int n); #endif//SUM_EX4_H

1 2 3 4

mintty + bash + GNU C $ gcc sum_ex4_main.c sum_ex4_formula.c && ./a <<<10 n = 55

sum 関数だけ差し替え

訂正2015-06-26 追加: 2行目: #define SUM_EX4_H

Page 416: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

再帰(RECURSION)

自分自身を呼び出す関数

416

Page 417: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 再帰による1~nの和

• 1~nの和

𝑖

𝑛

𝑖=1

= 1 + 2 +⋯+ 𝑛

を求めるプログラムを考える。

• 知っているやり方 • ループを使ってi=1~nまで増やしながら足す • 和の公式を計算する

𝑖

𝑛

𝑖=1

=𝑛 𝑛 + 1

2

• 他にもやり方がある?

417 教科書 pp.190-197.

Page 418: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 再帰による1~nの和

• 1~nの和は以下のように1~n-1の和とnに分解出来る

𝑖

𝑛

𝑖=1

= 1 + 2 +⋯+ 𝑛 − 1 + 𝑛

つまり

𝑖 = 𝑖

𝑛−1

𝑖=1

+ 𝑛 : 1 < 𝑛

1 : (𝑛 = 1)

𝑛

𝑖=1

これを関数にしてみると・・・

418 教科書 pp.190-197.

Page 419: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 再帰による1~nの和

• 1~n-1とnに分けて計算してみる

419

sum_ex4_recursion.c #include "sum_ex4.h" int sum(int n) { if (n == 1) { return 1; } return sum(n - 1) + n; }

教科書 pp.190-197.

sum_ex4_main.c #include <stdio.h> #include "sum_ex4.h" void main() { int n; fprintf(stderr, "n = ?¥b"); scanf("%d", &n); printf("%d¥n", sum(n)); }

1 2 3 4 5 6 7 8 9

1 2 3 4 5 6 7 8 9 10 11 12

mintty + bash + GNU C $ gcc sum_ex4_main.c sum_ex4_recursion.c && ./a <<<10 n = 55

n-1 にして 自分自身を呼んでいる 再帰的処理

sum 関数だけ差し替え

sum_ex4.h #ifndef SUM_EX4_H #define SUM_EX4_H int sum(int n); #endif//SUM_EX4_H

1 2 3 4

訂正2015-06-26 追加: 2行目: #define SUM_EX4_H

Page 420: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

階乗(FACTORIAL)の計算

関数の演習

420

Page 421: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

階乗 (factorial)関数

• 考え方

• ループの場合

𝑛! = 1 ⋅ 1 ⋅ 2⋯ 𝑛 − 1 ⋅ 𝑛𝑛

• 再帰の場合 𝑛! = 𝑛 ⋅ 𝑛 − 1 !

𝑛 − 1 ! = 𝑛 − 1 ⋅ 𝑛 − 2 !⋮

1! = 1 ⋅ 0!0! = 1

421

再帰の場合は 1つ小さな値を 引数にして 自分で自身を呼ぶ だけ

それ以上小さく 出来なくなったら ルールに沿って 適当な値を返す

ループの場合はこの数列を作り𝑛個積算していく

教科書 pp.190-197.

Page 422: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: factorial_practice1_for.c

• int型の整数𝑛について階乗(factorial) 𝑛!を求める関数factorial(n)をforループを用いてfactorial_practice1_for.cに実装せよ

• main関数とヘッダは、factorial_practice1_main.c 及び factorial_practice1.h に用意してある。

• 引数 • int n : 整数

• 戻り値 • 𝑛! をint型で返せ

422 教科書 pp.190-197.

訂正2015-06-26 誤: factoriali 正: factorial

Page 423: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: factorial_practice1_recursion.c

• int型の整数𝑛について階乗(factorial) 𝑛!を求める関数factorial(n)を再帰を用いてfactorial_practice1_recursion.c に実装せよ

• main関数とヘッダは、factorial_practice1_main.c 及び factorial_practice1.h に用意してある。

• 引数 • int n : 整数

• 戻り値 • 𝑛! をint型で返せ

423 教科書 pp.190-197.

訂正2015-06-26 誤: factoriali 正: factorial

Page 424: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: factorial_practice1_*.c

• 実行例

424

mintty + bash + GNU C $ gcc factorial_practice1_main.c factorial_practice1_for.c && ./a <<<5 n = 120

mintty + bash + GNU C $ gcc factorial_practice1_main.c factorial_practice1_recursion.c && ./a <<<5 n = 120

訂正2015-06-26 誤: factoriali 正: factorial

Page 425: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子

通用範囲、格納場所、初期化の違い

425

Page 426: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の初期化

• 明示的な初期化がない場合

• 外的変数、静的変数→0

• 自動変数、レジスタ変数→不定

• 初期化する場合

• 外的変数、静的変数←定数式でのみ初期化可

• コンパイル時に1度だけ初期化される

• 自動変数、レジスタ変数←任意の式で初期化可

• 実行時にブロック毎に初期化される

426

[1] pp.103-104., p.273.

Page 427: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子による 通用範囲と格納場所と初期化

関数外 関数内 備考

無指定

広域的 メインメモリー 定数でコンパイル時1回

局所的 スタック 変数可、実行時毎回

標準的な 外部変数と内部変数

auto

局所的 スタック 変数可、実行時毎回

register

局所的 レジスタまたはスタック 変数可、実行時毎回

アドレス演算子使用不可

extern

広域的 メインメモリー 宣言のみ可能

広域的 メインメモリー 宣言のみ可能

初期化不可 (定義時に初期化済み)

static

広域的(ファイル内限定) メインメモリー 定数でコンパイル時1回

局所的 メインメモリー 定数でコンパイル時1回

静的変数

427

Page 428: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子:無指定

関数外

• 外部変数の定義

• 広域的

• コンパイル時に1回だけ初期化

• 定数でのみ初期化可能

関数内

• 自動変数の定義

• 局所的

• 各ブロックの実行時に毎回初期化

• 変数でも初期化可能

• auto と同義

428

Page 429: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子: auto

関数外

• 使用不可

関数内

• 自動変数の定義

• 局所的

• 各ブロックの実行時に毎回初期化

• 変数でも初期化可能

429

Page 430: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子: register

関数外

• 使用不可

関数内

• レジスタ変数の定義

• 局所的

• 各ブロックの実行時に毎回初期化

• 変数でも初期化可能

• アドレス演算子&使用不可

430

レジスタ変数は自動変数の一種 優先的にレジスタに割り当てるが レジスタは数が少ないので 必ずしもレジスタに割り当てられるわけではない

Page 431: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子: static

関数外

• 静的変数の定義

• 広域的(ただしファイル外からはアクセス出来ない)

• コンパイル時に1回だけ初期化

• 定数でのみ初期化可能

関数内

• 静的変数の定義

• 局所的

• コンパイル時に1回だけ初期化

• 定数でのみ初期化可能

431

Page 432: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

記憶クラス指定子: extern

関数外

• 外部変数の宣言

• 広域的

• 定義の側で初期化を行う(宣言の側では初期化出来ない)

関数内

• 外部変数の宣言

• 広域的

• 定義の側で初期化を行う(宣言の側では初期化出来ない)

432

Page 433: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数のメモリへの割り当て

• 通常の自動変数はスタックに作成される

433

呼び出し元アドレス

int a

int b

int c

#include <stdio.h> void main() { int a; int b; int c; }

実行時に随時スタックに積んで行く 使い終わったらスタックから破棄する

教科書pp.177-179.

Page 434: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数のメモリへの割り当て

• 外部変数、静的変数はメモリの特定領域へ作成される

434

呼び出し元アドレス

int a

int b

#include <stdio.h> int a; void main() { static int b; int c; }

:

:

コンパイル時にあらかじめ 決められたメモリに配置される

int c

教科書pp.177-179.

Page 435: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

スタックメモリ

• 積み木式データ構造

• LIFO(Last-In-First-Out)

• FILO(First-In-Last-Out)

• 先入れ後出し

• 後入れ先出し

• サブルーチン呼び出し等で呼び出し元アドレスの保存やローカル変数の作成に使われる

• push (一番上に格納)

• pop (一番上から取り出し)

435

呼び出し元アドレス

教科書pp.177-179.

Page 436: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

スタックメモリ

• 積み木式データ構造

• LIFO(Last-In-First-Out)

• FILO(First-In-Last-Out)

• 先入れ後出し

• 後入れ先出し

• サブルーチン呼び出し等で呼び出し元アドレスの保存やローカル変数の作成に使われる

• push (一番上に格納)

• pop (一番上から取り出し)

436

呼び出し元アドレス

教科書pp.177-179.

int a

Page 437: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

スタックメモリ

• 積み木式データ構造

• LIFO(Last-In-First-Out)

• FILO(First-In-Last-Out)

• 先入れ後出し

• 後入れ先出し

• サブルーチン呼び出し等で呼び出し元アドレスの保存やローカル変数の作成に使われる

• push (一番上に格納)

• pop (一番上から取り出し)

437

呼び出し元アドレス

int a

教科書pp.177-179.

int b

Page 438: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

スタックメモリ

• 積み木式データ構造

• LIFO(Last-In-First-Out)

• FILO(First-In-Last-Out)

• 先入れ後出し

• 後入れ先出し

• サブルーチン呼び出し等で呼び出し元アドレスの保存やローカル変数の作成に使われる

• push (一番上に格納)

• pop (一番上から取り出し)

438

呼び出し元アドレス

教科書pp.177-179.

int a

Page 439: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

スタックメモリ

• 積み木式データ構造

• LIFO(Last-In-First-Out)

• FILO(First-In-Last-Out)

• 先入れ後出し

• 後入れ先出し

• サブルーチン呼び出し等で呼び出し元アドレスの保存やローカル変数の作成に使われる

• push (一番上に格納)

• pop (一番上から取り出し)

439

呼び出し元アドレス

教科書pp.177-179.

Page 440: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

レジスタ

• CPU 内で計算に用いられるメモリの一種

• メインメモリよりも高速だが数が少ない

• x86では32bitの汎用レジスタがたったの8つ(eax, ecx, edx, ebx, esp, ebp, esi, edi)しかない

440

レジスタ

メインメモリー 計算する際は必要な値を レジスタにロードしては戻している

可能なら限り値をレジスタに 置きっ放しにしておくと速くなる

メインメモリ外(CPU内)にあるためアドレスがない

Page 441: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の宣言と定義の違い

• 宣言

• 変数の型やサイズを指示する

• メモリへの割り当ては行わない

• 定義

• 変数の宣言を行う

• 実際にメモリへの割り当ても行う

441 [1] p.98.

分割コンパイルする場合、複数のファイルで同じ変数を重複して定義は出来ない 定義はどれか1つのファイルで1回だけ行い あとのファイルは宣言だけして定義済みの変数を参照する。

Page 442: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の宣言と定義

• 複数のファイルでの外部変数を共有する

442 [1] p.98.

extern_ex1_main.c #include <stdio.h> void sub(int); // 外部関数の宣言 int sum = 0; // 外部変数の定義と初期化 void main() { int i; for (i = 0; i < 10; i++) { sub(i); } printf("%d¥n", sum); }

extern_ex1_sub.c extern int sum; // 外部変数の宣言 // 外部関数の定義 void sub(int x) { sum += x; }

Page 443: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

static 宣言

• static 宣言には 3 種類の意味がある

443 教科書p.164., [1] p.101.

外部的 内部的

変数 外部変数に対する static 宣言 内部変数に対する static 宣言

関数 関数に対する static 宣言

外部変数や関数を 宣言されたファイル外から隠す

内部変数を 静的に割り当てる

Page 444: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

外部変数に対する static 宣言

• 複数ファイルでの外部変数共用

444

static_ex1_main.c #include <stdio.h> extern int val1; // 外部変数の宣言 //extern int val2; // 外部変数の宣言 void main() { printf("val1: %d¥n", val1); //printf("val2: %d¥n", val2); // val2 は static 変数なので // ファイル外からアクセス出来ない }

static_ex1_sub.c int val1 = 1; // 外部変数の定義と初期化 static int val2 = 2; // 外部変数の定義と初期化

教科書p.164., [1] p.101.

Page 445: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

内部変数に対する static 宣言

• 複数ファイルでの外部変数共用

445

static_ex2_main.c void sub1(); // 外部関数の宣言 void sub2(); // 外部関数の宣言 void main() { sub1(); sub1(); sub2(); sub2(); }

static_ex2_sub.c #include <stdio.h> void sub1() { int i = 0; // 自動変数の定義 printf("sub1: %d¥n", i++); } void sub2() { static int i = 0; // 静的変数の定義 printf("sub2: %d¥n", i++); }

mintty + bash + GNU C $ gcc static_ex1_main.c static_ex1_sub.c && ./a sub1: 0 sub2: 0 sub1: 0 sub2: 1

静的変数はコンパイル時に 1回だけしか初期化されない

教科書p.164., [1] p.101.

Page 446: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数に対する static 宣言

• 複数ファイルでの外部変数共用

446

static_ex3_main.c #include <stdio.h> void sub1(); // 外部関数の宣言 //void sub2(); // 外部関数の宣言 void main() { sub1(); sub1(); // sub2(); // sub2 は static 関数なので // sub2(); // ファイル外からは呼べない }

static_ex3_sub.c #include <stdio.h> void sub1() { printf("sub1¥n"); } static void sub2() { printf("sub2¥n"); }

教科書p.164., [1] p.101.

Page 447: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

447

Page 448: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第10週

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

情報処理言語Ⅰ(実習を含む。)

448

Page 449: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

基本型

449

Page 450: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ヘッダ: <limits.h>

450

• 整数型の最小値・最大値は以下のマクロで定義されている

unsigned signed

最小値 最大値 最小値 最大値

char 0 UCHAR_MAX SCHAR_MIN SCHAR_MAX

short 0 USHRT_MAX SHRT_MIN SHORT_MAX

int 0 UINT_MAX INT_MIN INT_MAX

long 0 ULONG_MAX LONG_MIN LONG_MAX

char 型に関する定義

CHAR_BIT char 型のビット数

CHAR_MIN 0 または SCHAR_MIN

CHAR_MAX UCHAR_MAX または SCHAR_MAX

Page 451: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ヘッダ: <float.h>

451

• 浮動小数点型に関する定数は以下のマクロで定義されている

float double

指数表現の基数 FLT_RADIX DBL_RADIX

精度の10進桁数 FLT_DIG DBL_DIG

仮数部における基数(RADIX)の桁数 FLT_MANT_DIG DBL_MANT_DIG

1.0 + 𝑥 ≠ 1.0となる最小の𝑥 FLT_EPSILON DBL_EPSILON

最大値 FLT_MAX DBL_MAX

正規化された最小の浮動小数値 FLT_MIN DBL_MIN

RADIX𝑛 − 1が表現可能な𝑛の最大値 FLT_MAX_EXP DBL_MAX_EXP

10𝑛を正規化された浮動小数値として表現可能な𝑛の最小値 FLT_MIN_EXP DBL_MIN_EXP

Page 452: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

良くあるエラーの例

エラーメッセージを読みエラーの原因を推測しましょう

452

Page 453: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

gcc のエラーメッセージ

• 環境変数LANGを設定すると言語が変わる

453

mintty + bash + GNU C $ LANG=C gcc error1.c error1.c: In function 'main': error1.c:7:3: error: expected ';' before 'printf' printf("world¥n"); ^

mintty + bash + GNU C $ LANG=ja_JP.UTF-8 gcc error1.c error1.c: 関数 ‘main’ 内: error1.c:7:3: エラー: expected ‘;’ before ‘printf’ printf("world¥n"); ^

ロケール(locale)と呼ばれる 多言語化の仕組み JM: locale (7)

Page 454: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

mintty の locale の設定

• mintty左上のアイコンからoption→Text

454

ここに Locale: ja_JP Cahaacter set: UTF-8 を設定して「OK」しておく

Page 455: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

文末の「;」忘れ

• 文末に「;」を忘れると次の文字でエラーに

455

error1.c int main() { printf("hello, ") printf("world¥n"); return EXIT_SUCCESS; }

4 5 6 7 8 9 10

mintty + bash + GNU C $ gcc error1.c error1.c: 関数 ‘main’ 内: error1.c:7:3: エラー: expected ‘;’ before ‘printf’ printf("world¥n"); ^

エラーが生じたのは7行目の3文字目だが、エラーの原因は6行目の行末。 C言語では、スペースや改行は人間に読み易くするための位置調整に過ぎないので printf("hello, ") printf("world¥n"); は printf("hello, ")printf("world¥n"); と同じ意味。

ここに「;」があるべきだが 「;」の前に「p」が現れたことが エラーの原因

Page 456: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ブロック開始終端の不整合

• 「{」が1つ多い

456

error2_1.c int main() { { printf("hello, world¥n"); return EXIT_SUCCESS; }

4 5 6 7 8 9 10

mintty + bash + GNU C $ gcc error2_1.c error2_1.c: 関数 ‘main’ 内: error2_1.c:10:1: エラー: expected declaration or statement at end of input } ^

「}」が1つ足らない状態で、ファイルの終端(入力の終端)に達している。

Page 457: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ブロック開始終端の不整合

• 「}」が1つ多い

457

エラーが生じたのは8行目の3文字目だが、エラーの原因は7行目。 「}」が1つ多いので、main関数の定義が7行目で終わっている。 つまり、8~9行目は、何もないところにいきなり以下のように書いたのと同じ。

return EXIT_SUCCESS; }

8 9

error2_2.c int main() { printf("hello, world¥n"); } return EXIT_SUCCESS; }

4 5 6 7 8 9

mintty + bash + GNU C $ gcc error2_2.c error2_2.c:8:3: エラー: expected identifier or ‘(’ before ‘return’ return EXIT_SUCCESS; ^ error2_2.c:9:1: エラー: expected identifier or ‘(’ before ‘}’ token } ^

Page 458: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ブロック開始終端の不整合

• 関数名のミススペル

458

コンパイルではなくリンクに失敗したと言われている。 分割コンパイルによる、外部関数のリンクの際、print が見つからなかった。 printf のつもりが print とミススペルしている。 標準ライブラリに print 関数は用意されていない。

error3.c int main() { print("hello, world¥n"); return EXIT_SUCCESS; }

4 5 6 7 8 9

mintty + bash + GNU C $ gcc error3.c /tmp/ccopiKHp.o:error3.c:(.text+0x15): `print' に対する定義されていない参照です /tmp/ccopiKHp.o:error3.c:(.text+0x15): 再配置がオーバーフローしないように切り詰められました: R_X86_64_PC32 (未定義シンボル `print' に対して) /usr/lib/gcc/x86_64-pc-cygwin/4.8.2/../../../../x86_64-pc-cygwin/bin/ld: /tmp/ccopiKHp.o: 誤った再配置アドレス 0x0 がセクション `.pdata' 内にあります /usr/lib/gcc/x86_64-pc-cygwin/4.8.2/../../../../x86_64-pc-cygwin/bin/ld: 最終リンクに失敗しました: 無効な操作です collect2: エラー: ld はステータス 1 で終了しました

コンパイルフェーズではなくリンクフェーズでのエラー。 ~.o ファイルについて参照がみつからないと言われている。

Page 459: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

不要な ;

• 関数定義がプロトタイプ宣言になっている

459

main() の直後に ; があるのでそこで文が終わっている。 このため、関数の定義ではなく、関数のプロトタイプ宣言になっている。

error4.c int main(); { printf("hello, world¥n"); return EXIT_SUCCESS; }

4 5 6 7 8 9

mintty + bash + GNU C $ gcc error4.c error4.c:5:1: エラー: expected identifier or ‘(’ before ‘{’ token { ^

Page 460: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイルが見つからない

• ファイル名や配置場所を確認する

460

#include しようとしたファイルが見つからない。 #include に与えたファイル名か、ファイルに付けた名前のどちらかが間違っている。 上記の例では stdlib.h が正しいが lib ではなく ilb になっている。

error5.c #include <stdio.h> #include <stdilb.h> int main(); { printf("hello, world¥n"); return EXIT_SUCCESS; }

1 2 3 4 5 6 7 8 9

mintty + bash + GNU C $ gcc error5.c error5.c:2:20: 致命的エラー: stdilb.h: No such file or directory #include <stdilb.h> ^ コンパイルを停止しました。

コンパイルフェーズではなく、プリプロセスフェーズでのエラー

Page 461: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語のコンパイル

• コンパイラにより実行形式に変換する

461

.h ファイル .h ファイル

.h ファイル

Source files

.c ファイル .c ファイル

.c ファイル

.o ファイル .o ファイル

.o ファイル

Object files

ライブラリ ライブラリ

ライブラリ

実行ファイル

Executable files

C compiler

Preprocessor

linker

C compiler Cコンパイラは実際には preprocessor compiler linker の3段階に分かれている

Page 462: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

エラー時の対処方法

• エラーメッセージをよく読みましょう。

• 行番号と何文字目かも参考になります。

• 同じようなエラーメッセージなら、同じような原因である可能性が高いはずです。

• 原因が分からない場合は、エラーメッセージを Google 等の検索エンジンで検索しましょう。

462

Page 463: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

463

Page 464: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第11週

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

情報処理言語Ⅰ(実習を含む。)

464

Page 465: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

いろいろなプログラム

465

Page 466: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

列挙子

名前付きの定数

466

Page 467: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

定数の種類

• リテラル

• 数値リテラル

• 文字列リテラル

• 列挙定数

467

マジックナンバーになると分かり辛いので、マクロか const 変数にして名前付の定数にする。

自動的に名前付定数の数値を割り振ってくれる

Page 468: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

列挙(enumeration) 列挙子(enumerator)

• 書式: • enum 列挙名 {列挙定数名 [= 定整数値], ...}

• 値を設定しないと

• 0から開始

• 前の値から+1ずつ増加

• #define の代わりに使える

468

Page 469: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

列挙(enumeration) 列挙子(enumerator)

• 例:

enum boolean {NO, YES};

enum escape { BELL = '¥a', BACKSPACE = '¥b', TAB = '¥t', NEWLINE = '¥n', VTAB = '¥v', RETURN = '¥r'};

enum month { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};

NO = 0 YES = 1

JAN = 1 FEB = 2 MAR = 3 ... DEC = 12

469

Page 470: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

列挙(enumeration) 列挙子(enumerator)

• #define で書き変えた場合の例:

#define NO 0 #define YES 1

#define BELL '¥a' #define BACKSPACE '¥b' #define TAB '¥t' #define NEWLINE '¥n' #define VTAB '¥v' #define RETURN '¥r'

#define JAN 1 #define FEB 2 #define MAR 3 // ... #define DEC 12

470

Page 471: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

パラメータ付きのマクロ

関数のようなマクロ

471

Page 472: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

パラメータ付きのマクロ

• #define で定義するマクロに ( ) を付けるとパラメータを与えることが出来る。

472

macro_ex1.c #include <stdio.h> #define MIN(X,Y) (X<Y?X:Y) void main() { printf("min: %d¥n", MIN(1,2)); }

1 2 3 4 5 6 7 8

コンパイル前 プリプロセッサにより (1<2?1:2)で置換される

Page 473: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

パラメータ付きのマクロの注意点

• マクロは単純な置換なので置換結果がどうなるか注意する必要がある。

473

macro_ex2_1.c #include <stdio.h> #define POW2(X) (X*X) void main() { printf("pow2: %d¥n", POW2(2)); }

1 2 3 4 5 6 7 8

コンパイル前 プリプロセッサにより (2*2)と置換される

Page 474: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

パラメータ付きのマクロの注意点

• マクロは単純な置換なので置換結果がどうなるか注意する必要がある。

474

macro_ex2_1.c #include <stdio.h> #define POW2(X) (X*X) void main() { printf("pow2: %d¥n", POW2(2+1)); }

1 2 3 4 5 6 7 8

コンパイル前 プリプロセッサにより (2+1*2+1)と置換される

(2+1)*(2+1)=9 ではなく 2+(1*2)+1=5 になってしまう

Page 475: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

パラメータ付きのマクロの注意点

• マクロは単純な置換なので置換結果がどうなるか注意する必要がある。

475

macro_ex2_2.c #include <stdio.h> #define POW2(X) ((X)*(X)) void main() { printf("pow2: %d¥n", POW2(2+1)); }

1 2 3 4 5 6 7 8

コンパイル前 プリプロセッサにより ((2+1)*(2+1))と置換される

パラメータはなるべく括弧で括る

Page 476: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

パラメータ付きのマクロの注意点

• マクロは単純な置換なので置換結果がどうなるか注意する必要がある。

476

macro_ex2_3.c #include <stdio.h> #define POW2(X) ((X)*(X)) void main() { int x=2; printf("pow2: %d¥n", POW2(++x)); }

1 2 3 4 5 6 7 8 9

コンパイル前 プリプロセッサにより ((++x)*(++x))と置換され 結果として 3*4 になってしまう

マクロのパラメータに 副作用を伴う演算を用いては駄目

Page 477: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の交換

swap

477

Page 478: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の交換

• 以下のケースで x,y の値を交換するにはどうしたら良いか?

478

int x = 10; int y = 20; // 以下で x,y の値を入れ替えたい x = y; y = x;

こうするとxは既に 20で上書きされているので、 両方20になってしまう。

Page 479: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の交換

• 中間変数を用いると良い

479

int x = 10; int y = 20; int tmp; // 以下で x,y の値を入れ替えたい tmp = x; x = y; y = tmp;

こうやると中間変数tmpに保存された xの値10をyに入れることで x,yの値を入れ替える事が出来る。

Page 480: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

値の交換

• マクロにしてみる

480

macro_ex3.c #define SWAP(TYPE,X,Y) {TYPE SWAP_tmp=X; X=Y; Y=SWAP_tmp;} int x = 10; int y = 20; // 以下で x,y の値を入れ替えたい SWAP(int, x, y);

ブロック内のローカル変数として 中間変数を作成

// 以下で x,y の値を入れ替えたい {int SWAP_tmp=x; x=y; y=SWAP_tmp;};

プリプロセッサにより 以下のように置換される

Page 481: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

481

Page 482: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第12週

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

情報処理言語Ⅰ(実習を含む。)

482

Page 483: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

文字列の基本

483

Page 484: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

𝑁進数

• 各桁は𝑁種類の数字(0~𝑁 − 1)で表す

• 下の桁から、 𝑁0の桁、 𝑁1の桁、 𝑁2の桁、 …

• 現在の桁数で表せない数値は桁上がりする

2進数 8進数 10進数 16進数

0 0 0 0

1 1 1 1

10 2 2 2

11 3 3 3

100 4 4 4

101 5 5 5

110 6 6 6

111 7 7 7

1000 10 8 8

1001 11 9 9

1010 12 10 a

1011 13 11 b

1100 14 12 c

1101 15 13 d

1110 16 14 e

1111 17 15 f

10000 20 16 10

484

2の桁へ 桁上がり

4の桁へ 桁上がり

8の桁へ 桁上がり

16の桁へ 桁上がり

8の桁へ 桁上がり

10の桁へ 桁上がり

16の桁へ 桁上がり

2進数3桁 ⇕

8進数1桁

2進数4桁 ⇕

16進数1桁

Page 485: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

𝑁進数

2進数 4桁(場合の数 2 4) 16進数 1桁(場合の数16 1) 2進数 8桁(場合の数 2 8) 16進数 2桁(場合の数16 2) 2進数16桁(場合の数 216) 16進数 4桁(場合の数16 4) 2進数32桁(場合の数 232) 16進数 8桁(場合の数16 8) 2進数64桁(場合の数 264) 16進数16桁(場合の数1616)

2進数 8進数 10進数 16進数

11111000 370 248 f8

11111001 371 249 f9

11111010 372 250 fa

11111011 373 251 fb

11111100 374 252 fc

11111101 375 253 fd

11111110 376 254 fe

11111111 377 255 ff

100000000 400 256 100

100000001 401 257 101

100000010 402 258 102

100000011 403 259 103

100000100 404 260 104

100000101 405 261 105

100000110 406 262 106

100000111 407 263 107

100001000 400 264 108

485

256の桁へ 桁上がり

256の桁へ 桁上がり

2進数3桁 ⇕

8進数1桁

2進数4桁 ⇕

16進数1桁

𝑥バイト(8𝑥ビット)の数値は 2𝑥桁の16進数で表すことが出来る

Page 486: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

8bit整数の10進表現

2進 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

16進 0 1 2 3 4 5 6 7 8 9 A B C D E F

0000 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0001 1 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0010 2 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

0011 3 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

0100 4 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

0101 5 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

0110 6 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

0111 7 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

1000 8 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

1001 9 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

1010 A 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175

1011 B 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

1100 C 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207

1101 D 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

1110 E 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

1111 F 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

上位4ビット

下位4ビット

486

2進数と10進数は桁数の対応で収まりが悪い

Page 487: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

8bit整数の2進表現

2進 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

16進 0 1 2 3 4 5 6 7 8 9 A B C D E F

0000 0 0000 0000 0000 0001 0000 0010 0000 0011 0000 0100 0000 0101 0000 0110 0000 0111 0000 1000 0000 1001 0000 1010 0000 1011 0000 1100 0000 1101 0000 1110 0000 1111

0001 1 0001 0000 0001 0001 0001 0010 0001 0011 0001 0100 0001 0101 0001 0110 0001 0111 0001 1000 0001 1001 0001 1010 0001 1011 0001 1100 0001 1101 0001 1110 0001 1111

0010 2 0010 0000 0010 0001 0010 0010 0010 0011 0010 0100 0010 0101 0010 0110 0010 0111 0010 1000 0010 1001 0010 1010 0010 1011 0010 1100 0010 1101 0010 1110 0010 1111

0011 3 0011 0000 0011 0001 0011 0010 0011 0011 0011 0100 0011 0101 0011 0110 0011 0111 0011 1000 0011 1001 0011 1010 0011 1011 0011 1100 0011 1101 0011 1110 0011 1111

0100 4 0100 0000 0100 0001 0100 0010 0100 0011 0100 0100 0100 0101 0100 0110 0100 0111 0100 1000 0100 1001 0100 1010 0100 1011 0100 1100 0100 1101 0100 1110 0100 1111

0101 5 0101 0000 0101 0001 0101 0010 0101 0011 0101 0100 0101 0101 0101 0110 0101 0111 0101 1000 0101 1001 0101 1010 0101 1011 0101 1100 0101 1101 0101 1110 0101 1111

0110 6 0110 0000 0110 0001 0110 0010 0110 0011 0110 0100 0110 0101 0110 0110 0110 0111 0110 1000 0110 1001 0110 1010 0110 1011 0110 1100 0110 1101 0110 1110 0110 1111

0111 7 0111 0000 0111 0001 0111 0010 0111 0011 0111 0100 0111 0101 0111 0110 0111 0111 0111 1000 0111 1001 0111 1010 0111 1011 0111 1100 0111 1101 0111 1110 0111 1111

1000 8 1000 0000 1000 0001 1000 0010 1000 0011 1000 0100 1000 0101 1000 0110 1000 0111 1000 1000 1000 1001 1000 1010 1000 1011 1000 1100 1000 1101 1000 1110 1000 1111

1001 9 1001 0000 1001 0001 1001 0010 1001 0011 1001 0100 1001 0101 1001 0110 1001 0111 1001 1000 1001 1001 1001 1010 1001 1011 1001 1100 1001 1101 1001 1110 1001 1111

1010 A 1010 0000 1010 0001 1010 0010 1010 0011 1010 0100 1010 0101 1010 0110 1010 0111 1010 1000 1010 1001 1010 1010 1010 1011 1010 1100 1010 1101 1010 1110 1010 1111

1011 B 1011 0000 1011 0001 1011 0010 1011 0011 1011 0100 1011 0101 1011 0110 1011 0111 1011 1000 1011 1001 1011 1010 1011 1011 1011 1100 1011 1101 1011 1110 1011 1111

1100 C 1100 0000 1100 0001 1100 0010 1100 0011 1100 0100 1100 0101 1100 0110 1100 0111 1100 1000 1100 1001 1100 1010 1100 1011 1100 1100 1100 1101 1100 1110 1100 1111

1101 D 1101 0000 1101 0001 1101 0010 1101 0011 1101 0100 1101 0101 1101 0110 1101 0111 1101 1000 1101 1001 1101 1010 1101 1011 1101 1100 1101 1101 1101 1110 1101 1111

1110 E 1110 0000 1110 0001 1110 0010 1110 0011 1110 0100 1110 0101 1110 0110 1110 0111 1110 1000 1110 1001 1110 1010 1110 1011 1110 1100 1110 1101 1110 1110 1110 1111

1111 F 1111 0000 1111 0001 1111 0010 1111 0011 1111 0100 1111 0101 1111 0110 1111 0111 1111 1000 1111 1001 1111 1010 1111 1011 1111 1100 1111 1101 1111 1110 1111 1111

上位4ビット

下位4ビット

487

2進数は桁が多過ぎて直感的に分かり難い

Page 488: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

8bit整数16進表現

2進 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

16進 0 1 2 3 4 5 6 7 8 9 A B C D E F

0000 0 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f

0001 1 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

0010 2 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f

0011 3 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f

0100 4 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f

0101 5 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f

0110 6 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f

0111 7 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f

1000 8 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f

1001 9 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f

1010 A a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af

1011 B b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf

1100 C c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf

1101 D d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df

1110 E e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef

1111 F f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff

上位4ビット

下位4ビット

488

2進数と16進数は相性が良い。2進数4桁が16進数1桁に対応するので直感的に分かり易い

Page 489: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ASCII文字コード表

16進 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI 1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 2 SP ! " # $ % & ' ( ) * + , - . / 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 4 @ A B C D E F G H I J K L M N O 5 P Q R S T U V W X Y Z [ ¥ ] ^ _ 6 ` a b c d e f g h i j k l m n o 7 p q r s t u v w x y z { | } ~ DEL 8 9 A B C D E F

上位4ビット

下位4ビット

赤字は制御コード

教科書 p.51.,第2週資料 p.67.

http://ja.wikipedia.org/wiki/ASCII

489

Page 490: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ヘッダ <ctype.h>

// 文字コードの調査(cが該当する文字なら真を返す) int islower(int c); //小文字 int isupper(int c); //大文字 int isdigit(int c); //10進数(数字) int isxdigit(int c);//16進数 int isalpha(int c); //英字 (isupper(c)||islower(c)) int isalnum(int c); //英数字(isalpha(c)||isdigit(c)) int iscntrl(int c); //制御文字(0x00~0x1f, 0x7f) int isspace(int c); //空白文字(' ','¥f','¥n','¥r','¥t','¥v') int isprint(int c); //印字可能文字(0x20~0x7e) int isgraph(int c); //印字可能文字(スペースを除く) isprint(c)&&!isspace(c) int ispunct(int c); //印字可能文字(スペース、英数字を除く)isgraph(c)&&!isalnum(c) // 文字コードの変換 int tolower(int c); //cを小文字に変換 int toupper(int c); //cを大文字に変換

490 [1] pp.303.

JM: isalpha (3) toupper (3) 講義資料の ctype_test.c, ctype_test.xlsx も参照

Page 491: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

char型変数と文字コード

• char, unsigned char 型

• 半角文字の文字コードを1つ つまり1バイト(=8ビット)を格納出来るサイズ

• char : -128~127

• unsigned char : 0~255

491 教科書 pp.44, 96-99., 第2週資料 pp.54-63.

c

0110 1000

変数の実体はNバイト(8Nビット)のメモリ つまり内部的には2進数が入っている

16進数リテラルによる初期化 char c = 0x68; // =104='h'

文字コードに対応する文字を表示 printf("%c¥n", 104); // "%c"に文字コードを与えると対応する文字が表示される

Page 492: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

char型変数と文字コード

• 以下の変数宣言と初期化は全く同じ結果

492 教科書 pp.44, 96-99., 第2週資料 pp.54-63.

c

0110 1000 どの方法で初期化しようと結局 char型(1バイト)の変数 c を 0b01101000 で初期化している

文字コードを代入したい場合 文字定数リテラルで書くと 数値リテラルで書くよりも 意味が分かり易くなる

結果は同じでも読んだ時 分かり易いのはどれだろう?

必要であれば 読んだ人が分かり易いよう コメントで情報を補うと良い

文字定数リテラルによる初期化 char c = 'h'; // 0x68

10進数リテラルによる初期化 char c = 104; // 'h'

16進数リテラルによる初期化 char c = 0x68; // 'h'

c

104

c

0x68

c

'h'

Page 493: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

char型配列と文字列

• 以下の変数宣言と初期化は全く同じ結果

493

文字定数リテラルによる初期化 char s[] = {'h', 'e', 'l', 'l', 'o', '¥0'};

文字列定数リテラルによる初期化 char s[] = "hello";

教科書 pp.44, 96-99., 第2週資料 pp.54-63.

10進数リテラルによる初期化 char s[] = {104, 101, 108, 108, 111, 0};

16進数リテラルによる初期化 char s[] = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};

s[0]

'h'

s[1]

'e'

s[2]

'l'

s[3]

'l'

s[4]

'o'

s[5]

'¥0' 文字列は配列に格納した 一連の文字コード 終端には 0 を格納する

どれで書いても良いが 普通は面倒だから 文字列の初期化は 文字列定数リテラルを 用いる

Page 494: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

char型配列と文字列

• 文字列の表示

494

文字列定数リテラルによる初期化 char s[] = "hello";

教科書 pp.44, 96-99., 第2週資料 pp.54-63.

s[0]

'h'

s[1]

'e'

s[2]

'l'

s[3]

'l'

s[4]

'o'

s[5]

'¥0'

文字列の表示 printf("%s¥n", s); // "%s"に与えたアドレス以降'¥0'が現れるまで // メモリに格納された文字コードに対応する文字が表示される

Page 495: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数の引数とよく使われる名前

• p, ptr, pointer : ポインタ • c, ch, chr, character : 文字 • s, str, string : 文字列 • s, src, source : 発信元 • d, dst, destination : 送信先 • t, txt, text : テキスト • l, len, length : 長さ • w, wid, width : 幅 • h, hei, height : 高さ • n, num, number : (個)数 • s, size : サイズ • b, buf, buff, buffer : バッファ • i, idx, index : 添え字 • s, stat, status : 状態

495

Page 496: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ヘッダ <string.h>

size_t strlen(const char *s); // 文字列の長さ char *strcpy(char *dst, const char *src); // 文字列のコピー char *strncpy(char *dst, const char *src, size_t n); // 文字列のコピー(最長制限付) char *strcat(char *dst, const char *src); // 文字列の連結 char *strncat(char *dst, const char *src, size_t n); // 文字列の連結(最長制限付) char *strcmp(const char *s1, const char *s2); // 文字列の比較 char *strncmp(const char *s1, const char *s2, size_t n); // 文字列の比較(最長制限付) char *strchr(const char *s, char c); // 文字の検索(先頭から) char *strrchr(const char *s, char c); // 文字の検索(末尾から) int strspn(const char *s, const char *t); // 先頭部分の文字列の長さ(∈t) int strcspn(const char *s, const char *t); // 先頭部分の文字列の長さ(∉t) char *strpbrk(const char *s, const char *t); // 文字の検索(∈t) char *strstr(const char *s, const char *t); // 文字列の検索 char *strtok(char *s, const char *t); // 文字列の分割 void *memset(void *s, int c, size_t n); // メモリへ値を設定 void *memcpy(void *dst, const void *src, size_t n); // メモリのコピー void *memmove(void *dst, const void *src, size_t n); // メモリの移動 int memcmp(const void *s1, const void *s2, size_t n); // メモリの比較 void *memchr(const void *s, int c, size_t n); // メモリの検索

496

Page 497: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strlen 関数

• size_t strlen(const char *s); • 文字列 s の長さを返す

• 引数: • s: 長さを調べる文字列

• 戻り値 • 文字列 s の長さを返す

497 教科書 p.312., [1] pp.313-315.

JM: strlen (3)

Page 498: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strcpy 関数

• char *strcpy(char *dst, const char *src); • '¥0'を含めてsrcをdstへコピーする

• 引数: • dst: コピー先のアドレス • src: コピー元の文字列

• 戻り値 • dst を返す • dst が十分な大きさでないとバッファオーバーフローを引き起こす

ので注意

498 教科書 p.308., [1] pp.313-315.

JM: strcpy (3)

Page 499: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strncpy 関数

• char *strncpy(char *dst, const char *src, size_t n); • srcから最大n文字dstへコピーする

• 引数: • dst: コピー先のアドレス • src: コピー元の文字列 • n: コピーする最大文字数

• 戻り値 • dst を返す • src が n 文字より短い場合は、残りの dst の末尾に '¥0' を

詰めて、合計 n バイト書き込む

499 教科書 p.308., [1] pp.313-315.

JM: strcpy (3)

Page 500: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strcat 関数

• char *strcat(char *dst, const char *src); • 文字列dstの末尾に文字列srcを連結する

• 引数: • dst: 連結先の文字列 • src: 連結元の文字列

• 戻り値 • dst を返す • dst が十分な大きさでないとバッファオーバーフローを引き起こす

ので注意

500 教科書 p.309., [1] pp.313-315.

JM: strcat (3)

Page 501: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strncat 関数

• char *strncat(char *dst, const char *src, size_t n); • 文字列dstの末尾に文字列srcを最大n文字連結する

• 引数: • dst: 連結先の文字列 • src: 連結元の文字列 • n: 連結する最大文字数

• 戻り値 • dst を返す • dst は strlen(dst)+min(strlen(stc),n)+1 の大きさがな

ければバッファオーバーフローが発生する

501 教科書 p.309., [1] pp.313-315.

JM: strcat (3)

Page 502: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strcmp 関数

• char *strcmp(const char *s1, const char *s2); • 文字列s1とs2を比較する

• 引数: • s1: 比較する文字列1 • s2: 比較する文字列2

• 戻り値 • s1がs2に比べて小さければマイナスの値を返す • s1とs2が等しければ0を返す • s1がs2に比べて大きければプラスの値を返す

502 教科書 p.309., [1] pp.313-315.

JM: strcmp (3)

Page 503: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strncmp 関数

• char *strncmp(const char *s1, const char *s2, size_t n); • 文字列s1とs2の先頭n文字を比較する

• 引数: • s1: 比較する文字列1 • s2: 比較する文字列2 • n: 比較する最大文字数

• 戻り値 • strcmpに同じ

503 教科書 p.310., [1] pp.313-315.

JM: strcmp (3)

Page 504: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strchr 関数

• char *strchr(const char *s, char c); • 文字列sのなかで最初に現れるcを見つける

• 引数: • s: 検索する文字列 • c: 検索する文字

• 戻り値 • 最初に見つかったcへのポインタを返す • 見つからなかった場合はNULLを返す

504 教科書 p.312., [1] pp.313-315.

JM: strchr (3)

Page 505: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strrchr 関数

• char *strrchr(const char *s, char c); • 文字列sのなかで最後に現れるcを見つける

• 引数: • s: 検索する文字列 • c: 検索する文字

• 戻り値 • 最後に見つかったcへのポインタを返す • 見つからなかった場合はNULLを返す

505 教科書 p.313., [1] pp.313-315.

JM: strchr (3)

Page 506: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strspn 関数

• int strspn(const char *s, const char *t); • 文字列sの先頭から、tに含まれる文字だけからなる文字列の長さ

を返す

• 引数: • s: 検索する文字列 • t: 検索する文字の集合

• 戻り値 • tに含まれる文字からなる接頭子(prefix)の長さを返す

506 [1] pp.313-315.

JM: strspn (3)

Page 507: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strcspn 関数

• int strcspn(const char *s, const char *t); • 文字列sの先頭から、tに含まれない文字だけからなる文字列の長

さを返す

• 引数: • s: 検索する文字列 • t: 検索する文字の補集合

• 戻り値 • tに含まれない文字からなる接頭子(prefix)の長さを返す

507 [1] pp.313-315.

JM: strspn (3)

Page 508: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strpbrk 関数

• char *strpbrk(const char *s, const char *t); • 文字列sのなかで、tに含まれる文字が最初に出てくる位置を見つ

ける

• 引数: • s: 検索する文字列 • t: 検索する文字の集合

• 戻り値 • tに含まれる文字が最初に見つかった位置へのポインタを返す • 見つからなかった場合はNULLを返す

508 [1] pp.313-315.

JM: strpbrk (3)

Page 509: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strstr 関数

• char *strstr(const char *s, const char *t); • 文字列sのなかで、文字列tが最初に現れる位置を見つける

• 引数: • s: 検索する文字列 • t: 検索する文字列

• 戻り値 • 文字列tが最初に見つかった位置へのポインタを返す • 見つからなかった場合はNULLを返す

509 教科書 p.314., [1] pp.313-315.

JM: strstr (3)

Page 510: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strtok 関数

• char *strtok(char *s, const char *t); • 文字列sのなかから、 tに含まれる文字で区切られるトークンを見

つける

• 引数: • s: 検索する文字列 • t: トークンを区切る文字の集合

• 戻り値 • トークンへのポインタを返す • 2つ目以降のトークンは s を NULL にして呼ぶことで順次切り出

される • トークンがなくなったらはNULLを返す • s は区切り文字の位置が終端文字'¥0'で破壊される

510 [1] pp.313-315.

JM: strtok (3)

Page 511: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

memset 関数

• void *memset(void *s, int c, size_t n); • sの先頭からnバイトをcで埋めsを返す

• 引数: • s: データで埋める先頭アドレス • c: メモリを埋める1バイトのデータ • n: データcを埋めるバイト数

• 戻り値 • s を返す • 要 string.h

511 [1] pp.313-315.

JM: memset (3)

Page 512: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

memcpy 関数

• void *memcpy(void *dst, const void *src, size_t n); • dstにsrcの内容をnバイトコピーする • dstとsrcは領域が重なっていてはならない。重なっている場合は

memmoveを用いる

• 引数: • dst: データのコピー先 • src: データのコピー元 • n: コピーするバイト数

• 戻り値 • dst を返す • 要 string.h

512 [1] pp.313-315.

JM: memcpy (3)

Page 513: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

memmove 関数

• void *memmove(void *dst, const void *src, size_t n); • dstとsrcは領域が重なっていても良い点を除けば、memcpyと同じ

• 引数: • dst: データのコピー先 • src: データのコピー元 • n: コピーするバイト数

• 戻り値 • dst を返す • 要 string.h

513

JM: memmove (3)

[1] pp.313-315.

Page 514: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

memcmp 関数

• int memcmp(const void *s1, const void *s2, size_t n); • s1とs2の最初のnバイトを比較する

• 引数: • s1: 比較するメモリ1 • s2: 比較するメモリ2 • n: 比較するバイト数

• 戻り値 • strcmpに同じ • 要 string.h

514

JM: memcmp (3)

[1] pp.313-315.

Page 515: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

memchr 関数

• void *memchr(const void *s, int c, size_t n); • sの中でcが最初に現れる位置を見つける

• 引数: • s: 検索するメモリ • c: 検索する値 • n: 検索する範囲のバイト数

• 戻り値 • cが最初に見つかった位置へのポインタを返す • 見つからなかった場合はNULLを返す要 string.h

515

JM: memchr (3)

[1] pp.313-315.

Page 516: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ヘッダ <stdlib.h>

// 文字列を数値に変換

double atof(const char *s); //文字列をdouble型の数値に変換

int atoi(const char *s); //文字列をint型の数値に変換

long atol(const char *s); //文字列をlong型の数値に変換

double strtod(const char *s, char **endp);

long strtol(const char *s, char **endp, int base);

unsigned long strtoul(const char *s, char **endp, int base);

// 文字列を double, long, unsigned long 型の数値に変換する

// endp が NULL でない場合、

// *endp は変換に用いた最後の文字の次の文字へのポインタとなる

// base は変換元の文字列の基数

// base が 0 の場合、文字列先頭の 0 や 0x を解釈し

// 8 進数や 16 進数として扱う

516 [1] pp.316-317.

JM: atof (3) atoi (3)

strtod (3) strtol (3)

Page 517: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

シーザー暗号

文字列の演習

517

Page 518: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

シーザー暗号

• アルファベットをN文字シフトする暗号

• 例: IBM→1文字左へ→HAL

518

Page 519: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: caesar.c

• 与えられた文字列をシーザー暗号で暗号化する関数caesar(n,s)を作成せよ。 • 文字コードが0x20~0x7eの文字ついてのみ処理し、それ以外の文字について

は処理せずそのまま残すこと。 • 0x20~0x7eからはみ出す値は値域の反対側に繋がるよう循環するよう変換せ

よ。例えばn=1なら0x61('a')は0x62('b')に、0x7eは0x20に変換される変換される。n=-1の場合も同様で、0x20は0x7eに変換される。

• caesar_main.c と共にコンパイルして動作を確認せよ • 引数:

• int n : 暗号鍵(シフトする文字数) • char s[] : 暗号化する文字列(終端が'¥0')

• 戻り値 • なし(void) • 与えた配列 s を上書きしてシーザー暗号で

暗号化した文字列で上書きせよ

519

mintty + bash + GNU C $ gcc caesar_main.c caesar.c && ./a n = 1 s = hal ibm

Page 520: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ヒント

• プロトタイプ宣言の末尾の ; を {} に変えれば関数の定義になる。

• 文字の末尾は ¥0 で終端されている。 • i を増やしながら s[i] != '¥0' の間ループを

続ければ良い。

• s 全体を暗号文で上書きするには各 s[i] を暗号化して s[i] に戻してやれば良い。

520

caerar_main.c void caesar(int n, char s[]); 4

Page 521: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ヒント

• 0x20未満、0x7e超になった場合の処理は幾つかやり方がある

• if 文等で場合分けする方法

• 剰余算を使う方法

• 等々

521

Page 522: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

522

Page 523: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第13週

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

情報処理言語Ⅰ(実習を含む。)

523

Page 524: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

メモリ上におけるデータの並び

マルチバイトデータの各バイトはどう並ぶか?

524 備考

Page 525: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の割り当てとバイトオーダー

• 32bit int型の場合

0x?? 0x~00

0x?? 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

32bit

int a; // 変数の宣言

a

0x????????

525 備考

Page 526: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の割り当てとバイトオーダー

• 32bit int型の場合(Little Endian)

0x78 0x~00

0x56 0x~01

0x34 0x~02

0x12 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

32bit

int a = 0x12345678; // 変数の宣言と初期化

a

0x12345678

Intel の x86 系 CPU 等

526 備考

Page 527: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の割り当てとバイトオーダー

• 32bit int型の場合(Big Endian)

0x12 0x~00

0x34 0x~01

0x56 0x~02

0x78 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

32bit

int a = 0x12345678; // 変数の宣言と初期化

a

0x12345678

ネットワーク上を流れるデータ等

527 備考

Page 528: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の割り当てとバイトオーダー

• 16bit short型の場合(Little Endian)

0x34 0x~00

0x12 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

short a = 0x1234; // 変数の宣言と初期化

a

0x????1234

a

0x1234

16bit

同じ場所から32bitで取ると

Intel の x86 系 CPU 等

528 備考

Page 529: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変数の割り当てとバイトオーダー

• 16bit short型の場合(Big Endian)

0x12 0x~00

0x34 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

short a = 0x1234; // 変数の宣言と初期化

a

0x1234????

a

0x1234

16bit

同じ場所から32bitで取ると

ネットワーク上を流れるデータ等

529 備考

Page 530: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ

メモリのアドレスを用いて格納値を操作する

530

Page 531: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

• メモリ上のアドレスを指し示すための変数

• char * 型: char 型の変数へのポインタ

• int * 型: int 型の変数へのポインタ

• 要はアドレスを格納するための変数

• ポインタ型のサイズはアドレス空間のビット数

• sizeof(char *)もsizeof(int *)も同じ

• 32ビットアドレス空間なら4バイト

• 64ビットアドレス空間なら8バイト

531 教科書pp.207-272.

pointer: 指し示す者

Page 532: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

メモリの構成

• 1byte単位でアドレスが振られている

• つまり各アドレスには1byteの値を格納出来る

0x00 0x00000000

0x00 0x00000001

0x00 0x00000002

0x00 0x00000003

0x00 0xffffffff

: :

: :

0x00 0x0000000000000000

0x00 0x0000000000000001

0x00 0x0000000000000002

0x00 0x0000000000000003

0x00 0xffffffffffffffff

: :

: :

32bitのOSは32bitのアドレス空間 最大232Bytes=4GiB

64bitのOSは64bitのアドレス空間 最大264Bytes=16EiB

アドレス 格納値 アドレス 格納値

教科書 pp.52-56. 第2週資料 p.49.

ポインタ変数には これらの値が入る

532

Page 533: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

• 例: 16bit short型little endianの場合

0x34 0x~00

0x12 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

short a = 0x1234; short *p = &a;

a

0x1234

a

p に &a を入れておくと *p は a への 参照として機能する C言語ではこれを ポインタと言う

533

p

0x~00

&a

0x~00

&aは 変数aの メモリ上の 先頭アドレス

実際に存在している変数はpで中にはアドレスが格納されている

*pはアドレスpに 置かれた変数(ここではa) への参照

要はリンク みたいなもの

*p

0x1234

0x~00

宣言時に*を付けると ポインタ変数になる

教科書pp.207-272.

pは変数*pの アドレスを指し示す

Page 534: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

• 変数が配置されたアドレスを扱うための変数

534

pointer_ex1_1.c int main() { int a = 1; int *p; p = &a; *p = 2; printf("*p=%d¥n", *p); printf(" a=%d¥n", a); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書pp.207-272.

変数の宣言で 変数名の前にポインタ宣言子「*」を付けると ポインタ変数になる。

mintty + bash + GNU C $ gcc pointer_ex1_1.c && ./a *p=2 a=2 重要

ポインタ変数 p に 変数 a のアドレス &a を代入すると 変数 a の代わりに *p が使える。

Page 535: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

• 変数が配置されたアドレスを扱うための変数

535

pointer_ex1_1.c int main() { int a = 1; int *p; p = &a; *p = 2; printf("*p=%d¥n", *p); printf(" a=%d¥n", a); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書pp.207-272.

変数の宣言で 変数名の前にポインタ宣言子「*」を付けると ポインタ変数になる。 この場合、 int 型の変数 *p を宣言した結果、 実際には int 型変数へのポインタである int * 型変数 p が定義された と理解しておくとスッキリする。

mintty + bash + GNU C $ gcc pointer_ex1_1.c && ./a *p=2 a=2 重要

Page 536: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

• 変数が配置されたアドレスを扱うための変数

536

pointer_ex1_1.c int main() { int a = 1; int *p; p = &a; *p = 2; printf("*p=%d¥n", *p); printf(" a=%d¥n", a); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書pp.207-272.

mintty + bash + GNU C $ gcc pointer_ex1_1.c && ./a *p=2 a=2

0x~

&a

a

1

p

0x~

アドレス演算子「&」を用いて int 型変数 a のアドレス &a を int 型の変数へのポインタ p に代入する

Page 537: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

• 変数が配置されたアドレスを扱うための変数

537

pointer_ex1_1.c int main() { int a = 1; int *p; p = &a; *p = 2; printf("*p=%d¥n", *p); printf(" a=%d¥n", a); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書pp.207-272.

mintty + bash + GNU C $ gcc pointer_ex1_1.c && ./a *p=2 a=2

int 型の変数へのポインタ p の前に 間接演算子「*」を付けて *p とすると ポインタ変数 p が指し示すアドレスを int 型の変数としてアクセス出来る。 今 p には変数 a のアドレス &a が 入っているので、 *p は変数 a を意味するようになる

0x~ *p⇒a

1

p

0x~ &a

2

実際 *p に代入した値 2 が a に反映されていることが確認出来る。

Page 538: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

p

0x~

ポインタ変数

• 変数が配置されたアドレスを扱うための変数

538

pointer_ex1_1.c int main() { int a = 1; int *p; p = &a; *p = 2; printf("*p=%d¥n", *p); printf(" a=%d¥n", a); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書pp.207-272.

mintty + bash + GNU C $ gcc pointer_ex1_1.c && ./a *p=2 a=2

ポインタ変数pには 変数aのアドレス&aが入っている この状態で*pは アドレス&aにある変数 つまり変数aを意味する。

0x~ *p⇒a

1

&a⇒

2

Page 539: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

• 同じ「*」だが宣言時とそれ以外で意味が異なる

539

宣言時 それ以外

*p pをポインタとして宣言(※1) *pの格納値(※2)

*p=x pにxを代入(※3) *pにxを代入(※4)

要注意

pointer_ex1_1.c

教科書pp.207-272., [1] pp.250,268-269.

pointer_ex1_2.c

int a = 1; int *p; // ※1 p = &a; *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

int a = 1; int *p = &a; // ※3 *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

Page 540: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

• 同じ「*」だが宣言時とそれ以外で意味が異なる

540

宣言時 それ以外

*p pをポインタとして宣言(※1) *pの格納値(※2)

*p=x pにxを代入(※3) *pにxを代入(※4)

要注意

pointer_ex1_1.c

教科書pp.207-272., [1] pp.250,268-269.

pointer_ex1_2.c

int a = 1; int *p; // ※1 p = &a; *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

int a = 1; int *p = &a; // ※3 *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

int型の変数 *p を宣言した 実際に作成されたのは int型のポインタ変数 p

pが指すアドレスの格納値

Page 541: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

• 同じ「*」だが宣言時とそれ以外で意味が異なる

541

宣言時 それ以外

*p pをポインタとして宣言(※1) *pの格納値(※2)

*p=x pにxを代入(※3) *pにxを代入(※4)

要注意

pointer_ex1_1.c

教科書pp.207-272., [1] pp.250,268-269.

pointer_ex1_2.c

int a = 1; int *p; // ※1 p = &a; *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

int a = 1; int *p = &a; // ※3 *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

特に※3に注意 *p に &a を代入している のではなく p に &a を代入している

この2つの代入は 同じ処理を意味する

Page 542: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

• 同じ「*」だが宣言時とそれ以外で意味が異なる

542

宣言時 それ以外

*p pをポインタとして宣言(※1) *pの格納値(※2)

*p=x pにxを代入(※3) *pにxを代入(※4)

要注意

pointer_ex1_1.c

教科書pp.207-272., [1] pp.250,268-269.

pointer_ex1_2.c int a = 1; int *p = &a; // ※3 *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

int a = 1; int *p; // ※1 p = &a; *p = 2; // ※4 printf("*p=%d¥n", *p);// ※2

int型の変数 *p を宣言して int型のポインタ変数 p に p = &a と代入 つまりpが指すアドレスを&aに

pが指すアドレスの格納値 つまり変数aの格納値を2に

Page 543: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

• 同じ「*」だが宣言時とそれ以外で意味が異なる

543

ポインタ変数pの宣言 (言い換えると、ある型の変数*pを宣言)し 宣言した変数pに対して アドレスxを代入している

ポインタ変数pが指すアドレスの中身 (言い換えると、ある型の変数*p)を 操作(参照or代入)する

要注意

*は間接演算子 indirection operator または間接参照演算子 dereference operator

教科書pp.207-272., [1] pp.250,268-269.

*はポインタ宣言子 pointer declarator

宣言時 それ以外

*p pをポインタとして宣言(※1) *pの格納値(※2)

*p=x pにxを代入(※3) *pにxを代入(※4)

Page 544: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

544

pointer_ex2.cpp

6 7 8 9 10 11 12 13 14 15 16 17

教科書pp.207-272.

要注意

mintty + bash + GNU C $ gcc pointer_ex2.c && ./a &a =0x000000000022cb0c p1=0x000000000022cb0c q2=0x000000000022cb0c a =1 *p1=1 *p2=1

int a = 1; int *p1 = &a; int *p2; p2 = &a; 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);

実際に *p1 と p1 のどちらが &a になっているか 確認してみましょう。

Page 545: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 「*」と「=」の使い方は要注意

545

pointer_ex2.cpp

6 7 8 9 10 11 12 13 14 15 16 17

教科書pp.207-272.

要注意

mintty + bash + GNU C $ gcc pointer_ex2.c && ./a &a =0x000000000022cb0c p1=0x000000000022cb0c p2=0x000000000022cb0c a =1 *p1=1 *p2=1

int a = 1; int *p1 = &a; int *p2; p2 = &a; 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);

宣言時は「*」が間接演算子ではなく ポインタ宣言子として働いている 宣言時に初期化すると *p1 ではなく p1 に &a を代入している

p2 に &a を代入している

宣言時以外は「*」が関節演算子として働く ポインタの前に*が付くと、 指し示すアドレスに格納されている値が 操作の対象となる

*p1 ではなく p1 に &a が 代入される事が確認出来る

Page 546: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

備考: ポインタの表示

• %p

• void *;ポインタとして印字(処理系依存)

546

pointer_ex2.cpp printf("&a =%#0*p¥n", sizeof(&a )*2+2, &a );

第3週資料pp.24-33.

mintty + bash + GNU C $ gcc pointer_ex2.c && ./a &a =0x000000000022cb0c p1=0x000000000022cb0c p2=0x000000000022cb0c a =1 *p1=1 *p2=1

#: 16進表示が0でない場合、先頭を0xにする 0: フィールド幅いっぱいに左側から0を詰める *: 最小フィールド幅を引数で指定 p: void *;ポインタとして印字

%*pによる最小フィールド幅指定 1バイト=16進数2桁 先頭の0xで更に2桁

11

Page 547: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 宣言時の「*」が係る場所にも注意

547

pointer_ex3_1.cpp int *p, q; printf("sizeof(p)=%d¥n", sizeof(p)); printf("sizeof(q)=%d¥n", sizeof(q));

6 7 8 9

教科書pp.207-272.

要注意

Cygwin64 + bash + GNU C

$ gcc pointer_ex3_1.c && ./a sizeof(p)=8 sizeof(q)=4

p は「int *」型の宣言(int型へのポインタ変数) q は「int 」型の宣言(int型の変数) 複数の変数を同時に宣言する場合 変数名の直前に ポインタ宣言子「*」を付けた変数だけが ポインタ変数になる 要注意

p,q 共にポインタとして 宣言するには int *p, *q; または int *p; int *q; とする必要がある。

サイズが違うので p,q が別の型だと分かる

Page 548: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の宣言と代入

• 宣言時の「*」が係る場所にも注意

548

pointer_ex3_1.cpp int *p, q; printf("sizeof(p)=%d¥n", sizeof(p)); printf("sizeof(q)=%d¥n", sizeof(q));

6 7 8 9

教科書pp.207-272.

要注意

Cygwin64 + bash + GNU C $ gcc pointer_ex3_1.c && ./a sizeof(p)=8 sizeof(q)=4

p は「int *」型の宣言(int型へのポインタ変数) q は「int 」型の宣言(int型の変数) 複数の変数を同時に宣言する場合 変数名の直前に ポインタ宣言子「*」を付けた変数だけが ポインタ変数になる 要注意

p,q 共にポインタとして 宣言するには int *p, *q; または int *p; int *q; とする必要がある。

int 型の変数 *p と q を宣言している

int 型の変数 *p と *q を宣言している

Page 549: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

549

pointer_ex4.c 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]); }

6 7 8 9 10 11 12 13 14 15 16 17 18

教科書pp.207-272.

Cygwin64+mintty+bash+GNU C $ gcc pointer_ex4.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

結果がどうなるかは別として アドレス演算子を使って 変数のアドレスを入れなくても 適当な値を入れても動く。

Page 550: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数

550

pointer_ex4.c 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]); }

6 7 8 9 10 11 12 13 14 15 16 17 18

教科書pp.207-272.

Cygwin64+mintty+bash+GNU C $ gcc pointer_ex4.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

結果が正しいかどうかは別として 配列の途中のアドレスを ポインタに入れることも出来る

Page 551: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数の引数とポインタ

値渡しと参照渡し(ポインタ渡し)の用途等

551

Page 552: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

552

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); 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

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

関数の引数は呼び出し元とは別の変数になっていた

第8週資料pp.21-23.

Page 553: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

553

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100

Page 554: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 参照渡し: 呼出し元の値の格納場所を渡す

554

call_by_pointer.c void sub(int *lo) { *lo = 200; } int main() { int lo = 100; sub(&lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

scanf で見たことがある書き方! &: アドレス演算子

教科書p.171.

引数で受け取った変数を変更すると 呼び出し元にも反映される

これは正確には ポインタ渡しと言う

変数loのアドレスを 渡している

mintty + bash + GNU C $ gcc call_by_pointer.c && ./a lo=200

Page 555: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• C++における参照渡し

555

call_by_reference.cpp 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_reference.cpp && ./a lo=200

4 5 6 7 8 9 10 11 12 13 14 15 16

参考

引数で受け取った変数を変更すると 呼び出し元にも反映される

C++では 本物の参照渡しが 可能になった

C++の参照渡しでは アドレス演算子「&」が不要

値が変化することが 分かり難いという デメリットもある

Page 556: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

call by pointer (ポインタ渡し)

• 呼び出し元の変数の内容を変更したい場合

556

swapi_ex1.c void swapi(int *a, int *b) { int c; c = *a; *a = *b; *b = c; }

教科書p.171.

void swapi(int *a, int *b); 関数 *a と *b の値を入れ替える

swapi_test.c int a, b; fprintf(stderr, "a = ? "); scanf("%d", &a); fprintf(stderr, "b = ? "); scanf("%d", &b); swapi(&a, &b); printf("a = %d¥n", a); printf("b = %d¥n", b);

Page 557: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

call by pointer (ポインタ渡し)

• 2つ以上の値を返したい場合

• 戻り値は1つしかないので、関数の引数にポインタを渡して、値を返す

557

modf_ex1.c double modf(double x, double *iptr) { *iptr = x < 0 ? ceil(x): floor(x); return x - *iptr; }

教科書p.171.

double modf(double x, double *iptr); 関数 浮動小数点数を整数部と小数部に分ける 戻り値: x の小数部を戻り値に x の整数部を *iptr に返す 戻り値は共に x と同じ符号を持つ JM: modf (3)

modf_test.c double x; double i; double f; fprintf(stderr, "x = ?¥b"); scanf("%lf", &x); f = modf(x, &i); printf("i : %f¥n", i); printf("f : %f¥n", f);

Page 558: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

call by pointer (ポインタ渡し)

• 任意の長さの配列を渡したい場合

• 例えば文字列等

558

strlen_ex1.c size_t strlen(const char *s) { size_t len = 0; while(s[len] != '¥0') { len++; } return len; }

教科書p.171.

size_t strlen(const char *s); 関数 '¥0'で終端された文字列の長さを返す

strlen_test.c char s[1024] = ""; fprintf(stderr, "s = ? "); scanf("%1023[^¥n]", &s); printf("strlen(s) = %d¥n", strlen(s));

値が書き変えられては困る場合 const char への * (ポインタ) にしておくと、この関数を使っても 与えた内容が変更されないことを ある程度保証することが出来る

Page 559: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

const 修飾子

• const 型: 変数の値を変更出来なくなる

559

const_ex1.c const int i = 0; // 初期化は出来る int const j = 0; // const int も int const も同じ意味 i = 1; // const を付けた変数には代入出来ない j = 1; // const を付けた変数には代入出来ない

6 7 8 9

mintty + bash + GNU C $ gcc const_ex1.c const_ex1.c: 関数 ‘main’ 内: const_ex1.c:8:5: エラー: 読み取り専用変数 ‘i’ への代入です i = 1; // Error: i is const ^ const_ex1.c:9:5: エラー: 読み取り専用変数 ‘j’ への代入です j = 1; // Error: j is const ^

const 修飾子は型修飾子(type-qualifier)の一種 型修飾子は型名の前後どちらにつけても良い

変更しようとするとコンパイル時に エラーになるので 本来書き変えてはいけない値を 書き変えてしまうことで生じるバグを 未然に防げる

教科書p.308,310,314., [1] pp.240,257,261-262.

Page 560: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

const 修飾子

• const char 型へのポインタ

560

const_ex2.c char s[] = "hello, world"; const char *p; // ポインタの場合 *p が const になる p = s; // ポインタへは代入出来る *p = 'H'; // ポインタ指し示す先の変数には代入出来ない p[7] = 'W'; // ポインタ指し示す先の変数には代入出来ない *(char *) p = 'H'; // const のない型へ cast してやると代入出来る

6 7 8 9 10 11

mintty + bash + GNU C $ gcc const_ex2.c const_ex2.c: 関数 ‘main’ 内: const_ex2.c:9:6: エラー: 読み取り専用位置 ‘*p’ への代入です *p = 'H'; // Error: *p is const ^ const_ex2.c:10:8: エラー: 読み取り専用位置 ‘*(p + 7u)’ への代入です p[7] = 'W'; // Error: p[x] is const ^

ただし、わざわざ const を付けているということは 変更してはいけない、 または変更しないことを前提としているのであるから 普通は、特別に理由がない限り無理矢理書き変えてはいけない

教科書p.308,310,314., [1] pp.240,257,261-262.

char const * 型 const char * 型

Page 561: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

const 修飾子

• char 型への const ポインタ

561

const_ex3.c char s[] = "hello, world"; char *const p = s; // p が const で *p が char になる p = s; // p が const なのでポインタへは代入出来ない *p = 'H'; // ポインタ指し示す先の変数には代入出来る p[7] = 'W'; // ポインタ指し示す先の変数には代入出来る

6 7 8 9 10

mintty + bash + GNU C $ gcc const_ex3.c const_ex3.c: 関数 ‘main’ 内: const_ex3.c:8:5: エラー: 読み取り専用変数 ‘p’ への代入です p = s; // Error: p is const ^

const char *p と char const *p は同じだが char * const p は意味が異なる 前者は *p が const char つまり p は変数で *p が定数 後者は *const p が char つまり p は定数で *p は変数 である

* がどこに係っているか よく考えるましょう

教科書p.308,310,314., [1] pp.240,257,261-262.

char * const 型

Page 562: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列とポインタ

1次元配列とポインタの相違点

562

Page 563: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数とアドレス演算

• 例: 16bit short型little endianの場合

0x34 0x~00

0x12 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

short a = 0x1234; short *pa = &a;

*pa

±1するとsizeof(*pa)単位で アドレスが増減する つまり short 型配列の 0要素目、1要素目、... という意味になる

563

pa

pa+1

pa+2

pa+3

*(pa+1)

*(pa+2)

*(pa+3)

要注意

教科書pp.207-272.

Page 564: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数とアドレス演算

• 例: 32bit int型little endianの場合

0x78 0x~00

0x56 0x~01

0x34 0x~02

0x12 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

int a = 0x12345678; int *pa = &a;

*pa

±1するとsizeof(*pa)単位で アドレスが増減する つまり int 型配列の 0要素目、1要素目、... という意味になる

564

pa

pa+1

*(pa+1)

要注意

教科書pp.207-272.

Page 565: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の配列的利用法

• 例: 16bit short型little endianの場合

0x34 0x~00

0x12 0x~01

0x?? 0x~02

0x?? 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

short a = 0x1234; short *pa = &a;

pa[0]

配列同様[x]で先頭x個目の 要素にアクセス出来る 要素の頭に&を付けると アドレスが得られる

565

&pa[0]

&pa[1]

&pa[2]

&pa[3]

pa[1]

pa[2]

pa[3]

教科書pp.207-272.

Page 566: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ変数の配列的利用法

• 例: 32bit int型little endianの場合

0x78 0x~00

0x56 0x~01

0x34 0x~02

0x12 0x~03

: :

: :

0x?? 0x~04

0x?? 0x~05

0x?? 0x~06

: :

: :

0x?? 0x~07

0x?? 0x~08

int a = 0x12345678; int *pa = &a;

pa[0]

配列同様[x]で先頭x個目の 要素にアクセス出来る 要素の頭に&を付けると アドレスが得られる

566

&pa[0]

&pa[1]

pa[1]

教科書pp.207-272.

Page 567: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

• 64bit OSで 8bit char 型の例 (little endian)

0x10 0x23cb08

⋮ ⋮ char a[] = { 0,1,2,3, 4,5,6,7, }; char*p = a;

p

567

&p

&a =a =p

a[0]

教科書pp.207-272.

0xcb 0x23cb09

0x23 0x23cb0a

0x00 0x23cb0b

0x00 0x23cb0c

0x00 0x23cb0d

0x00 0x23cb0e

0x00 0x23cb0f

0x00 0x23cb10

0x01 0x23cb11

0x02 0x23cb12

0x03 0x23cb13

0x04 0x23cb14

0x05 0x23cb15

0x06 0x23cb16

0x07 0x23cb17

⋮ ⋮

a

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

sizeof(a) は aの1要素当たりのバイト数×要素数 つまりsizeof(char)*N

sizeof(p) は OSのアドレス空間のビット数/8 つまりsizeof(char *)

&a[4] =&p[4] =p+4

Page 568: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

• 64bit OSで 16bit short 型の例 (little endian)

0x10 0x23cb08

⋮ ⋮ short a[] = { 0x0001,0x0203, 0x0405,0x0607, }; short *p = a;

p

568

&p

&a =a =p a[0]

教科書pp.207-272.

0xcb 0x23cb09

0x23 0x23cb0a

0x00 0x23cb0b

0x00 0x23cb0c

0x00 0x23cb0d

0x00 0x23cb0e

0x00 0x23cb0f

0x01 0x23cb10

0x00 0x23cb11

0x03 0x23cb12

0x02 0x23cb13

0x05 0x23cb14

0x04 0x23cb15

0x07 0x23cb16

0x06 0x23cb17

⋮ ⋮

a[1]

a[2]

a[3]

a &a[2] =&p[2] =p+2

Page 569: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

• 64bit OSで 32bit int 型の例 (little endian)

0x10 0x23cb08

⋮ ⋮ int a[] = { 0x00010203, 0x04050607, }; int *p = a;

p

569

&p

&a =a =p

a[0]

教科書pp.207-272.

0xcb 0x23cb09

0x23 0x23cb0a

0x00 0x23cb0b

0x00 0x23cb0c

0x00 0x23cb0d

0x00 0x23cb0e

0x00 0x23cb0f

0x03 0x23cb10

0x02 0x23cb11

0x01 0x23cb12

0x00 0x23cb13

0x07 0x23cb14

0x06 0x23cb15

0x05 0x23cb16

0x04 0x23cb17

⋮ ⋮

a[1]

a &a[1] =&p[1] =p+1

Page 570: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列 int p[N];

ポインタ int *p;

sizeof(p) ○ ○ 変数pの割り当てバイト数

&p △ ○ 変数pのアドレス(配列の場合&pとpは同じ)

p ○ ○ アドレスp(p[0]のアドレス)

*p ○ ○ アドレスpの格納値(p[0]の格納値)

p[x] ○ ○ アドレスpを先頭にしてx個目の要素(p[x])の格納値

*(p+x) ○ ○ アドレスpを先頭にしてx個目の要素(p[x])の格納値

&p[x] ○ ○ アドレスpを先頭にしてx個目の要素(p[x])のアドレス

p+x ○ ○ アドレスpを先頭にしてx個目の要素(p[x])のアドレス

p+=x × ○ アドレスpを先頭にしてx個目の要素(p[x])のアドレス

1次元配列とポインタ

• 機能としてはほぼ同じ

• ポインタはアドレスを変更可能(少し柔軟)

570

配列は1要素のバイト数×要素数 ポインタはアドレス空間のビット数/8

教科書pp.207-272.

Page 571: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

571

pointer_ex5.c 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);

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

cygwin64 + mintty + bash + GNU C $ gcc pointer_ex5.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

教科書pp.207-272.

Page 572: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

572

pointer_ex5.c 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);

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

cygwin64 + mintty + bash + GNU C $ gcc pointer_ex5.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

教科書pp.207-272.

配列 int p[N];

ポインタ int *p;

sizeof(p) ○ ○ 変数pの割り当てバイト数

a は int 型 10 個分のサイズ つまり sizeof(int[10])

p は int * 型 1 個分のサイズ つまり sizeof(int *)

Page 573: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

573

pointer_ex5.c 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);

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

cygwin64 + mintty + bash + GNU C $ gcc pointer_ex5.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

教科書pp.207-272.

配列 int p[N];

ポインタ int *p;

&p △ ○ 変数pのアドレス(配列の場合&pとpは同じ)

p ○ ○ アドレスp(p[0]のアドレス)

*p ○ ○ アドレスpの格納値(p[0]の格納値)

配列変数aはメモリ上のどこかに確保されている a は配列全体を意味する(実際は先頭アドレス) &a は配列変数aのアドレス(aと同一) ポインタ変数pはメモリ上のどこかに確保されている &pはそのアドレス p はポインタ変数 p に格納されているアドレス この例では配列変数aの先頭アドレス&aまたはa *a, *p は各アドレス a, p に格納されたデータ

0x22aaa0 a[0]

0

0x22aaa4 a[1]

1

⋮ ⋮

0x22aa98 p

0x22aaa0

Page 574: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

574

pointer_ex5.c 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);

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

cygwin64 + mintty + bash + GNU C $ gcc pointer_ex5.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

教科書pp.207-272.

Page 575: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

575

pointer_ex5.c 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);

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

cygwin64 + mintty + bash + GNU C $ gcc pointer_ex5.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

教科書pp.207-272. 配列 int p[N];

ポインタ int *p;

p[x] ○ ○ アドレスpを先頭にしてx個目の要素(p[x])の格納値

*(p+x) ○ ○ アドレスpを先頭にしてx個目の要素(p[x])の格納値

a の x 番目の要素にアクセスしている

Page 576: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

1次元配列とポインタ

576

pointer_ex5.c 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);

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

cygwin64 + mintty + bash + GNU C $ gcc pointer_ex5.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

教科書pp.207-272. 配列 int p[N];

ポインタ int *p;

&p[x] ○ ○ アドレスpを先頭にしてx個目の要素(p[x])のアドレス

p+x ○ ○ アドレスpを先頭にしてx個目の要素(p[x])のアドレス

p+=x × ○ アドレスpを先頭にしてx個目の要素(p[x])のアドレス

pに1を足しているのに 結果が4増えていることが 確認出来る

Page 577: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

配列を引数に取る関数

577

Page 578: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列のサイズ

• sizeof で得られるバイト数

0x?? a = &a[ -1]

: :

: :

0x?? a+N = &a[N ]

0x?? a+N+1 = &a[N+1]

sizeof(a) = sizeof(int) * N

int a[N];

578

sizeof(int)

0x?? a = &a[ 0]

0x?? a + 1 = &a[ 1]

0x?? a + 2 = &a[ 2]

0x?? :

0x?? :

0x?? a+N-1 = &a[N-1]

sizeof(a[0]) = sizeof(int)

講義資料 第3週p.42-51.

sizeof_ex3.c int a[10]; printf("sizeof(int) : %2d¥n", sizeof(int)); //int型の割り当てバイト数 printf("sizeof(a) : %2d¥n", sizeof(a)); //配列変数aの割り当てバイト数 printf("sizeof(a[0]) : %2d¥n", sizeof(a[0])); //変数a[0]の割り当てバイト数 printf("sizeof(a)/sizeof(a[0]) : %2d¥n", sizeof(a)/sizeof(a[0])); //配列変数aの要素数

mintty + bash + GNU C $ gcc sizeof_ex3.c && ./a sizeof(int) : 4 sizeof(a) : 40 sizeof(a[0]) : 4 sizeof(a)/sizeof(a[0]) : 10

オレンジ色は 未割当のメモリ

Page 579: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 引数名直後の1次元はポインタ扱いになる

579 [1] pp.121-122.

pointer_ex6.c int main() { // 0 1 2 3 4 5 6 7 8 9 int a[10] = { 2, 3, 5, 7,11,13,17,19,23,29}; int b[2][5] = { 2, 3, 5, 7,11,13,17,19,23,29}; printf("sizeof(a) = %d¥n", sizeof(a)); func_with_array1d(a); func_with_pointer(a); printf("sizeof(b) = %d¥n", sizeof(b)); func_with_array2d(b); func_with_pointer(b); //a += 1; // It's impossible. Because a is an array. //b += 1; // It's impossible. Because b is an array. return EXIT_SUCCESS; }

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

mintty + bash + GNU C $ gcc pointer_ex6.c && ./a pointer_ex6.c: 関数 ‘main’ 内: pointer_ex6.c:37:21: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています func_with_pointer(b); ^ pointer_ex6.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(b) = 40 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8

pointer_ex6.c void func_with_pointer(int *p) { printf("sizeof(p) = %d¥n", sizeof(p)); }

20 21 22 23

Page 580: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 引数名直後の1次元はポインタ扱いになる

580 [1] pp.121-122.

pointer_ex6.c int main() { // 0 1 2 3 4 5 6 7 8 9 int a[10] = { 2, 3, 5, 7,11,13,17,19,23,29}; int b[2][5] = { 2, 3, 5, 7,11,13,17,19,23,29}; printf("sizeof(a) = %d¥n", sizeof(a)); func_with_array1d(a); func_with_pointer(a); printf("sizeof(b) = %d¥n", sizeof(b)); func_with_array2d(b); func_with_pointer(b); //a += 1; // It's impossible. Because a is an array. //b += 1; // It's impossible. Because b is an array. return EXIT_SUCCESS; }

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

mintty + bash + GNU C $ gcc pointer_ex6.c && ./a pointer_ex6.c: 関数 ‘main’ 内: pointer_ex6.c:37:21: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています func_with_pointer(b); ^ pointer_ex6.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(b) = 40 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8

pointer_ex6.c void func_with_pointer(int *p) { printf("sizeof(p) = %d¥n", sizeof(p)); }

20 21 22 23

Page 581: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 引数名直後の1次元はポインタ扱いになる

581 [1] pp.121-122.

mintty + bash + GNU C $ gcc pointer_ex6.c && ./a pointer_ex6.c: 関数 ‘main’ 内: pointer_ex6.c:37:21: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています func_with_pointer(b); ^ pointer_ex6.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(b) = 40 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8

備考より関数の引数に与えた int b[2][5] が int (*)[5] 扱い されていることが分かる

pointer_ex6.c int main() { // 0 1 2 3 4 5 6 7 8 9 int a[10] = { 2, 3, 5, 7,11,13,17,19,23,29}; int b[2][5] = { 2, 3, 5, 7,11,13,17,19,23,29}; printf("sizeof(a) = %d¥n", sizeof(a)); func_with_array1d(a); func_with_pointer(a); printf("sizeof(b) = %d¥n", sizeof(b)); func_with_array2d(b); func_with_pointer(b); //a += 1; // It's impossible. Because a is an array. //b += 1; // It's impossible. Because b is an array. return EXIT_SUCCESS; }

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

pointer_ex6.c void func_with_pointer(int *p) { printf("sizeof(p) = %d¥n", sizeof(p)); }

20 21 22 23

Page 582: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• ポインタ扱いなので配列サイズが取れない

582 [1] pp.121-122.

mintty + bash + GNU C $ gcc pointer_ex6.c && ./a pointer_ex6.c: 関数 ‘main’ 内: pointer_ex6.c:37:21: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています func_with_pointer(b); ^ pointer_ex6.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(b) = 40 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8

pointer_ex6.c void func_with_array1d(int x[10]) { printf("sizeof(x) = %d¥n", sizeof(x)); printf("sizeof(x[0]) = %d¥n", sizeof(x[0])); x += 1; // x はポインタなので変更出来る }

4 5 6 7 8 9

pointer_ex6.c void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d¥n", sizeof(y)); printf("sizeof(y[0]) = %d¥n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d¥n", sizeof(y[0][0])); y += 1; // y はポインタなので変更出来る //y[0] += 1; // y[0] は配列なので変更来ない }

11 12 13 14 15 16 17 18

sizeof(int[2][5]) ではなく sizeof(int(*)[5])

sizeof(y[0])は sizeof(int[5])

sizeof(int[10]) ではなく sizeof(int*)

配列へのポインタなので 2次元目以降のサイズは取れる

1次元目はポインタになるので 配列サイズが取れない

Page 583: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• ポインタ扱いなのでアドレスが変更出来る

583 [1] pp.121-122.

mintty + bash + GNU C $ gcc pointer_ex6.c && ./a pointer_ex6.c: 関数 ‘main’ 内: pointer_ex6.c:37:21: 警告: 互換性のないポインタ型から 1 番目の ‘func_with_pointer’ の引数に渡しています func_with_pointer(b); ^ pointer_ex6.c:20:6: 備考: expected ‘int *’ but argument is of type ‘int (*)[5]’ void func_with_pointer(int *p) ^ sizeof(a) = 40 sizeof(x) = 8 sizeof(x[0]) = 4 sizeof(p) = 8 sizeof(b) = 40 sizeof(y) = 8 sizeof(y[0]) = 20 sizeof(y[0][0]) = 4 sizeof(p) = 8

pointer_ex6.c void func_with_array1d(int x[10]) { printf("sizeof(x) = %d¥n", sizeof(x)); printf("sizeof(x[0]) = %d¥n", sizeof(x[0])); x += 1; // x はポインタなので変更出来る }

4 5 6 7 8 9

pointer_ex6.c void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d¥n", sizeof(y)); printf("sizeof(y[0]) = %d¥n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d¥n", sizeof(y[0][0])); y += 1; // y はポインタなので変更出来る //y[0] += 1; // y[0] は配列なので変更来ない }

11 12 13 14 15 16 17 18

y はポインタだが、 y[0] は int[5] 配列だから アドレスの変更が出来ない アンコメントして コンパイル出来ない事を確認せよ

定義は配列変数 int x[10] に見えるが 実はポインタ変数 int *p なので アドレスの変更出来る

定義は配列変数 int y[2][5]に見えるが 実はポインタ変数 int (*y)[5] なので アドレスの変更出来る

Page 584: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認: 関数定義の引数と配列

• 以下の個所を変えてコンパイルし確認せよ

584 [1] pp.121-122.

pointer_ex6.c void func_with_array1d(int x[10]) { printf("sizeof(x) = %d¥n", sizeof(x)); printf("sizeof(x[0]) = %d¥n", sizeof(x[0])); x += 1; // It's possible. Because x is pointer. }

4 5 6 7 8 9

int x[10] ではなく int x[20] や int x[] にしても 問題なくコンパイル出来る事を確認せよ

pointer_ex6.c void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d¥n", sizeof(y)); printf("sizeof(y[0]) = %d¥n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d¥n", sizeof(y[0][0])); y += 1; // It's possible. Because y is a pointer to an array. //y[0] += 1; // It's impossible. Because y is an array. }

11 12 13 14 15 16 17 18

int y[2][5] ではなく int y[20][5], int y[][5]にしても 問題なくコンパイル出来る事を確認せよ int y[2][10] だと コンパイル出来ないことを確認せよ

変数名に一番近い次元はポインタ扱いされるので 要素数が意味を持たなくなっていることを確認せよ

Page 585: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 引数名直後の1次元は要素数を省略すべき

585 [1] pp.121-122.

pointer_ex6.c void func_with_array1d(int x[10]) { printf("sizeof(x) = %d¥n", sizeof(x)); printf("sizeof(x[0]) = %d¥n", sizeof(x[0])); x += 1; // It's possible. Because x is pointer. }

4 5 6 7 8 9

int x[10] という引数の宣言は int *x と同じ意味

pointer_ex6.c void func_with_array2d(int y[2][5]) { printf("sizeof(y) = %d¥n", sizeof(y)); printf("sizeof(y[0]) = %d¥n", sizeof(y[0])); printf("sizeof(y[0][0]) = %d¥n", sizeof(y[0][0])); y += 1; // It's possible. Because y is a pointer to an array. //y[0] += 1; // It's impossible. Because y is an array. }

11 12 13 14 15 16 17 18

int y[2][5] という引数の宣言は int (*y)[5] と同じ意味

int x[10] より int x[] int y[2][5] より int y[][5] と書く方が実態に合っている

int *x int (*y)[5] と書くのが最も正確

簡易表記?

無意味な数値は なるべく書くべきでない

Page 586: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 関数定義の仮引数では以下の定義は同義

586 [1] pp.121-122.

int sub(char s[N]) { // ... }

int sub(char s[]) { // ... }

int sub(char s[M][N]) { // ... }

int sub(char s[][N]) { // ... }

int sub(char *s) { // ... }

int sub(char (*s)[N]) { // ... }

= =

= =

int sub(char s[L][M][N]) { // ... }

int sub(char s[][M][N]) { // ... }

int sub(char (*s)[M][N]) { // ... }

= =

...

...

...

1次元配列 2次元配列 3次元配列

Page 587: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 関数定義の仮引数では以下の定義は同義

587 [1] pp.121-122.

int sub(char s[N]) { // ... }

int sub(char s[]) { // ... }

int sub(char s[M][N]) { // ... }

int sub(char s[][N]) { // ... }

int sub(char *s) { // ... }

int sub(char (*s)[N]) { // ... }

= =

= =

int sub(char s[L][M][N]) { // ... }

int sub(char s[][M][N]) { // ... }

int sub(char (*s)[M][N]) { // ... }

= =

...

...

...

1次元配列 2次元配列 3次元配列

関数の引数では 配列の最初の次元は 無視されてポインタ扱いになる

Page 588: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数定義の引数と配列

• 関数定義の仮引数では以下の定義は同義

588 [1] pp.121-122.

int sub(char s[N]) { // ... }

int sub(char s[]) { // ... }

int sub(char s[M][N]) { // ... }

int sub(char s[][N]) { // ... }

int sub(char *s) { // ... }

int sub(char (*s)[N]) { // ... }

= =

= =

int sub(char s[L][M][N]) { // ... }

int sub(char s[][M][N]) { // ... }

int sub(char (*s)[M][N]) { // ... }

= =

...

...

...

1次元配列 2次元配列 3次元配列

関数の引数では配列の最初の次元は無視されてポインタ扱いになる 配列っぽく書いても良いが実際にはポインタとして処理される

Page 589: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

複雑なポインタの宣言

* はどこに係っているのか?

589

Page 590: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演算子の優先度

演算子 結合規則 備考

( ) [ ] -> . 左から右→

! ~ ++ -- + - * & (type) sizeof 右から左← 単項演算子

* / % 左から右→ 二項演算子

+ - 左から右→ 二項演算子

<< >> 左から右→ bitシフト

< <= > >= 左から右→ 関係演算子

== != 左から右→ 等値演算子

& 左から右→ bit毎のAND

^ 左から右→ bit毎のXOR

| 左から右→ bit毎のOR

&& 左から右→ 論理演算子(AND)

|| 左から右→ 論理演算子(OR)

?: 右から左← 三項演算子

= += -= *= /= %= &= ^= |= <<= >>= 右から左← 代入演算子

, 左から右→

[1] p.65. より

優先度

590

Page 591: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

複雑なポインタの宣言

• 配列はポインタ自身か?指している先か?

591

0x22ab98 p2

0x22aaa0

0x22aba0 a2[0]

0

0x22aba4 a2[1]

1

⋮ ⋮

0x22abbb a2[6]

1

pointer_ex7.c int *(p1[7]); // int *p1[7]; と同義 int (*p2)[7];

0x22aa98 a1

0

0x22aaa0 p1[0]

0x22aa98

0x22aaa8 p1[1]

?

⋮ ⋮

0x22aad0 p1[6]

?

int a1; int a2[7]; int *(p1[7]); int (*p2)[7];

教科書.pp.235-239., [1]pp.148-153.

[] は * よりも優先順位の高い演算子

int *(p1[7]); → *(p1[x])がint

int (*p2)[7]; → *p2がint[7]

Page 592: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

複雑なポインタの宣言

• * を付けると何になるか?

592

pointer_ex7.c int *(p1[7]); // int *p1[7]; と同義 int (*p2)[7]; printf("sizeof( p1)=%2d¥n", sizeof( p1)); printf("sizeof( p2)=%2d¥n", sizeof( p2)); printf("sizeof(*p1)=%2d¥n", sizeof(*p1)); printf("sizeof(*p2)=%2d¥n", sizeof(*p2));

教科書.pp.235-239., [1]pp.148-153.

mintty + bash + GNU C $ gcc pointer_ex7.c && ./a sizeof( p1)=56 sizeof( p2)= 8 sizeof(*p1)= 8 sizeof(*p2)=28

[] は * よりも優先順位の高い演算子 宣言の読み方

要注意

p1[x]に*が付く、つまり*p1[x]がint型になる 従ってp1[x]はint*型、つまりp1は要素数7のint*型配列

p2に*が付く、つまり*p2が要素数7のint型配列になる 従ってp2は「『要素数7のint型配列』へのポインタ」

int *(p1[7]); → *(p1[x])がint

int (*p2)[7]; → *p2がint[7]

Page 593: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数へのポインタ

関数をポインタ変数に代入して呼び出す

593

Page 594: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数へのポインタ

• 関数へのポインタの例

594

pointer_ex8.c int compi(const int *a, const int *b) { return *a - *b; } int main() { int a, b; int (*fnc)(const int *a, const int *b) = compi; fprintf(stderr, "a = ? "); scanf("%d", &a); fprintf(stderr, "b = ? "); scanf("%d", &b); printf("(*fnc)(&a, &b) = %d¥n", (*fnc)(&a, &b)); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

mintty + bash + GNU C $ gcc pointer_ex8.c && ./a a = ? 10 b = ? 20 (*fnc)(&a, &b) = -10

関数への ポインタ変数 fnc に関数 compi を 代入して

fnc 経由で 関数 compi を 呼び出す

Page 595: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数へのポインタ

• 作り方 • 関数のプロトタイプ宣言を書き写す • 関数名を変数名に書き変える • 変数名を ( ) で囲む • 変数名の前に * を付ける

• 例: • 格納したい関数のプロトタイプ宣言

• int compi(const int *a, const int *b);

• 関数へのポインタの宣言 • int (*fnc)(const int *, const int *);

• 関数へのポインタによる関数の呼び出し • (*fnc)(&a, &b);

595

fnc という変数を宣言 戻り値が int int *型の引数を2つ取る 関数のアドレスを 格納出来る

fnc という変数に 格納されたアドレスにある 関数に引数を渡して実行

引数名は省略可能

Page 596: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数へのポインタ

• ポインタ変数に * が付いたら何になるか?

596

関数へのポインタ変数の宣言 int (*fnc)(int *a, int *b);

関数の定義 int cmp(int *a, int *b) { return *a - *b; }

関数のプロトタイプ宣言 int cmp(int *a, int *b);

fnc がポインタ変数で *fnc が 戻り値が int 型 引数が (int *a, int *b) の 関数という意味になる

cmp が 戻り値が int 型 引数が (int *a, int *b) の 関数という意味になる

関数へのポインタに代入と呼び出し fnc = cmp; (*fnc)(&x, &y);

*fnc とすれば 関数へのポインタが関数になる 演算子の優先順位は 高*>()低なので*fncに()が必要

Page 597: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数へのポインタ

• 関数関連の宣言では引数名は省略可能

• 関数のプロトタイプ宣言

• 関数へのポインタ変数の宣言

597

関数へのポインタ変数の宣言

関数へのポインタ変数の宣言 int (*fnc)(int *a, int *b);

関数のプロトタイプ宣言 int cmp(int *a, int *b);

int (*fnc)(int * , int * );

関数のプロトタイプ宣言 int cmp(int * , int * );

Page 598: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

関数へのポインタ

• 汎用型の場合キャストが必要

• 例: qsort や bsearch へ渡す比較関数

598

関数へのポインタ変数の宣言 int (*fnc)(void *a, void *b);

関数のプロトタイプ宣言 int cmp(int *a, int *b);

関数へのポインタに代入と呼び出し fnc = (int (*)(void *, void *)) cmp; (*fnc)(&x, &y);

Page 599: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

void 型と void 型へのポインタ

• void(=空洞)つまり大きさがない

• 関数に引数や戻り値がないことを意味する

• ポインタの指し示す先の大きさが不明(特定の型に縛られない)であることを意味する

599

変数の宣言 void a; // void 型の変数はないのでコンパイルエラー void *p; // p が void 型へのポインタ

大きさが0バイトのデータ つまり void a; には意味がないが 大きさが不明のデータでも先頭アドレス つまり void *p; には意味がある

0x~0

0x~1

0x~2

0x~3

0x~0

0x~1

0x~2

0x~3

p= 0x~0

Page 600: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

void 型と void 型へのポインタ

• void * 型は使用時に大きさを決めて使う

• 適当な型へのポインタとしてキャストする

600

void 型ポインタの例 int a; void *p = &a; // p に a のアドレスが入る *((int *)p) = 1; // p は void* なので *p は void だが // p を int* にキャストすると *p が int になる

0x~0

0x~1

0x~2

0x~3

0x~0

0x~1

0x~2

0x~3

*p は void なので意味がない

*((int*)p) は int なので意味がある p= 0x~0

Page 601: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ライブラリの qsort 関数

• void qsort(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *));

• 要素サイズsize,要素数nのデータbaseを比較関数cmpの結果に従い並べ替える

• 引数 • base: データへのポインタ

• n : データの要素数

• size: 1要素当りのバイト数

• cmp : 比較に用いる関数へのポインタ

• 戻り値 • なし

601 [1] pp.144-148, 319.

関数へのポインタ 並べ替えの際、 比較を可換にすることで 汎用性を持たせている。

並べ替えの順序 昇順、降順 データ型 int, double, 文字列

void * 型は 任意の方へのポインタ

JM: qsort (3)

Page 602: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

qsort 利用の例

• 比較関数を用意すれば任意データに使える

602

qsort_ex1.c int compi(const int *a, const int *b) { return *a - *b; }

28 29 30 31

mintty + bash + GNU C $ gcc qsort_ex1.c && ./a n = ? 10 v[] = 197 22 155 489 71 47 137 364 486 70 v[] = 22 47 70 71 137 155 197 364 486 489

qsort_ex1.c printiv(v, n); qsort(v, n, sizeof(int), (int (*)(const void *, const void *)) compi); printiv(v, n);

47 48 49

const void * を 引数とする関数として キャストする必要がある

int 型のデータの比較関数

int 型のデータの並べ替えの例

Page 603: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

qsort 利用の例

• 比較関数を用意すれば任意データに使える

603

qsort_ex2.c int strcmp_wrapper(const char **a, const char **b) { return strcmp(*a, *b); }

47 48 49 50

mintty + bash + GNU C $ gcc qsort_ex2.c && ./a n = ? 2 v[0] = "yocchzcmwhmufrdvde" v[1] = "iipfziuhu" v[0] = "iipfziuhu" v[1] = "yocchzcmwhmufrdvde"

qsort_ex2.c printsv(v, n); qsort(v, n, sizeof(char*), (int (*)(const void*,const void*))strcmp_wrapper); printsv(v, n);

67 68 69

const void * を 引数とする関数として キャストする必要がある

標準ライブラリ関数 strcmp のラッパー関数

配列へのポインタ並べ替えの例

Page 604: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ライブラリの2分探索関数

• void *bsearch(const void *key, const void *base, size_t n, size_t size, int (*cmp)(const void *keyval, const void *datum));

• ソート済み配列を二分探索(binary search)する • 引数

• key : 検索したい値へのポインタ • base : 検索対象のデータ集合へのポインタ • n : データの要素数 • size : データの1要素当りのバイト数 • cmp : データ比較用の関数へのポインタ

• 戻り値 • マッチした項目へのポインタを返す • マッチした項目がない場合NULLを返す

604 教科書 pp.198-202. JM: bsearch (3)

Page 605: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準ライブラリの2分探索関数

• 比較関数さえ用意すれば簡単に検索出来る

605 教科書 pp.198-202.

bsearch_ex1.c int cmp(const int *keyval, const int *datum) { return *keyval - *datum; }

4 5 6 7

bsearch_ex1.c p = bsearch(&key, data, sizeof(data)/sizeof(int), sizeof(int), (int (*)(const void*, const void*))cmp); if (p) { printf("data[%d] = %d¥n", p - data, *p); } else { printf("not found.d¥n"); }

29 30 31 32 33 34

bsearch_ex1.c { int data[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, }; int key; int *p;

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

mintty + bash + GNU C $ gcc bsearch_ex1.c && ./a key = ? 113 data[29] = 113

Page 606: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

動的配列

メモリの確保・解放とポインタによる配列

606

Page 607: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

動的配列

607

多くの問題では 配列のサイズを事前に (コンパイルの段階では) 決められない。

実行時、プログラムに 与えるデータや パラメータによって 配列のサイズは決まる。

プログラムの実行時に 配列のサイズを適宜に決める事が必要

malloc, calloc, realloc, free 関数

Page 608: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

malloc 関数

• void *malloc(site_t size); • 動的にメモリを確保する

• 引数: • size : 確保するメモリのバイト数

• 戻り値 • 確保したメモリへのポインタを返す • 確保したメモリの内容は初期化されない • エラーの場合は NULL を返す

608

JM: malloc (3)

Page 609: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

calloc 関数

• void *calloc(site_t nobj, site_t size); • 動的にメモリを確保する

• 引数: • nobj : メモリを確保する要素数 • size : 1要素当たりバイト数

• 戻り値 • 確保したメモリへのポインタを返す • 確保したメモリの内容は0で初期化される • エラーの場合は NULL を返す

609

JM: malloc (3)

Page 610: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

realloc 関数

• void *realloc(void *p, site_t size); • 動的に確保したメモリのサイズを変更する

• 引数: • p : サイズを変更するメモリへのポインタ • size : 変更後のバイト数

• 戻り値 • 確保したメモリへのポインタを返す • サイズ変更前後で小さい方のサイズまでは

前の内容が維持される • 増加した部分のメモリの内容は初期化されない • エラーの場合は NULL を返す

• 元のブロックは維持される

610

JM: malloc (3)

Page 611: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

free 関数

• void free(void *p); • 動的に確保したメモリを解放する

• 引数: • p : 解放するメモリへのポインタ

611

JM: malloc (3)

Page 612: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

動的配列の基本

• malloc で確保し free で解放する

612

配列 #define N 10 // 要素数は定数 // ... int a[N]; // 配列の確保 // 確保できないとコンパイルに失敗する a[i] = x; // 変数に対する操作 // 配列はスコープの終わりで // 自動的に開放される

動的配列 int N = 10; // 要素数は変数も可 // ... int *a = malloc(sizeof(int) * N); // メモリの確保 if (a == NULL) {// 確保できないと a に NULL が入る fprintf(stderr, "Error: malloc failed.¥n"); exit(EXIT_FAILURE); // エラー処理が必要 } a[i] = x; // 変数に対する操作 free(a); // メモリの解放 // 動的配列は解放しないといつまでも確保され続ける

Page 613: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

動的配列の基本

• malloc で確保し free で解放する

613

2次元画像の例 unsigned char *img; // 画像用の動的配列 (unsigned char 型へのポインタ) int w, h; // 画像の縦横サイズ // 動的にサイズを決める fprintf(stderr, "w = ?"); scanf("%d", &w); fprintf(stderr, "h = ?"); scanf("%d", &h); if ((img = malloc(3 * w * h)) == NULL) { // メモリーの動的確保 fprintf(stderr, "Error: in %s line %d: malloc failed¥n", __FILE__, __LINE__); exit(EXIT_FAILURE); } // ... // ここで確保したメモリーに対する処理を行う free(img); // 使い終わって不要になったメモリーの解放

Page 614: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

動的配列の例

• 1週目の bmptest.c と同じグラデーション

614

dynamic_array_ex1.c void print_ppm(unsigned char *img, int w, int h, int q); int main() { unsigned char *img; int w, h, x, y; fprintf(stderr, "w = ? "); scanf("%d", &w); fprintf(stderr, "h = ? "); scanf("%d", &h); if ((img = malloc(3 * w * h)) == NULL) { fprintf(stderr, "Error: in %s line %d: malloc failed¥n", __FILE__, __LINE__); exit(EXIT_FAILURE); } for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { img[3 * (w * y + x) + 0] = 255; // R img[3 * (w * y + x) + 1] = 255 * x / w; // G img[3 * (w * y + x) + 2] = 255 * y / h; // B } } print_ppm(img, w, h, UCHAR_MAX); free(img); return EXIT_SUCCESS; }

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

mintty + bash + GNU C $ gcc dynamic_array_test.c print_ppm.c && ./a | convert - a.bmp w = ? 255 h = ? 255

a.bmp

malloc で確保したメモリは 普通に1次元配列のように使える

Page 615: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

動的配列によるカラー画像

• 1次元配列を3次元配列のように使う

615

dynamic_array_ex1.c for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { img[3 * (w * y + x) + 0] = 255; // R img[3 * (w * y + x) + 1] = 255 * x / w; // G img[3 * (w * y + x) + 2] = 255 * y / h; // B } }

18 19 20 21 22 23 24

R G B R G B ... R G B

R G B R G B ... R G B

R G B R G B ... R G B

: : : : : : ⋱ : : :

R G B R G B ... R G B

w*3

h

x

y

img

img[3 * (w * y + x) + 0]

unsigned char *img; を unsigned char img[h][w][3]; と同じように使う

動的配列は1次元的にしか取れないため、 要素の位置は自分で計算する必要がある。

Page 616: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト形式PPM画像の書き出し

• PPMの書き出しを関数化してみる

616

print_ppm.c #include <stdio.h> void print_ppm(unsigned char *img, int w, int h, int q) { int c, x, y; printf("P3¥n"); printf("%d %d¥n", w, h); printf("%d¥n", q); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf(" "); for (c = 0; c < 3; c++) { printf(" %3d", img[3 * (w * y + x) +c]); } } printf("¥n"); } }

関数のプロトタイプ宣言 // 作った関数の本体(並括弧の中身)を取り除き // 末尾に ; (セミコロン)を付ける void print_ppm(unsigned char *img, int w, int h, int q);

R G B R G B ... R G B

R G B R G B ... R G B

R G B R G B ... R G B

: : : : : : ⋱ : : :

R G B R G B ... R G B

c

y

x

y, x, c のループで書き出す

Page 617: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト形式PPM画像の書き出し

• PPMの書き出しを関数化してみる

617

print_ppm.c #include <stdio.h> void print_ppm(unsigned char *img, int w, int h, int q) { int c, x, y; printf("P3¥n"); printf("%d %d¥n", w, h); printf("%d¥n", q); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf(" "); for (c = 0; c < 3; c++) { printf(" %3d", img[3 * (w * y + x) +c]); } } printf("¥n"); } }

関数のプロトタイプ宣言 // 作った関数の本体(並括弧の中身)を取り除き // 末尾に ; (セミコロン)を付ける void print_ppm(unsigned char *img, int w, int h, int q);

c

y

x

B B B ... B

B B B ... B

B B B ... B

: : : ⋱ :

B B B ... B

G G G ... G

G G G ... G

G G G ... G

: : : ⋱ :

G G G ... G

R R R ... R

R R R ... R

R R R ... R

: : : ⋱ :

R R R ... R

Page 618: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト形式PPM画像の読み込み

• 読み込んだパラメータに応じて大きさを変更

618

read_pnm_p3_core.c unsigned char *read_pnm_p3(int *w, int *h, int *q) { char s[10]; unsigned char *img; int y, x, c; scanf("%9s%d%d%d", s, w, h, q); if ((img = calloc(*h * *w * 3, 1)) == NULL) { return NULL; } for (y = 0; y < *h; y++) { for (x = 0; x < *w; x++) { for (c = 0; c < 3; c++) { scanf("%d", &img[3 * (*w * y + x) + c]); } } } return img; }

パラメータの読み込み

パラメータに応じて 動的配列の確保

配列に格納する値の 読み込み

確保し値を読み込んだ 動的配列を返す

実用上は、これ+エラー処理が必要 詳細は read_pnm_p3.c 参照

Page 619: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列の添え字調整

配列の添え字の範囲 0~N-1 をずらして使う

619

Page 620: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整

C言語における配列の宣言 型名 変数名[要素数];

例: 要素数N個でint型の配列a int a[N];

利用可能な要素は a[0]~a[N-1]

添え字0~N-1の範囲を自由変更出来ないか?

ポインタを利用すれば可能

620

Page 621: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整

• 1元配列とメモリ上の配置

621

a[-1]

a[ 0]

a[ 1]

a[ 2]

a[ 3]

... 確保されたメモリ

... 確保されたメモリ外

p[-1]

p[ 0]

p[ 1]

p[ 2]

p[ 3]

=

p = &a[0] とした場合

p[-2]

p[-1]

p[ 0]

p[ 1]

p[ 2]

=

p = &a[1] とした場合

int a[3]; int *p; として

p[0] が a のどこに対応するか 調整してやれば添え字の範囲を 自由に調整して使える

a[ 0]~a[ 2] を p[-1]~p[ 1] として使う

p[ 0]

p[ 1]

p[ 2]

p[ 3]

p[ 4]

=

p = &a[-1] とした場合

a[ 0]~a[ 2] を p[ 1]~p[ 3] として使う

Page 622: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整

• オフセットを与えてポインタを格納する

622

array_offset_ex1.c int a[3] = {2,3,5}; int *p; int i; for (i = 0; i < 3; i++) { printf("%p: a[% d] = %d¥n", &a[i], i, a[i]); } p = a + 1; for (i = -1; i <= 1; i++) { printf("%p: p[% d] = %d¥n", &p[i], i, p[i]); } p = a - 1; for (i = 1; i <= 3; i++) { printf("%p: p[% d] = %d¥n", &p[i], i, p[i]); }

mintty + bash + GNU C $ gcc array_offset_ex1.c && ./a 0x23cb00: a[ 0] = 2 0x23cb04: a[ 1] = 3 0x23cb08: a[ 2] = 5 0x23cb00: p[-1] = 2 0x23cb04: p[ 0] = 3 0x23cb08: p[ 1] = 5 0x23cb00: p[ 1] = 2 0x23cb04: p[ 2] = 3 0x23cb08: p[ 3] = 5

a[i] と p[i] の対応を 確認しましょう

Page 623: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整

• オフセットを与えてポインタを格納する

623

array_offset_ex1.c int a[3] = {2,3,5}; int *p; int i; for (i = 0; i < 3; i++) { printf("%p: a[% d] = %d¥n", &a[i], i, a[i]); } p = a + 1; for (i = -1; i <= 1; i++) { printf("%p: p[% d] = %d¥n", &p[i], i, p[i]); } p = a - 1; for (i = 1; i <= 3; i++) { printf("%p: p[% d] = %d¥n", &p[i], i, p[i]); }

mintty + bash + GNU C $ gcc array_offset_ex1.c && ./a 0x23cb00: a[ 0] = 2 0x23cb04: a[ 1] = 3 0x23cb08: a[ 2] = 5 0x23cb00: p[-1] = 2 0x23cb04: p[ 0] = 3 0x23cb08: p[ 1] = 5 0x23cb00: p[ 1] = 2 0x23cb04: p[ 2] = 3 0x23cb08: p[ 3] = 5

a に対してオフセットを 1 加える p は a[1] のアドレスを指す つまり p[0] が a[1] 結果、以下の要素が対応する a[ 0], a[ 1], a[ 2] p[-1], p[ 0], p[ 1]

Page 624: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整

• オフセットを与えてポインタを格納する

624

array_offset_ex1.c int a[3] = {2,3,5}; int *p; int i; for (i = 0; i < 3; i++) { printf("%p: a[% d] = %d¥n", &a[i], i, a[i]); } p = a + 1; for (i = -1; i <= 1; i++) { printf("%p: p[% d] = %d¥n", &p[i], i, p[i]); } p = a - 1; for (i = 1; i <= 3; i++) { printf("%p: p[% d] = %d¥n", &p[i], i, p[i]); }

mintty + bash + GNU C $ gcc array_offset_ex1.c && ./a 0x23cb00: a[ 0] = 2 0x23cb04: a[ 1] = 3 0x23cb08: a[ 2] = 5 0x23cb00: p[-1] = 2 0x23cb04: p[ 0] = 3 0x23cb08: p[ 1] = 5 0x23cb00: p[ 1] = 2 0x23cb04: p[ 2] = 3 0x23cb08: p[ 3] = 5

a に対してオフセットを 1 減らす p は a[-1] のアドレスを指す つまり p[0] が a[-1] 結果、以下の要素が対応する a[ 0], a[ 1], a[ 2] p[ 1], p[ 2], p[ 3]

Page 625: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• 2次元配列とメモリ上の配置

625

a[ 0][ 0]

a[ 0][ 1]

a[ 0][ 2]

a[ 1][ 0]

a[ 1][ 1]

a[ 1][ 2]

a[ 2][ 0]

a[ 2][ 1]

a[ 2][ 2]

... 確保されたメモリ

... 添え字の範囲外だが 確保されたメモリ内

... 確保されたメモリ外

a[ 1][-3]

a[ 1][-2]

a[ 1][-1]

a[ 1][ 0]

a[ 1][ 1]

a[ 1][ 2]

a[ 1][ 3]

a[ 1][ 4]

a[ 1][ 5]

a[ 0][ 0]

a[ 0][ 1]

a[ 0][ 2]

a[ 0][ 3]

a[ 0][ 4]

a[ 0][ 5]

a[ 0][ 6]

a[ 0][ 7]

a[ 8][ 8]

a[ 2][-6]

a[ 2][-5]

a[ 2][-4]

a[ 2][-3]

a[ 2][-2]

a[ 2][-1]

a[ 2][ 0]

a[ 2][ 1]

a[ 2][ 2]

=

多次元配列も 結局は1次元の メモリアドレスに 割り振られる

添え字の範囲外でも メモリ上で連続であれば アクセスは可能

Page 626: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• 2次元配列とポインタのオフセット

626

a[ 0][ 0]

a[ 0][ 1]

a[ 0][ 2]

a[ 1][ 0]

a[ 1][ 1]

a[ 1][ 2]

a[ 2][ 0]

a[ 2][ 1]

a[ 2][ 2]

(*p)[-1][-1]

(*p)[-1][ 0]

(*p)[-1][ 1]

(*p)[ 0][-1]

(*p)[ 0][ 0]

(*p)[ 0][ 1]

(*p)[ 1][-1]

(*p)[ 1][ 0]

(*p)[ 1][ 1]

=

int [3][3] へのポインタ p を作り p が a[ 1][ 1] を指すよう調整すれば a[ 0][ 0]~ a[ 2][ 2] を (*p)[-1][-1]~(*p)[ 1][ 1] として使える!

int a[3][3]; int (*p)[3][3]=(int (*)[3][3])&a[1][1];

Page 627: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• 2次元配列とポインタのオフセット

627

⋱ ⋮ ⋮ ⋮ ⋮ ⋮ ⋰

... a[-1][-1] a[-1][ 0] a[-1][ 1] a[-1][ 2] a[-1][ 3] ...

... a[ 0][-1] a[ 0][ 0] a[ 0][ 1] a[ 0][ 2] a[ 0][ 3] ...

... a[ 1][-1] a[ 1][ 0] a[ 1][ 1] a[ 1][ 2] a[ 1][ 3] ...

... a[ 2][-1] a[ 2][ 0] a[ 2][ 1] a[ 2][ 2] a[ 2][ 3] ...

... a[ 3][-2] a[ 3][ 0] a[ 3][ 1] a[ 3][ 2] a[ 3][ 3] ...

⋰ ⋮ ⋮ ⋮ ⋮ ⋮ ⋱

p = a とした時の (*p)[-1][-1]~(*p)[1][1]の範囲

... 確保されたメモリ

... 添え字の範囲外だが確保されたメモリ内

... 確保されたメモリ外

p = &a[1][1] とした時の (*p)[-1][-1]~(*p)[1][1]の範囲

Page 628: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• オフセットを与えてポインタを格納する

628

array_offset_ex2_1.c int a[3][3] = { { 2, 3, 5}, { 7,11,13}, {17,19,23}, }; int (*p)[3][3] = (int (*)[3][3]) &a[1][1]; int x, y; printf("sizeof(a) = %d¥n", sizeof(a)); printf("sizeof(*p) = %d¥n", sizeof(*p)); for (y = 0; y < 3; y++) { for (x = 0; x < 3; x++) { printf("%p: a[% d][% d] = %d¥n", &a[y][x], y, x, a[y][x]); } } for (y = -1; y <= 1; y++) { for (x = -1; x <= 1; x++) { printf("%p: (*p)[% d][% d] = %d¥n", &(*p)[y][x], y, x, (*p)[y][x]); } }

int [3][3] へのポインタは int (*)[3][3]

a[1][1]は int[3][3]型ではなく int型なのでキャストが必要

Page 629: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• オフセットを与えてポインタを格納する

629

array_offset_ex2_2.c int a[3][3] = { { 2, 3, 5}, { 7,11,13}, {17,19,23}, }; int (*p)[3] = (int (*)[3]) &a[1][1]; int x, y; printf("sizeof(a) = %d¥n", sizeof(a)); printf("sizeof(*p) = %d¥n", sizeof(*p)); for (y = 0; y < 3; y++) { for (x = 0; x < 3; x++) { printf("%p: a[% d][% d] = %d¥n", &a[y][x], y, x, a[y][x]); } } for (y = -1; y <= 1; y++) { for (x = -1; x <= 1; x++) { printf("%p: p[% d][% d] = %d¥n", &p[y][x], y, x, p[y][x]); } }

int [3][3] へのポインタは int (*)[3][3] だが int (*)[3] でも格納可能 使う時は *p としなくて良いので 後者の方が使い易い?

1次元配列でも int [3] への ポインタではなく int 型への ポインタを 使っていた

Page 630: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

630

mintty + bash + GNU C $ gcc array_offset_ex2_2.c && ./a sizeof(a) = 36 sizeof(*p) = 12 0x22aa90: a[ 0][ 0] = 2 0x22aa94: a[ 0][ 1] = 3 0x22aa98: a[ 0][ 2] = 5 0x22aa9c: a[ 1][ 0] = 7 0x22aaa0: a[ 1][ 1] = 11 0x22aaa4: a[ 1][ 2] = 13 0x22aaa8: a[ 2][ 0] = 17 0x22aaac: a[ 2][ 1] = 19 0x22aab0: a[ 2][ 2] = 23 0x22aa90: p[-1][-1] = 2 0x22aa94: p[-1][ 0] = 3 0x22aa98: p[-1][ 1] = 5 0x22aa9c: p[ 0][-1] = 7 0x22aaa0: p[ 0][ 0] = 11 0x22aaa4: p[ 0][ 1] = 13 0x22aaa8: p[ 1][-1] = 17 0x22aaac: p[ 1][ 0] = 19 0x22aab0: p[ 1][ 1] = 23

mintty + bash + GNU C $ gcc array_offset_ex2_1.c && ./a sizeof(a) = 36 sizeof(*p) = 36 0x22aa90: a[ 0][ 0] = 2 0x22aa94: a[ 0][ 1] = 3 0x22aa98: a[ 0][ 2] = 5 0x22aa9c: a[ 1][ 0] = 7 0x22aaa0: a[ 1][ 1] = 11 0x22aaa4: a[ 1][ 2] = 13 0x22aaa8: a[ 2][ 0] = 17 0x22aaac: a[ 2][ 1] = 19 0x22aab0: a[ 2][ 2] = 23 0x22aa90: (*p)[-1][-1] = 2 0x22aa94: (*p)[-1][ 0] = 3 0x22aa98: (*p)[-1][ 1] = 5 0x22aa9c: (*p)[ 0][-1] = 7 0x22aaa0: (*p)[ 0][ 0] = 11 0x22aaa4: (*p)[ 0][ 1] = 13 0x22aaa8: (*p)[ 1][-1] = 17 0x22aaac: (*p)[ 1][ 0] = 19 0x22aab0: (*p)[ 1][ 1] = 23

sizeof(*p)は異なる int (*p)[3][3]; だと sizeof(*p) は sizeof(int[3][3]) int (*p)[3]; だと sizeof(*p) は sizeof(int[3])

Page 631: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• 配列のサイズが必要になるのが欠点

631

array_offset_ex2_2.c int a[3][3] = { { 2, 3, 5}, { 7,11,13}, {17,19,23}, }; int (*p)[3] = (int (*)[3]) &a[1][1]; int x, y; printf("sizeof(a) = %d¥n", sizeof(a)); printf("sizeof(*p) = %d¥n", sizeof(*p)); for (y = 0; y < 3; y++) { for (x = 0; x < 3; x++) { printf("%p: a[% d][% d] = %d¥n", &a[y][x], y, x, a[y][x]); } } for (y = -1; y <= 1; y++) { for (x = -1; x <= 1; x++) { printf("%p: p[% d][% d] = %d¥n", &p[y][x], y, x, p[y][x]); } }

最後の次元以外は要素数が既知でないと 配列へのポインタを作れない

つまり動的配列に対して使えない

Page 632: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタの応用: 配列の添え字調整 2次元配列の場合

• 動的配列の場合は自力でアドレスを計算する

632

array_offset_ex3.c int a[3][3] = { { 2, 3, 5}, { 7,11,13}, {17,19,23}, }; int *p = &a[1][1], w = 3, h = 3; int x, y; for (y = 0; y < 3; y++) { for (x = 0; x < 3; x++) { printf("%p: a[% d][% d] = %d¥n", &a[y][x], y, x, a[y][x]); } } for (y = -1; y <= 1; y++) { for (x = -1; x <= 1; x++) { printf("%p: p[w * % d + % d] = %d¥n", &p[w * y + x], y, x, p[w * y + x]); } }

ポインタを1次元配列として用いる 但しアドレスを計算し易いオフセットを あらかじめ設定しておく

アドレスは自力で計算

Page 633: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認問題

• 以下の状況で9行目の時点の *p と p の値を16進数で答えよ。

633

hoge.c int a = 0x12345678; int *p = &a; printf("&a = %p¥n", &a);

mintty + bash + GNU C $ gcc hoge.c && ./a &a = 0x22aac4

6 7 8 9

Page 634: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

確認問題

• int 型へのポインタ変数 a, b を宣言する場合正しいのは以下のうちどれか?

634

hoge.c int a, b; // (1) int *a, b; // (2) int a, *b; // (3) int *a, *b; // (4)

Page 635: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

635

Page 636: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第14週

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

情報処理言語Ⅰ(実習を含む。)

636

Page 637: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

復習

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

637

Page 638: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

638

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); 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

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

Page 639: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

639

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

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

gl

100

0x00000001004071c0

0x000000000023cb24

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 640: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

640

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

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 0x000000000023cb18

gl

100

0x00000001004071c0

0x000000000023cb20

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 641: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

641

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

呼び出し元アドレス

scopetest.c 22 行目

0x000000000023cb18

lo

300

0x000000000023cb20

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

gl

100

0x00000001004071c0

0x000000000023cb14

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 642: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

642

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

呼び出し元アドレス

scopetest.c 22 行目

0x000000000023cb18

lo

300

0x000000000023cb20

lo

401

0x000000000023cb14

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

gl

101

0x00000001004071c0

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 643: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

643

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

呼び出し元アドレス

scopetest.c 22 行目

0x000000000023cb18

lo

300

0x000000000023cb20

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

gl

101

0x00000001004071c0

0x000000000023cb14

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 644: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

644

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

呼び出し元アドレス

scopetest.c 22 行目

0x000000000023cb18

lo

301

0x000000000023cb20

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

gl

102

0x00000001004071c0

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 645: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

645

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

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 0x000000000023cb18

gl

102

0x00000001004071c0

0x000000000023cb20

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 646: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 変数のスコープ(有効範囲)

646

scopetest.c int gl = 100; void sub(int lo) { { int lo = 400; printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); } int main() { int lo = 200; sub(300); printf("%-4s : %3d: gl=%d, lo=%d¥n", __func__, __LINE__, ++gl, ++lo); return EXIT_SUCCESS; }

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

第8週資料pp.21-23.

呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

201

0x000000000023cb24

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

gl

103

0x00000001004071c0

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 647: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

647

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100

Page 648: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

648

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

0x000000000023cb24

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

Page 649: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

649

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

100

0x000000000023cb24

0x000000000023cb18

0x000000000023cb20

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

訂正2015-07-25 誤: 11行目 正: 12行目

Page 650: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

650

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

100

0x000000000023cb24

呼び出し元アドレス

cal_by_value.c 12 行目

0x000000000023cb18

lo

200

0x000000000023cb20

注: rbpレジスタの退避や メモリ配置時のアライメントの問題等もあるため 実際のメモリーの状況とは若干異なります。

訂正2015-07-25 誤: 11行目 正: 12行目

Page 651: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

651

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

100

0x000000000023cb24

0x000000000023cb18

0x000000000023cb20

注: 実際にはrbpレジスタの退避等もあるため もう少し余分な物もスタックに積まれます

訂正2015-07-25 誤: 11行目 正: 12行目

Page 652: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 値渡し: 呼出し元の値のコピーを渡す

652

call_by_value.c void sub(int lo) { lo = 200; } int main() { int lo = 100; sub(lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

引数で受け取った変数を変更しても 呼び出し元には反映されない

第8週資料pp.21-23. 教科書p.171.

mintty + bash + GNU C $ gcc call_by_value.c && ./a lo=100 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

100

0x000000000023cb24

Page 653: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 参照渡し: 呼出し元の値の格納場所を渡す

653

call_by_pointer.c void sub(int *lo) { *lo = 200; } int main() { int lo = 100; sub(&lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

scanf で見たことがある書き方! &: アドレス演算子

教科書p.171.

引数で受け取った変数を変更すると 呼び出し元にも反映される

これは正確には ポインタ渡しと言う

変数loのアドレスを 渡している

mintty + bash + GNU C $ gcc call_by_pointer.c && ./a lo=200

Page 654: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 参照渡し: 呼出し元の値の格納場所を渡す

654

call_by_pointer.c void sub(int *lo) { *lo = 200; } int main() { int lo = 100; sub(&lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書p.171.

mintty + bash + GNU C $ gcc call_by_pointer.c && ./a lo=200 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

100

0x000000000023cb24

0x000000000023cb14

0x000000000023cb1c

Page 655: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 参照渡し: 呼出し元の値の格納場所を渡す

655

call_by_pointer.c void sub(int *lo) { *lo = 200; } int main() { int lo = 100; sub(&lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書p.171.

mintty + bash + GNU C $ gcc call_by_pointer.c && ./a lo=200 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

呼び出し元アドレス

cal_by_pointer.c 12 行目

0x000000000023cb18

lo

0x000000000023cb24

0x000000000023cb18

ポインターを介して呼び出し元の lo を書き換え

Page 656: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

• 参照渡し: 呼出し元の値の格納場所を渡す

656

call_by_pointer.c void sub(int *lo) { *lo = 200; } int main() { int lo = 100; sub(&lo); printf("lo=%d¥n", lo); return EXIT_SUCCESS; }

4 5 6 7 8 9 10 11 12 13 14 15 16

教科書p.171.

mintty + bash + GNU C $ gcc call_by_pointer.c && ./a lo=200 呼び出し元アドレス

0x0000000180048551

0x000000000023cb28

lo

200

0x000000000023cb24

0x000000000023cb14

0x000000000023cb1c

Page 657: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

文字列操作とポインタ操作

標準ライブラリ関数を例にした実例

657

Page 658: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列操作の例

• strlen 関数の大まかな仕組み

658

strlen_with_idx.c size_t strlen(const char *s) { size_t len = 0; while (s[len] != '¥0') len++; return len; }

文字列の長さは 先頭から終端文字('¥0')の手前までの 文字数

strlen_with_ptr1.c size_t strlen(const char *s) { const char *s0 = s; while (*s != '¥0') s++; return s - s0; }

strlen_with_ptr2.c size_t strlen(const char *s) { const char *s0 = s; while (*(s++) != '¥0') ; return s - s0 - 1; }

Page 659: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列のコピーの例

• strcpy 関数の大まかな仕組み

659

strcpy_with_idx.c 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; }

文字列のコピーは 先頭から終端文字('¥0')までを コピーすれば良い

Page 660: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列のコピーの例

• strncpy 関数の大まかな仕組み

660

strncpy_with_idx.c 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; }

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; }

strncpy は strcpy に加えて 終端文字('¥0')以降を'¥0'で埋める

論理演算は左から右に評価され、 真偽値が確定すると評価を終了する。 つまり i < n や dst < dst0 + n が偽なら、 そこで真偽値が確定するので それより右にある (dst[i] = src[i]) != '¥0' や (*(dst++) = *(src++)) != '¥0' は 実行されない。

Page 661: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列の比較の例

• strcmp 関数の大まかな仕組み

661

strcmp_with_idx.c 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; }

どちらかが終端文字('¥0')になるか 異なる値が出てくるまで比較し 終了位置を比較すれば良い

Page 662: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列の比較の例

• strncmp 関数の大まかな仕組み

662

strncmp_with_idx.c 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; }

strncmp は strcmp の 比較文字数を最大n文字に限定する

Page 663: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列の連結の例

• strcat 関数の大まかな仕組み

663

strcat_with_idx.c 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; }

dst の終端位置に src をコピーする

Page 664: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタを用いた文字列の連結の例

• strncat 関数の大まかな仕組み

664

strncat_with_idx.c 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; }

strncat は strcat の 連結文字を最大n文字に限定する ただしsrcがn文字以上の場合 終端文字が+1文字され 合計n+1バイト追記される

Page 665: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタへのポインタ

• 関数の引数でポインタを返したい場合はポインタ変数へのポインタを用いる

665

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; }

教科書 pp.243-250.

main.c char s[] = "ffz"; char *endp; printf("strtoui(s, &endp, 16);

この例だと endp に "z" へのポインタ つまり&s[2]が返ってくる

Page 666: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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

main 関数の引数

666

Page 667: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドライン引数

• main 関数の引数として取得出来る。

667

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

教科書 pp.265-272., [1] pp.139-144., 第8週資料 p.4.

argument は英語で 引数を意味する

Page 668: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドライン引数

• main 関数の引数として取得出来る。

668

コマンドプロンプト >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 $ ./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"

教科書 pp.265-272., [1] pp.139-144., 第8週資料 p.4.

コマンドライン空白で分割されて argvに格納される。 argvに空白を含めたい場合は 「"」(ダブルクォーテーション)で囲む 「"」を含めたい場合は「¥」でエスケープする argv[0]は実行中のコマンド名

Page 669: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

コマンドライン引数

• char *argv[] は char* 型の配列

669

mintty + bash $ ./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"

教科書 pp.265-272., [1] pp.139-144., 第8週資料 p.4.

'a' '¥0' 'b' '¥0' 'c' ' ' 'd' '¥0' 'e' '"' f '¥0'

argv[1]

argv[2]

argv[3]

argv[4]

正確には 関数の引数で最初の [] は * と同じだったので char *argv[] は char **argv と同じ つまり char 型へのポインタへのポインタ

Page 670: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

文字列とポインタ

670

Page 671: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ポインタ配列の初期化

• char * の配列の初期化

671

char *s[] = {"one", "two", "three"};

教科書.pp.235-239., [1]pp.148-153.

0x~00 o

0x~01 n

0x~02 e

0x~03 ¥0

0x~04 t

0x~05 w

0x~06 o

0x~07 ¥0

0x~08 t

0x~09 h

0x~0a r

0x~0b e

0x~0c e

0x~0d ¥0

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 ~

s[0]

s[1]

s[2]

s[0] は "one" s[1] は "two"

s[0][0] は 'o' s[0][1] は 'n' s[0][2] は 'e' s[0][3] は '¥0'

s は char* 型で要素数3の配列 s[x] は char* 型 *s[x] は char 型

メモリ上のどこかに配置された 文字列

Page 672: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列とポインタの初期値と文字列

• 配列とポインタで扱いが異なることに注意

672

pointer_ex9.c void sub() { char s[] = "hello"; char *p = "world"; ...

教科書.pp.235-239., [1]pp.148-153.

objdump の結果 セクション .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) ...

sへは"hello"の文字コード 68,65,6c,6c,6fが代入されているが pへは.rdataセクションに予め 用意してある文字列"world"の アドレス0x403060が代入されている

.rdataセクションに用意されたデータは 書き変えてはいけない

一般にポインタに初期値として与えた 文字列定数は書き変えてはいけない

Page 673: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

配列とポインタの初期値と文字列

• 配列とポインタで扱いが異なることに注意

673

pointer_ex9.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(); sub(); return EXIT_SUCCESS; }

教科書.pp.235-239., [1]pp.148-153.

Cygwin + GNU C $ 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" s = "hello" p = "World"

sub()が実行された際、 sは毎回"hello"だが pは2回目以降"World"になってしまう もしくは.rdataへの不正な書き込みで 異常終了してしまう

Page 674: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習

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

674

Page 675: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ASCII文字コード表

0 1 2 3 4 5 6 7 8 9 A B C D E F 0 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI 1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC → ← ↑ ↓ 2 SP ! " # $ % & ' ( ) * + , - . / 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 4 @ A B C D E F G H I J K L M N O 5 P Q R S T U V W X Y Z [ ¥ ] ^ _ 6 ` a b c d e f g h i j k l m n o 7 p q r s t u v w x y z { | } ~ DEL 8 9 A B C D E F

上位4ビット

下位4ビット

赤字は制御コード

教科書 p.51., 第2週資料 p.67.

http://ja.wikipedia.org/wiki/ASCII

675

Page 676: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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 が得られる

676

Page 677: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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 が得られる

677

訂正2015-07-17 誤:0x61-0x60+0xa 正:0x61-0x61+0xa

Page 678: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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 が得られる

678

結局10進の場合も、16進の場合も N進の場合で一般化出来る

↓ N進変換のルーチンさえ作れば 全て変換出来る

訂正2015-07-17 誤:0x61-0x60+0xa 正:0x61-0x61+0xa

訂正2015-07-17 誤: {0x30, 0x78, 0x31, 0x32, 0x61, 0x62, 0x00} 正: {0x31, 0x32, 0x61, 0x62, 0x00}

Page 679: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

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"

679

Page 680: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N進整数文字列の数値化

• N進整数の文字列sに対して

680

符号の処理

N進法ヘッダの処理

N進整数数値化処理本体

符号があれば読み飛ばし、+1 または -1 を得る

N進法ヘッダがあれば読み飛ばし、基数を得る

N進整数文字列を数値に変換する

Page 681: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N進整数文字列の数値化

• N進整数の文字列sに対して

681

*s は?

s++

s++ 符号は-1

'-'

'+'

その他 符号は+1

符号の処理

何らかの方法で呼び出し元に 決定した符号を返してやる必要がある

何らかの方法で呼び出し元に sの現在位置を返してやる必要がある

戻り値が2つ必要

Page 682: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N進整数文字列の数値化

• N進整数の文字列sに対して

682

N進法ヘッダの処理

*s は?

s++ '0'

その他 10進

*s は?

s++ 'b'

s++ 'x'

8進 その他

基数の指示が ある?

Y

N

16進

2進

strtobase.c はこの部分 strtoi.c では この部分も必要となる

Page 683: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N進整数文字列の数値化

• N進整数の文字列sに対して

683

s++

N倍した変換済み数値に加算

変換済み数値に符号を付加

Y

N

*s を数値化

*s は N進文字

か?

N進整数数値化処理本体

変換済み数値を返して終了

'0'~'9' から 0x30(='0')を引く 'A'~'Z' から 0x41(='A')を引き 0xa(=10)を足す 'a'~'z' から 0x61(='a')を引き 0xa(=10)を足す

ヒント

例えば "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 が得られる

訂正2015-07-17 1,2,3,4 の加算順が逆だった(次項参照)

Page 684: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N進整数文字列の数値化

• N進整数の文字列sに対して

684

s++

N倍した変換済み数値に加算

変換済み数値に符号を付加

Y

N

*s を数値化

*s は N進文字

か?

N進整数数値化処理本体

変換済み数値を返して終了

'0'~'9' から 0x30(='0')を引く 'A'~'Z' から 0x41(='A')を引き 0xa(=10)を足す 'a'~'z' から 0x61(='a')を引き 0xa(=10)を足す

ヒント

例えば "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 が得られる

訂正2015-07-17 1,2,3,4 の加算順が逆だった(前頁参照)

訂正2015-07-25 誤: result += result * ... 正: result = result * ...

Page 685: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: 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])へのポインタ

685

Page 686: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: strtosign.c

• フローチャートから書き起こす

686

strtosign.c int strtosign(const char *s, char **endp) { int sign; switch (*s) { case '-': s++; sign = -1; break; case '+': s++; default: sign = +1; break; } if (endp != NULL) *endp = (char *) s; return sign; }

*s は?

s++

s++ 符号は-1

'-'

'+'

その他 符号は+1

符号の処理

mintty + bash + GNU C $ gcc strtosign_test.c strtosign.c && ./a s = ? -5 s = "-5"(0x22c710) strtosign(s, &endp) = -1 endp = "5"(0x22c711)

Page 687: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

例題: strtosign.c

• ヒント:

• *endp には s[0] または s[1] へのポインタが入る

• s[0] へのポインタは s, s[1] へのポインタは、s++ した後の s でも良い

687

mintty + bash + GNU C $ gcc strtosign_test.c strtosign.c && ./a s = ? -5 s = "-5"(0x22c710) strtosign(s, &endp) = -1 endp = "5"(0x22c711)

Page 688: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 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])へのポインタ

688

Page 689: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: strtobase.c

• ヒント:

• 前出の「N進法ヘッダの処理」のフローチャートを見てみよう

689

mintty + bash + GNU C $ gcc strtobase_test.c strtobase.c && ./a s = 0x123 s = "0x123"(0x22c710) strtobase(s, &endp) = 16 endp = "123"(0x22c712)

Page 690: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 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を返す

690

mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c && ./a c = ? z 35

Page 691: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: base36toint.c

• ヒント:

• cが'0'~'9'である場合、c-'0'とすると、0~9の数値に変換出来る

• cが'a'~'z'の場合、 c-'a'はいくらだろう?

• もし場合分けが面倒なら A~Z と a~z は tolower 関数または toupper 関数 で大文

字か小文字に変換してしまうと大文字小文字の場合分けが必要なくなる

691

mintty + bash + GNU C $ gcc base36toint_test.c base36toint.c && ./a c = ? z 35

Page 692: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: base36toint.c

• ヒント:

• デバッグ出力は以下のようにすれば良い

692

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

デバッグ出力 #ifdef DEBUG fprintf(stderr, "Warning: in file %s line %d: invalid value: c = '%c'(=%#04x)¥n", __FILE__, __LINE__, c, c); #endif

Page 693: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第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を返す

693

mintty + bash + GNU C $ gcc basetoint_test.c basetoint.c base36toint.c && ./a c = ? z base = ? 10 -1

Page 694: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: basetoint.c

• ヒント

• base36toint.c を用いると簡単に作成出来る

• base36toint の結果が

• -1 なら 36 進法で使えない数字

• N 以上なら N 進法で使えない数字

694

訂正2015-07-17 誤: N 以下 正: N 以上

Page 695: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: 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に返す

• 変換出来た最後の文字の次の文字へのポインタ

695

Page 696: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: strtoi.c

ヒント:

strtosign.c, strtobase.c, basetoint.c を利用すると比較的簡単に作成できる

696 講義資料 第10週 p.62.から移動

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)

Page 697: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

演習: strtoi.c

• ヒント

697

s++

N倍した変換済み数値に加算

変換済み数値に符号を付加

Y

N

*s を数値化

*s は N進文字

か?

N進整数数値化処理本体

変換済み数値を返して終了

base36toint(*s) の結果が -1 なら36進文字以外 N 以上なら N 進文字以外

base36toint(*s) の結果を そのまま使える

basetoint(*s, N) の結果が -1 なら N 進文字以外

符号の処理

N進法ヘッダの処理

N進整数数値化処理本体

全体が strtoi

Page 698: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語の開発支援ツール

698

Page 699: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

分割コンパイル

• ファイルが多くなるとコンパイルが大変

699

mintty + bash + GNU 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ファイルしか変更してないのに 全ファイルコンパイルし直すのは非効率

Page 700: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

make コマンド

• 依存関係を記述し必要な処理だけ行う

• Makefile に依存関係と作成方法を記述する

700

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

作成するファイル: 材料のファイル ... タブ...→作成方法

Page 701: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

make コマンド

• make と打つだけで自動的にコンパイル

701

mintty + bash + GNU 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

Page 702: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

make コマンド

• 依存関係の記述

702

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

Page 703: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

make コマンド

• 依存関係の解決

703

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 cc -c -o strtosign.o strtosign.c cc -o strtoi_test.exe strtoi_test.o strtoi.o strtosign.o strtobase.o basetoint.o base36toint.o

直前に削除したため改めて コンパイルが必要になった ファイルだけ処理し直して てくれている

コンパイルが完了しているので 改めてコンパイルする 必要がなかった

Page 704: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

make コマンド

• 依存関係の解決

• 必要に応じて適宜作成方法を実行する

• 例:

• 材料のファイルが不足している場合

• 作成するファイル(旧)、材料のファイル(新)の場合

704

Page 706: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

その他のビルドツール

• Autotools • autoconf, automake, libtool の総称 • UNIX 系のソフトウェアでは標準的なビルドツール • 以下の標準的な手順でビルド出来るようになる

• 書籍 • GNU AUTOCONF, AUTOMAKE, AND LIBTOOL

https://sourceware.org/autobook/ (無料オンライン版)

• Wikipedia / Autotools

706

mintty + bash + GNU C $ ./configure $ make $ make install

Page 707: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

その他のビルドツール

• CMake - http://www.cmake.org/

• マルチプラットフォームな Makefile 作成ツール

• Wikipedia / CMake

707

Page 708: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ライブラリの自作

• 標準ライブラリ関数はアーカイブやライブラリと呼ばれる複数のオブジェクトファイルを1つにまとめたファイルとして提供されている

• cygwinでは/usr/lib/libc.a等

• Borland C++ではC:¥boland¥bcc32¥Lib¥cw32.lib等

• 標準ライブラリはコンパイル時に自動的にリンクされる

• 但し <math.h> 等は -lm 等として明示的に /usr/lib/libm.aをリンクする必要がある場合もある

708 教科書pp.203-206.

Page 709: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ライブラリの自作

• 複数のオブジェクトファイルを1つのファイルにまとめるにはアーカイバやライブラリアンと呼ばれるツールを用いる

• JM / ar (1) • 作成方法:

ar q ライブラリ名 オブジェクトファイル名 ...

• embarcadero / ライブラリマネージャ TLIB.EXE • 作成方法:

tlib ライブラリ名 -+オブジェクトファイル名 ...

709

Page 710: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ライブラリの自作(Cygwin)

• 複数のオブジェクトファイル(.oファイル)を1つの.aファイルにまとめる

• まとめたファイルをアーカイブ(archive)またはスタティックライブラリ(static library)と呼ぶ

710

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 ファイルの作成

Page 711: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ライブラリの自作(Borland C++)

• 複数のオブジェクトファイル(.objファイル)を1つの.libファイルにまとめる

• まとめたファイルをライブラリと呼ぶ

711

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 Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland strtoi_test.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

必要な .obj ファイルを myfunc.lib から探してリンクし 実行ファイルを作成

複数の .o ファイルをまとめた .lib ファイルの作成

Page 712: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ライブラリの自作

• make によるアーカイブの作成

712

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

Page 713: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ライブラリの自作

• make によるアーカイブの作成

713

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 を作成しています

Page 714: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

714

Page 715: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

C言語入門 第15週

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

情報処理言語Ⅰ(実習を含む。)

715

Page 716: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

乱数

サイコロを振るようにランダムな値を得る

716

Page 717: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

乱数: ランダムな数値を得る

• rand 関数 : 疑似乱数整数の生成

• srand 関数 : 疑似乱数系列の初期化

• time 関数 : 現在時刻の取得 毎回違う値を得るため 乱数系列初期化に用いる

717 教科書 p.318, 322.

Page 718: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

rand 関数

• int rand(void)

• [0:RAND_MAX]の範囲で整数の疑似乱数を返す

• 戻り値:

• 疑似乱数の整数を返す

• 値の範囲は 0 以上 RAND_MAX 以下

• RAND_MAX は stdlib.h で定義されている

• RAND_MAX は少なくとも 32767 以上である

• RAND_MAX + 1 はオーバーフローするかもしれない

718

JM / rand(3)

教科書 p.322.

Page 719: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

srand 関数

• void srand(unsigned int seed)

• 疑似乱数系列の初期化を行う

• 引数:

• seed: 疑似乱数の新しい系列の種 初期値は1

• 同じ種からは毎回同じ疑似乱数系列が生成される。

719

JM / rand(3)

教科書 p.322.

Page 720: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

疑似乱数とは?

• 演算で生成する疑似的な乱数

• POSIX 1003.1-2003 で挙げられている実装例

static unsigned long next = 1; /* RAND_MAX を 32767 と仮定 */ int myrand(void) { next = next * 1103515245 + 12345; return((unsigned)(next/65536) % 32768); } void mysrand(unsigned int seed) { next = seed; }

計算式は決まっているので、 同じseedなら 毎回同じ計算になるため 毎回同じ乱数系列が生成される

720

Page 721: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

乱数系列の確認

• seed の値で乱数系列がどうなるか確認

721

rand_ex1.c int seed, i; printf("seed = "); scanf("%d", &seed); srand(seed); printf("RAND_MAX: %d¥n", RAND_MAX); for (i = 0; i < 10; i++) { printf("%d¥n", rand()); }

乱数系列の初期化

6 7 8 9

10 11 12 13 14 15 16

Cygwin64 mintty + bash $ gcc rand_ex1.c && ./a seed = 1 RAND_MAX: 2147483647 1481765933 1085377743 1270216262 1191391529 812669700 553475508 445349752 1344887256 730417256 1812158119

seed が同じなら 毎回同じ乱数系列が生成される

Page 722: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

乱数の初期化

実行毎に異なる乱数を得る

722

Page 723: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

実行毎に異なる乱数系列に初期化

• seed の値で乱数系列がどうなるか確認

723

rand_ex2.c int i; srand(time(NULL)); printf("RAND_MAX: %d¥n", RAND_MAX); for (i = 0; i < 10; i++) { printf("%d¥n", rand()); }

6 7 8 9

10 11 12 13

Cygwin64 mintty + bash $ gcc rand_ex2.c && ./a RAND_MAX: 2147483647 408068090 654635880 1819541412 1080013827 1356279002 1536746152 352225876 1197042546 1830476305 459739427

毎回 seed が異なるため 毎回違う乱数系列が生成される

time関数は 現在時刻を返す関数

Page 724: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

time 関数

• time_t time(time_t *t)

• 現在時刻を UNIX time で得る

• 引数:

• t: 通常はNULLで良い NULLでない場合*tにも戻り値を格納する

• 戻り値:

• 現在時刻を UNIX time で返す。

724

JM / time(2)

教科書 p.318.

Page 725: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

UNIX time (UNIX時間、UNIX時刻)

• UNIX epoch (UNIX 紀元)

• 1970-01-01 00:00:00 UTC

• UNIX time

• UNIX epoch からの経過秒数

• 2038年問題

• 2038-01-19 03:14:07 UTC = UNIX time: 2,147,483,647秒 = UNIC time: 0x7fffffff秒

• time_tが符号付き32bitの環境でオーバーフロー

725

EppochConverter

Page 726: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

2038年問題

• 2038-01-19 03:14:07 UTC = UNIX time: 2,147,483,647秒 = UNIC time: 0x7fffffff秒

• time_t が符号付き 32bit の環境

• time_t がオーバーフロー

• 以降、正しい日時が処理できなくなる!

• 対策

• time_t の 64bit 化等の対応が必要

726

Page 727: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

未対策の環境はあるのか?

• SOURCEFORGE.JP MAGAZINE / 2014-05-02: 2038年問題に対応した「OpenBSD 5.5」リリース

• http://sourceforge.jp/magazine/14/05/02/160000

• OpenBSD はセキュリティ面で非常に定評のある OS

• そんな OS でもつい最近になってようやく対応している状況もある。

727

Page 728: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

time_t の確認

• 0x7fffffff秒,0x80000000秒,-1秒を確認

time_t_test.c char buf[1024]; time_t t = 0x7fffffff; struct tm *tm; printf("sizeof(time_t): %d¥n", sizeof(time_t)); printf("time_t has sign: %s¥n", (~(time_t) 0) < (time_t) 0 ? "YES" : "NO"); tm = gmtime(&t); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm); printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf); t++; tm = gmtime(&t); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm); printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf); t = -1; tm = gmtime(&t); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm); printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf);

728

Page 729: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

strftime 関数

• size_t strftime(char *s, size_t max, const char *format, const struct tm *tm) • 日付と時刻を文字列に変換する

• 引数: • s: 変換結果の格納先(通常はchar型配列) • max: sのサイズ • format: 変換の書式 • tm: time_t 型の値をlocaltime関数または

gmtime関数を用いて変換した日付と時刻情報

• 戻り値: • 終端文字列'¥0'を含めた変換結果のサイズ • 格納先のサイズが不足していた場合は0

729

JM / strftime(3) JM / ctime(3)

Page 730: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各環境のtime_tの状況

730

Cygwin64 + GNU C $ gcc time_t_test.c && ./a sizeof(time_t): 8 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: 2147483648L: 2038-01-19 03:14:08 UTC 18446744073709551615UL: -1L: 1969-12-31 23:59:59 UTC

Cygwin32 + GNU C

$ gcc time_t_test.c && ./a sizeof(time_t): 4 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 1901-12-13 20:45:52 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

Page 731: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各環境のtime_tの状況

731

Borland C++ 5.5.1 >bcc32 time_t_test.c && time_t_test Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland time_t_test.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland sizeof(time_t): 4 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 2106-02-06 06:28:15 UTC

Page 732: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各環境のtime_tの状況

Visual Studio 2013 Express Desktop Windows 32bit版 >cl time_t_test.c && time_t_test Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. time_t_test.c Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:time_t_test.exe time_t_test.obj sizeof(time_t): 8 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

VC は long が 32bit だったので 64bit 表示出来てない点には注意

732

Page 733: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

各環境のtime_tの状況

Visual Studio 2013 Express Desktop Windows 64bit版 >cl time_t_test.c && time_t_test Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved. time_t_test.c Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:time_t_test.exe time_t_test.obj sizeof(time_t): 8 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

VC は long が 32bit だったので 64bit 表示出来てない点には注意

733

Page 734: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

乱数の範囲調整

任意の範囲の乱数を得る

734

Page 735: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

[0:1) の実数の乱数生成法

• rand(): [0:RAND_MAX]の整数の乱数を生成

• [0:1) を得るには?

• 実数にして RAND_MAX + 1 で割れば良い

• RAND_MAX って幾つ?

• RAND_MAX + 1 だとオーバーフローするかも?

• RAND_MAX + 1.0 なら大丈夫

#define frand() (rand() / (RAND_MAX + 1.0))

[1] p.205.

暗黙の算術変換により 全てdoubleに型変換されて 計算される。

735

Page 736: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

[0:N-1]の整数の乱数生成法

• [0:1) の実数の乱数を生成してNを掛けた後 整数に変換する

int x; x = frand() * N;

なぜ以下の計算方法では駄目か? x = rand() / RAMD_MAX * N; x = rand() / RAMD_MAX * (N – 1); x = frand() * (N – 1); ヒント: • 生成される値の範囲は? • N が出る確率は?

[0:N-1] の整数の乱数 = [0:N) の整数の乱数

736

Page 737: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

N面体のサイコロ

• [1:N] の整数が等確率で欲しい

int x; x = frand() * N + 1;

[1:N] の整数の乱数 = [0:N-1] + 1 の整数の乱数 = [0:N) + 1 の整数の乱数

737

Page 738: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

教科書の例

• 実は間違っている

738

test_p322.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define RANGE_MIN 0 #define RANGE_MAX 10 void main() { int rand10; // 0以上未満 srand( (unsigned)time(NULL) ); rand10=(int)(((double) rand() / (double) RAND_MAX) * RANGE_MAX + RANGE_MIN); printf("求まった乱数は %d¥n", rand10); }

0~9 までは (RAND_MAX / 10) / (RAND_MAX + 1) の確率で出現するので 0以上10以下の乱数を意図したとしても 出現確率のバランスが悪い

rand() は 0 以上 RAND_MAX 以下 の値を返すので、この実装では 1/(RAND_MAX+1) の確率で 10 が出現してしまう

ここのコメントも おかしいが、 0以上10未満でも 0以上10以下でも やってはいけない実装

教科書 p.322.

乱数に関してよく見られる 有名な間違いです。

Page 739: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

もっと質の良い疑似乱数

• random 関数 (POSIX.1-2001.)

• 非線形加法フィードバック

• JM / random(3)

• drand48 関数 (POSIX.1-2001.)

• 線形合同法+48bit整数

• JM / drand48(3)

• メルセンヌツイスタ

• Wikipedia / メルセンヌツイスタ

739

Page 740: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイル操作

ファイルに対する入出力

740

Page 741: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準入出力と標準エラー出力

• 以下の入出力が利用できる • stdin: STanDard INput: 標準入力

• stdout: STanDard OUTput: 標準出力

• stderr: STanDard ERRor output: 標準エラー出力

• scanf や getchar 等は stdin から入力している

• printf や putchar 等は stdout へ出力している

• stdin, stdout はパイプやリダイレクトの対象だが stderr は標準では対象外

[1] pp.196, 199, 218. 741

Page 742: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準入出力と標準エラー出力

• パイプやリダイレクトで処理されたくない内容は stderr へ出力する

• fscanf や fprintf を使うと、入出力先を自由に選択出来る

[1] pp.196, 199, 218. 742

stdiotest.c printf("output to stdout with printf¥n"); fprintf(stdout, "output to stdout with fprintf¥n"); fprintf(stderr, "output to stderr with fprintf¥n");

mintty + bash $ ./stdiotest > redirect.txt output to stderr with fprintf $ cat redirect.txt output to stdout with printf output to stdout with fprintf

Page 743: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

標準入出力と標準エラー出力

• stdin,stdout,stderrはstdio.hで定義されている

• stdio.h は standard input / output header

[1] pp.196, 199, 218. 743

Page 744: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fprintf 関数

• int fprintf(FILE *fp, const char *FORMAT, ...);

• printfの結果をfpへ書き出す

• 引数: • fp: FILE 構造体へのポインタ

• FORMAT: 書式

• ...: 任意の数の引数

• 戻り値: • 書き出された文字数

• エラーの場合負の数

教科書 pp.61, 64-66, 98, 300.

参考: [1] pp.305-306.

744

Page 745: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fscanf 関数

• int fscanf(FILE *fp, const char *FORMAT, ...); • fpからデータを読み込む

• 引数: • fp: FILE 構造体へのポインタ • FORMAT: 書式 • ...: 任意の数の引数

値を格納する変数へのポインタ

• 戻り値: • 変換され代入された入力項目の数 • ファイル終端またはエラーの場合EOF

教科書 pp.80-83, 254.

参考: [1] pp.307-309.

745

Page 746: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fopen 関数

• FILE *fopen(const char *filename, const char *mode); • ファイルを開き、FILE構造体へのポインタを得る

• 引数:

• filename: ファイル名(パス)の文字列

• mode: ファイルを開くモード

• 戻り値:

• FILE 構造体へのポインタ

• エラーの場合 NULL

教科書 pp.298-305.

参考: [1] pp.194-198.

746

Page 747: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fopen 関数の mode

mode 読み込み 書き込み 動作

"r" 任意の位置 × ファイルを開く、存在しない場合エラー

"w" × 任意の位置 ファイルを作成し、前の内容は消去する

"a" × ファイル末尾 ファイルを開く、または作成

"r+" 任意の位置 任意の位置 ファイルを開く、存在しない場合エラー

"w+" 任意の位置 任意の位置 ファイルを作成し、前の内容は消去する

"a+" 任意の位置 ファイル末尾 ファイルを開く、または作成

教科書 pp.298-305.

参考: [1] pp.194-198.

747

"r", "w", "a", "r+", "w+", "a+" はテキストモードで読み書きする テキストモードでは改行コード(¥n)の扱いが環境によって異なる • Windows: CR LF (0xd 0xa) • Mac: CR (0xd) • UNIX: LF (0xa) バイナリモードにするには、"rb", "wb", "ab", "r+b", "w+b", "a+b" のように "b" を追加する

Page 748: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fclose 関数

• int fclose(FILE *fp);

• ファイルを閉じます

• 引数:

• fp: FILE構造体へのポインタ

• 戻り値:

• 0 を返す

• エラーの場合 EOF を返す

教科書 pp.298-305.

参考: [1] pp.194-198.

748

Page 749: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイル入力の例

749

fprintf_ex1.c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; // ファイル入出力用のポインタ int value = 123; fp = fopen("sample.txt", "w"); // 書き込みモードでファイルを開く if (fp == NULL) { // エラー処理 fprintf(stderr, "Error: fopen: sample.txt¥n"); exit(EXIT_FAILURE); } fprintf(fp, "%d¥n", value); // fp に value の値を出力 fclose(fp); // 使い終わったファイルを閉じる return EXIT_SUCCESS; }

Page 750: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ファイル出力の例

750

fscanf_ex1.c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; // ファイル入出力用のポインタ int value; fp = fopen("sample.txt", "r"); // 読み込みモードでファイルを開く if (fp == NULL) { // エラー処理 fprintf(stderr, "Error: fopen: sample.txt¥n"); exit(EXIT_FAILURE); } fscanf(fp, "%d", &value); // fp から符号付き整数の文字列を読み込む printf("%d¥n", value); // 読み込んだ値を表示 fclose(fp); // 使い終わったファイルを閉じる return EXIT_SUCCESS; }

Page 751: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テスト

プログラムの動作を検証する

751

Page 752: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

ユニットテスト(単体テスト)

• 標準ライブラリヘッダ <assert.h>

• assert マクロの利用

• ユニットテストツールの利用

• CUnit http://cunit.sourceforge.net/

752 教科書pp.188-189.

CUnit のインストール (cygwin) apt-cyg install CUnit

Page 753: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

assert マクロ

void assert(int expression) • expression がゼロの場合以下のメッセージを stderr に出力し abort する

Assertion failed: expression, file filename, line nnn

• <assert.h>をインクルードする時点で NDEBUG マクロが定義されていると assert マクロは無視される

• ユニットテストだけでなくデバッグ時のみ有効にする不正値のチェック等でも利用される

753

JM / assert(3)

Page 754: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

assert マクロ

• 専用のテストルーチンで使用した例

754

is_leap_year_assert.c void test_leap_year() { assert(is_leap_year(-400) == 1); assert(is_leap_year(- 56) == 1); assert(is_leap_year(- 4) == 1); assert(is_leap_year( 0) == 1); assert(is_leap_year( 4) == 1); assert(is_leap_year( 56) == 1); assert(is_leap_year( 400) == 1); assert(is_leap_year(1996) == 1); assert(is_leap_year(2000) == 1); assert(is_leap_year(2004) == 1); }

is_leap_year_assert.c void test_normal_year() { assert(is_leap_year(-300) == 0); assert(is_leap_year(-200) == 0); assert(is_leap_year(-100) == 0); assert(is_leap_year(- 3) == 0); assert(is_leap_year(- 2) == 0); assert(is_leap_year(- 1) == 0); assert(is_leap_year( 1) == 0); assert(is_leap_year( 2) == 0); assert(is_leap_year( 3) == 0); assert(is_leap_year( 100) == 0); assert(is_leap_year( 200) == 0); assert(is_leap_year( 300) == 0); assert(is_leap_year(1900) == 0); assert(is_leap_year(1997) == 0); assert(is_leap_year(1998) == 0); assert(is_leap_year(1999) == 0); assert(is_leap_year(2001) == 0); assert(is_leap_year(2002) == 0); assert(is_leap_year(2003) == 0); }

is_leap_year_assert.c int main() { test_leap_year(); test_normal_year(); return EXIT_SUCCESS; }

Page 755: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

assert マクロ

• 専用のテストルーチンで使用した例

• エラーがなければ何も起きない

• エラーがあるとそこで実行が中断する

755

mintty + bash + GNU C

mintty + bash + GNU C

$ gcc is_leap_year_assert.c is_leap_year_func_ex4_2.c && ./a

$ gcc is_leap_year_assert.c is_leap_year_func_practice1.c && ./a assertion "is_leap_year(-300) == 0" failed: file "is_leap_year_assert.c", line 21, function: test_normal_year Aborted (コアダンプ)

Page 756: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

CUnit

• 専用のテストルーチンを作成して使用

756

is_leap_year_cunit.c void test_leap_year() { CU_ASSERT_EQUAL(is_leap_year(-400), 1); CU_ASSERT_EQUAL(is_leap_year(- 56), 1); CU_ASSERT_EQUAL(is_leap_year(- 4), 1); CU_ASSERT_EQUAL(is_leap_year(1996), 1); CU_ASSERT_EQUAL(is_leap_year(2000), 1); CU_ASSERT_EQUAL(is_leap_year(2004), 1); }

is_leap_year_cunit.c void test_normal_year() { CU_ASSERT_EQUAL(is_leap_year(-300), 0); CU_ASSERT_EQUAL(is_leap_year(-200), 0); CU_ASSERT_EQUAL(is_leap_year(-100), 0); CU_ASSERT_EQUAL(is_leap_year(- 3), 0); CU_ASSERT_EQUAL(is_leap_year(2002), 0); CU_ASSERT_EQUAL(is_leap_year(2003), 0); }

is_leap_year_cunit.c static CU_TestInfo test_is_leap_year[] = { {"leap year", test_leap_year}, {"normal year", test_normal_year}, CU_TEST_INFO_NULL, }; static CU_SuiteInfo suites[] = { {"is_leap_year test", NULL, NULL, test_is_leap_year}, CU_SUITE_INFO_NULL, }; int main() { CU_initialize_registry(); CU_register_suites(suites); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); CU_cleanup_registry(); return EXIT_SUCCESS; }

Page 757: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

CUnit

• 専用のテストルーチンを作成して使用

• ユニットテストの達成状況がレポートされる

757

mintty + bash + GNU C $ gcc is_leap_year_cunit.c is_leap_year_func_ex4_2.c -lcunit && ./a CUnit - A unit testing framework for C - Version 2.1-2 http://cunit.sourceforge.net/ Suite: is_leap_year test Test: leap year ...passed Test: normal year ...passed Run Summary: Type Total Ran Passed Failed Inactive suites 1 1 n/a 0 0 tests 2 2 2 0 0 asserts 29 29 29 0 n/a Elapsed time = 0.000 seconds

テストの通過状況の 統計が表示される

Page 758: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

CUnit

758

mintty + bash + GNU C $ gcc is_leap_year_cunit.c is_leap_year_func_practice1.c -lcunit && ./a CUnit - A unit testing framework for C - Version 2.1-2 http://cunit.sourceforge.net/ Suite: is_leap_year test Test: leap year ...passed Test: normal year ...FAILED 1. is_leap_year_cunit.c:21 - CU_ASSERT_EQUAL(is_leap_year(-300),0) 2. is_leap_year_cunit.c:22 - CU_ASSERT_EQUAL(is_leap_year(-200),0) 3. is_leap_year_cunit.c:23 - CU_ASSERT_EQUAL(is_leap_year(-100),0) 4. is_leap_year_cunit.c:30 - CU_ASSERT_EQUAL(is_leap_year( 100),0) 5. is_leap_year_cunit.c:31 - CU_ASSERT_EQUAL(is_leap_year( 200),0) 6. is_leap_year_cunit.c:32 - CU_ASSERT_EQUAL(is_leap_year( 300),0) 7. is_leap_year_cunit.c:33 - CU_ASSERT_EQUAL(is_leap_year(1900),0) Run Summary: Type Total Ran Passed Failed Inactive suites 1 1 n/a 0 0 tests 2 2 1 1 0 asserts 29 29 22 7 n/a Elapsed time = 0.000 seconds

テストの通過状況の 統計が表示される

Page 759: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

変更箇所の管理

比較、差分、パッチ、バージョン管理等

759

Page 760: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

diff のインストール

• mintty+bash から以下のコマンドを実行

760

mintty + bash apt-cyg install diff

Page 761: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

diff

• UNIX系のファイル比較コマンド

761

mintty + bash $ diff is_leap_year_func_practice1.c is_leap_year_func_ex4_2.c 5c5 < return year % 4 == 0; --- > return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;

上記の例では ファイル間の相違点を 一覧として表示している

Page 762: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

diff

• 並列表示

• --side-by-sideオプションによる比較

762

mintty + bash $ diff is_leap_year_func_practice1.c is_leap_year_func_ex4_2.c --side-by-side #include "is_leap_year_func.h" #include "is_leap_year_func.h" int is_leap_year(int year) int is_leap_year(int year) { { return year % 4 == 0; | return (year % 4 == 0 && year % 100 != 0) || year % 400 == } }

Page 763: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

fc

• Windows 標準添付のファイル比較コマンド

763

コマンドプロンプト >fc is_leap_year_func_practice1.c is_leap_year_func_ex4_2.c ファイル is_leap_year_func_practice1.c と IS_LEAP_YEAR_FUNC_EX4_2.C を比較しています ***** is_leap_year_func_practice1.c { return year % 4 == 0; } ***** IS_LEAP_YEAR_FUNC_EX4_2.C { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } *****

Page 764: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

WinMerge

• GUIによるテキストファイルの比較ツール

• 相違点の合成も出来る • http://www.forest.impress.co.jp/library/software/winmerge/

764

UNIX 環境の GUI 版の比較ツールだと meld や tkdiff 等がある

Page 765: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

Rekisa

• GUIによる複数テキストファイルの比較ツール • http://www.forest.impress.co.jp/library/software/rekisa/

765

Page 766: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

差分とパッチ

• diff : 差分比較、パッチ作成ツール

• JM / diff (1)

• Wikipedia / diff

• patch : 差分適用(パッチ適用)ツール

• JM / patch (1)

• Wikipedia / patch

766

単一ファイルのパッチの作成 $ diff -c myfile.orig myfile > myfile.patch

パッチの適用 $ patch < myfile.patch

ディレクトリ以下のパッチの作成 $ diff -crN mydir.orig mydir > mydir.patch

カレントディレクトリへのパッチの適用 $ patch -p0 -d. < mydir.patch

ファイル間の差異を パッチ(=絆創膏)として取り出し 適用することで変更箇所を反映させる

Page 767: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

バージョン管理ツール

• RCS • Wikipedia / Revision Control System

• CVS • Wikipedia / Concurrent Version System

• Subversion • Wikipedia / Apache Subversion

• Mercurial • Wikipedia / Mercurial

• Bazaar • Wikipedia / Bazaar

• git • Wikipedia / git

767

github の登場で 人気になっている

過去の改変の記録を残したり 複数人で共同で作業する際に 役立つ

Page 768: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

テキスト画面の簡易制御

tty_getchar.c

768

Page 769: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

getchar 関数

• int getchar(void) • 入力 stream から1文字読み込む

• stream というのはバッファのようなもの

• 通常はENTERが押されるまで入力streamには値が入って来ない。入力ストリームに値がない場合は値が入ってくるまで待機する

• 戻り値: • 入力された文字の文字コード返す

• ファイル終端やエラーの場合はEOFを返す

769

JM / fgetc(3)

Page 770: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

getchar 関数の動作

• ENTERが押されるまで一気に読み込む

770

getchartest.c #include <stdio.h> #include <stdlib.h> int main() { int c; while ((c = getchar()) != EOF) { printf("%#04x¥n", c); } return EXIT_SUCCESS; }

バッファリングと言います。 読み込み処理を 高速化するための仕組みです。

バッファリングに溜めてある 入力文字を1文字ずつ取り出します。 バッファが空になると ENTERが押されるまで 入力待ちの状態になります。

Page 771: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey

• ENTER待ちなしのキーボード入力

771

tty_getkey_ex1.c #include "tty_getkey.h" #include "msleep.h" int main() { int c; tty_begin(); // 開始処理 while(tty_iskeyhit() == 0) { // 打鍵待ちループ msleep(1); // CPU に負荷をかけずに 1 msec 待つ // tty_ishitkey() は即座に値を返すので空ループだと CPU に負荷がかかる } c = tty_getkey(); // 打鍵キーの取得 tty_printf("%#x key was hit.¥n", c); // tty 用の printf tty_printf("Hit ESC key to exit.¥n"); while(KEY_ESC != tty_getkey()) { // 打鍵待ちループ ; // tty_ketkey() はキー入力があるまで待機するため空ループでも CPU に負荷をかけない } tty_end(); // 終了処理 return EXIT_SUCCESS; }

Page 772: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey

• ENTER待ちなしのキーボード入力

• Windows 系の環境

• conio.h ライブラリを利用

• embarcadero / RAD Studio / conio.h

• MSDN / Console and Port I/O

• UNIX 系の環境

• curses ライブラリを利用

• http://ja.wikipedia.org/wiki/Curses

772

Page 773: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey を利用したプログラムの コンパイル

• サンプルプログラム

• tty_getkey_ex1.c : サンプルプログラム本体

• 必要なファイル

• msleep.h : ミリ秒 sleep 用ヘッダ

• tty_getkey.h : tty_getkey ヘッダファイル

• tty_getkey.c : tty_getkey 本体

773

mintty + bash + GNU C $ gcc tty_getkey_ex1.c tty_getkey.c -lcurses

コマンドプロンプト + Borland C++ >bcc32 tty_getkey_ex1.c tty_getkey.c

gcc では -lcurses オプションが必要 これには ncurses ライブラリが必要

Page 774: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey 利用前の準備 Cygwin の場合

• ncurses の開発用ライブラリが必要

• 以下のコマンドを入力してインストール

• Borland C++ では、標準添付の conio というライブラリを使っているので前準備は不要

774

Cygwin64 mintty + bash apt-cyg install libncursesw-devel

Cygwin32 mintty + bash apt-cyg install libncurses-devel

Page 775: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

Cygwinが何bit版か確認する方法

• uname コマンドに -a オプションを付けて実行

775

Cygwin64 mintty + bash $ uname -a CYGWIN_NT-6.1 EX58EXTREME 1.7.27(0.271/5/3) 2013-12-09 11:54 x86_64 Cygwin

Cygwin32 mintty + bash $ uname -a CYGWIN_NT-6.1-WOW64 EX58EXTREME 1.7.27(0.271/5/3) 2013-12-09 11:57 i686 Cygwin

i686 なら 32bit 版

x86_64 なら 64bit 版

Page 776: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey 初期化関数

• int tty_begin(void)

• tty_getkey の初期化処理を行います

• int tty_end(void)

• tty_getkey の終了処理を行います

776

Page 777: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey キー待ち受け関数

• int tty_iskeyhit(void)

• キー入力の有無を調べます。

• キー入力があれば 1 なければ 0 を返します。

• int tty_getkey(void)

• キー入力を取得します。キー入力がない場合、キー入力が発生するまで待機します。

• 通常のキーは'a'や'A'等の文字コードを返します。

• 特殊キーの場合はKEY_UPやKEY_DOWN等のマクロで定義されたキーコードを返します。

777

Page 778: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey() が返すキーコード

• KEY_INSERT

• KEY_DELETE

• KEY_HOME

• KEY_END

• KEY_PAGEUP

• KEY_PAGEDOWN

• KEY_UP

• KEY_DOWN

• KEY_LEFT

• KEY_RIGHT

• KEY_ESC

• KEY_TAB

• KEY_SPACE

• KEY_BS

• KEY_ENTER

• KEY_F1 ~ KEY_F48

通常のキーは 'a', 'A' 等の文字定数リテラルが対応

778

Page 779: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey 出力関数

• int tty_printf(char *fmt, ....)

• 書式付の出力を行います。

• 画面制御を伴うためtty_begin()~tty_end()の間では、通常のprintfは使わないでください。

• int tty_setxy(int x, int y)

• カーソルの座標を(x,y)に移動します。

779

Page 780: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey 画面情報関数

• int tty_getx(void)

• カーソルの x 座標を返します。

• int tty_gety(void)

• カーソルの y 座標を返します。

• int tty_getw(void)

• カーソルが移動可能な画面の幅を返します。

• int tty_geth(void)

• カーソルが移動可能な画面の高さを返します。

780

Page 781: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey_ex2.c

• カーソルキーで移動、ESC キーで終了

• 移動した場所に * を表示する

781

Page 782: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey_ex2.c

782

tty_getkey_ex2.c while (KEY_ESC != (c = tty_getkey())) { switch (c) { case KEY_UP: y--; break; case KEY_DOWN: y++; break; case KEY_RIGHT: x++; break; case KEY_LEFT: x--; break; } x = x < 1 ? 1 : w - 2 < x ? w - 2 : x; y = y < 1 ? 1 : h - 2 < y ? h - 2 : y; tty_setxy(0, 0); tty_printf("(%2d,%2d) : %#06x", x, y, c); tty_setxy(x, y); tty_printf("*"); }

入力された カーソルキーの方向に応じて 座標を上下左右に移動

画面から はみ出さないように 移動範囲を制限

Page 783: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tty_getkey_ex3.c

• 6面体サイコロの例

• 開始するとサイコロが転がり始める

• 何かキーを押すと3秒待って終了する

783

tty_getkey_ex3.c while(tty_iskeyhit() == 0) { d = frand() * 6 + 1; tty_setxy(0, 0); tty_printf("%d", d); msleep(1); } msleep(3000);

値域 [1:6] の乱数生成 = 6面体サイコロ

Page 784: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

総合実習

プログラムで遊んでみる

784

Page 785: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c

• テトリスの簡易版

• 操作方法

• 移動: ← →

• 落下: ↓

• 回転: z x SPACE

• 修了: ESC

785

mintty + bash + GNU C $ gcc tetris.c tty_getkey.c -lcurses && ./a

コマンドプロンプト + Borland C++ >bcc32 tetris.c tty_getkey.c && tetris

mintty + bash + GNU C ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

Page 786: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c

• フィールド

786

描画用フィールド field[0][y][x]

固定ブロック用フィールド field[1][y][x]

浮動ブロック b[y][x]

ブロック形状 block[spec][y][x]

仮り配置

選択して回転

落下したら固定

描画用フィールドにコピー

Page 787: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造

• 以下の改造を考えてみよう

• 「p」でポーズ/解除する

• 点数を表示する

• 次のブロックをランダムに決める

• 次のブロックを表示する

• 上まで積み上がったら ゲームオーバーにする

• ハイスコアを記録・表示してみる

787

mintty + bash + GNU C ## ## HISCORE: 001000 ## ## Score : 001000 ## ## ## ## NEXT ## ## ++--------++ ## ## ## || || ## ## ## || ## || ## #### ## || #### || ## ## || ## || ## ## ++--------++ ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

Page 788: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造 ヒント

• 「p」でポーズ/解除する

• ポーズフラグ用の変数が必要

• 「p」キーでポーズフラグを反転する

• ポーズフラグがONなら continue してループを先頭からやり直す

788

フラグの反転 // 以下の処理はいずれも // pause == 0 なら 1 // pause != 0 なら 0 // となる pause = pause ? 0 : 1; pause = !pause; pause = pause == 0;

Page 789: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造 ヒント

• 点数を表示する

• 点数用の変数が必要

• ブロックの落下や 1列消した場合に スコアを加算する

• 適当な位置にスコアを表示する

• 位置調整は tty_setxy()

• 表示は tty_printf()

789

mintty + bash + GNU C ## ## HISCORE: 001000 ## ## Score : 001000 ## ## ## ## NEXT ## ## ++--------++ ## ## ## || || ## ## ## || ## || ## #### ## || #### || ## ## || ## || ## ## ++--------++ ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

例えばこの位置に表示するなら tty_printf() の前に tty_setxy(W*2+2,1); を入れる

Page 790: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造 ヒント

• 次のブロックをランダムに決める

• spec の値を乱数で決定すれば良い

• 前述の frand() マクロを使うと [0:7) の乱数は frand()*7 で得られる

790

Page 791: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造 ヒント

• 次のブロックを表示する • 次のブロックを記憶するための変数が必要(※1) • ※1を使って spec を更新する • spec を更新後 ※1 も更新する • ※1 を適当な位置に表示する

• 表示位置は tty_setxy() で 調整する

• 枠は "++--------++" と "||" 以外でも 好きな文字を使えば良い

• block[※1][y][x] の値に応じて " " または "##" を表示する

791

mintty + bash + GNU C ## ## HISCORE: 001000 ## ## Score : 001000 ## ## ## ## NEXT ## ## ++--------++ ## ## ## || || ## ## ## || ## || ## #### ## || #### || ## ## || ## || ## ## ++--------++ ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

Page 792: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造 ヒント

• 上まで積み上がったらゲームオーバーにする

• y <= 0 でブロックが固定されたら、上まで積み上がっている

• ゲームオーバーになるとどうするか?

• GAME OVER と表示する?

• その後、再度ゲームをスタートするか?プログラムを終了するか?

• 一般に流通しているゲームはどうしているか参考にすると良い?

792

Page 793: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

tetris.c の改造

• ハイスコアを記録・表示してみる

• ハイスコア用の変数が必要

• ハイスコアは画面の適当な場所に表示する

• スコアがハイスコアを超えたらハイスコアを更新する必要がある

• ハイスコアはファイルに保存し、ゲーム開始時に読み込み終了時に保存する必要がある

• fopen, fclose でファイルのオープン、クローズが行える

• fprintf, fscanf で値の読み書きが行える

793

Page 794: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

まとめ

やったこと、やらなかったこと

794

Page 795: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

この授業で扱った事

• C言語の基礎

• 演算、式、変数、制御構造、関数、ポインタ等

• 簡単なプログラムの作成

• 奇数偶数の判定

• 閏年の判定

• 行列の演算

• シーザー暗号

• 等々

Page 796: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

この授業で扱わなかったこと

• 構造体と共用体: struct, union

• 型定義: typedef

• 可変長引数: <stdarg.h>

• va_list, va_start, va_arg, va_end

• 非局所ジャンプ: <setjmp.h>

• シグナル処理: <signal.h>

Page 797: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

参考文献

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

797

Page 798: プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機 ...web.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第1週 プログラミング言語Ⅰ(実習を含む。),

おしまい

おつかれさまでした。

来週は試験です。しっかり復習しておきましょう。