情報科学リテラシー · 2020-07-03 · •...
TRANSCRIPT
情報科学リテラシー
2020年7月14日海谷治彦
1
目次
• 前回の解答例解説
• マクロとヘッダー
• 変数の種類
• 文字型の配列,文字列
2
前回の解答例
teamsより
il09ans.zip
3
ついていけてないと思う学生へ
• 以下を復習として必ず実施してください.
1. 授業の資料(PDF)を熟読する.
2. 資料中のサンプルと解答例をコンパイルし実行する.• サンプルは資料を見て打ち込まなくてもダウンロード可能となっています.
3. サンプルをちょっと改造して実行する.• 表示の仕方を変える
• 表示する値を変える
• 条件(範囲)を変える
• 繰り返し回数を変える
等
4
復習
マクロ #define について
• define は,定数的なものを定義する文法である.
• 厳密には定数を定義しているのではなく,コンパイルの前に,プログラムの字面を見て,文字の置き換えを行っているに過ぎない.
• この前処理を行うアプリをプリプロセッサと呼ぶ.
• たとえば,
#define MAXLINE 100• は,以降,ソースプログラム中に現れる MAXLINE という文字を単純に置き換えている.
• ただし,"...." で囲まれる文字列定数内は除く.
• 配列の長さとループの回る回数をそろえる等の場合,便利.
• マクロは慣習として大文字と_のみで書く.
5
p.118-(明)
簡単な例
6
// define1¥main.c#include <stdio.h>
#define MAXARRAY 5
int main(void){int a[MAXARRAY]={3, 1, 4, 1, 5}, i=0;while(i<MAXARRAY){printf("%d, ", a[i]);i++;
}printf("¥n");return 0;
}
stdio.h 内で定義済のマクロ
• BUFSIZ • 標準的なバッファーのサイズ数.
• バッファーについては後述
• 任意文字列を保管する文字配列のサイズとして使うのもよいだろう.
• 手元の環境では 512 だったが,環境により異なる.
• NULL • 空ポインタ
• 詳細はプログラムAで話されるが,何も指していないことを示す定数.
• EOF• ファイル(プログラムAの範囲)の終わりをプログラムで識別するための定数.scanfの失敗判定にも使う.
7
ヘッダー stdio.h 等
• C言語ではいくつかの定数定義や関数定義がファイルに予めまとめられている.
• これらをヘッダーと呼ぶ.
• C言語側で提供されているヘッダーを,自分のプログラムに埋め込む命令が,
#include <stdio.h>等である.
• stdio.hのファイルがどこにあるかは,gcc等のコンパイラにより異なる.通常は,/usr/include/
• stdio.h 以外にもいくつかのヘッダーがある.(後述)
8
変数の種類
実はintは整数じゃない
9
変数の型について
• 値の種類によって保管箱の大きさが異なる.• 単なる整数,例えば 124 よりも,実数,例えば 3.14159254 を保管する箱のほうが大きめじゃないと困るでしょ.
• よって,型というもので変数の種類(保管場所の大きさと用途)を区別する.
• C言語には多様な型があるが,当面,以下くらいを知っていればよい.
• int整数を保管する変数の型,英単語integerに由来.
• float実数を保管する箱の型
(通常 int と同じサイズなので精度が悪い,浮動小数点と呼ばれる)• double倍精度実数を保管する型
• char文字1個を保管する型,英単語characterに由来.
10
p.28-31(明)
参考箱の大きさ
• 型によって一個の変数の大きさは異なる.
• char を1箱とすると,• int 4箱分• float 4箱分• double 8箱分
が一般的.しかし,C言語にはこの辺の明確な規定が無い.
• ハードウェアの効率にあわせてよいため.
11
‘x’ 15
文字 整数
sizeof演算子
• あるデータ型が,charのデータ型の何倍の大きさを使うかを示す演算子.
• その他,変数等のサイズがchar1個の何倍かも知ることができる.
• 前者の使い方は,主にgcc等の素性を知るための確認以外には,あまり使わない.
12
本授業でのgccの場合 (charbit)• 前々のページと同じサイズ感
• charは8bitで,intはその4倍の32bit 等
13
参考 CHAR_BIT マクロについて
• 使っているgcc等のコンパイラにおいて,charのビット数がいくつかを示している定数.
• 普通は8だが,8である保障は無い.
• limits.h 内に定義されているため,確認のためには,これを include する必要がある.
• まぁ,普通の状況ではあまり使わない.gcc等のコンパイラの素性を確認する時くらい.
14
この授業のintは32bit• この授業で用いるgccでは,intは32bitである.
• よって,232個(およそ42億)の数値しか表せない.• 例えば 1010 の整数(100億)は扱えない.
• 大体,-21億から21億まで (約2×10 9)• 地球の人口数より小さい,わりと狭い範囲.
• 巨大な整数を扱いたいなら,long long int 等,別の型を利用する必要がある.
• long long int は単に long long と書いても良い.
• この授業のlong long は,±263 程度すなわち1019 弱の数.
• この授業のgccでは,int と long は同じサイズ涙
15
復習かも BIT BYTE 他
高校の復習かも.
• 二進法の1桁の情報をbitと呼ぶ.0/1の値しかとれない
が,yes/no ok/ng 等の単純な情報を表せる.
• コレを8個束ねたものを,通常,バイト(Byte, B)と呼ぶ.
• 多くの場合,英数文字の1文字は1バイトで表現できる.
• 多くの場合 = ASCII 互換,すなわち UTF-8, SJIS等
• コンピュータ中のデータは1バイトをひとまとめで扱うこ
とが多い.
• メモリの一区画は1バイト入る.
• CPUやOSの32bit, 64bitは,一回で転送できるデータ数を示
す.16
例 longlong¥main.c
17
/*int と long long の値を10倍するのを22回くらい繰り返す.途中から計算がおかしくなるのがわかる.*/#include <stdio.h>
int main(void){int i=1, c=0;long long g=1;for(c=0; c<22; c++){
printf("%2d int %12d, ", c, i);printf(" long long %22lld¥n", g);i *= 10;g *= 10;
}return 0;
}2d 12d 等のフォーマットはあ
まり気にしないでください.ただ,long long を扱う場合は,必ず %lld を使ってください.
実数の内部表現 1/2• 実数は内部的には,
± 0.12345 × 10678
的な表現で数値を表現し,±, 12345, 678 の3つの情報(符号,仮数,指数)のみを記録している.
• 実際の32bit float は,以下のようになっている.
• Eの値は 0~255
18
実数の内部表現 2/2• 細かいことはおいといて,実際の数値を記録する仮数部分が float では,たった 23bitしか無いことが重要である.
• これによって,ちょっとした掛け算や割り算によって,すぐに誤差が出る.
• 64bitのdoubleでは,仮数部分に52bitを用いており,誤差が出にくい.
19
floatは精度が悪い
• floatは多くの環境で精度が悪い.
• 本授業の場合,32bitでfloatを表しているので,簡単な計算でも,すぐに誤差がでる.
• 実数の計算では,double を使うように.
20
#include <stdio.h>
int main(void){float h, w;
printf("input your weight: ");scanf("%f", &w);printf("input your height:");scanf("%f", &h);
printf("your weight %f and height %f¥n", w, h);return 0;
} // scanfloat¥main.c
実数値入力の簡単な例
21
Float は精度が悪い例
floatでなくdoubleなら平気
22
// scandouble¥main.c#include <stdio.h>
int main(void){double h, w;
printf("input your weight: ");scanf("%lf", &w);printf("input your height:");scanf("%lf", &h);
printf("your weight %lf and height %lf¥n", w, h);return 0;
}
doubleはscanf, printfともに %f でなく %lf を使うように.
実数にかかわる便利な関数
math.h というヘッダーを読み込む必要がある.
• double sqrt(double) 平方根
• double pow(double x,double y) べき乗,xのy乗• double sin(double), cos, tan 三角関数,ちなみに引数は180度等ではなく,π等で与える.M_PI というマクロが定義されている.
23
例 math¥main.c
24
/*簡単な数値計算関数の例コンパイル時点で,gcc main.c -lm としなければいけない場合も多いが,授業のgcc では -lm が無くても平気っぽい.*/#include <stdio.h>#include <math.h>
int main(void){double a, b, c;a=5.0;printf("root(5)=%lf¥n", sqrt(a));b=pow(a, 3.0);printf("5^3=%lf¥n", b);printf("sin(pi)=%lf cos(pi)=%lf cos(pi/3)=%lf¥n", sin(M_PI), cos(M_PI), cos(M_PI/3));return 0;
}
注意: 異なる型の変数を合わせ
• int, float, double 等,それぞれ異なる型の変数が宣言できる.
• 式の中の計算では大きなサイズで計算される.• 例 int と double の掛け算は double で計算される.
• 例 int と int の割り算をすると int で切り捨て.
• 代入の場合,代入先の変数型になる.• 例 float を int に代入すると,切り捨てて整数になる.
• 後述のキャスト(Cast 強制型変換)を行なう必要がある.
25
強制型変換 Cast• 主に代入等で,異なる型の変数に代入を行なう場合,強制的に型を変換する命令である.
• 次のページの例のように(型名)変数や式という形式で型名の変数に変換する.
• 変換できない場合もある.
26
Castの例
27
// cast¥main.c#include <stdio.h>
int main(void) {int a = 3, b = 10, x;float div, p = 7.0, q = 10.0;// a/bはintなので切り捨てでゼロにdiv = a / b;printf("%f¥n", div);
// aをfloatに変換するので切り捨てられないdiv = (float)a / b;printf("%f¥n", div);
// 整数割でゼロになってから,floatに強制変換してもゼロのままdiv = (float)(a / b);printf("%f¥n", div);
// floatをintに代入すると切り捨てられてしまう.div = p / q;x = div;printf("%f %x¥n", div, x);return 0;
}
文字の配列
文字列
28
配列の基本
• 配列は変数の一種である.• 宣言する必要あり.
• 値を読む(使う)ことができる.
• 値を書く(更新する)ことができる.
• 通常の変数と異なり,同種の値を複数個扱うことができる.
• 1個でもいいが,あんまり意味がない.
• 同じ変数名で扱う値群を区別するために,添字という0から始まる番号を用いる.
• 値を読む場合,書く場合に,変数名に加えて,この添字を指定する必要がある.
29
復習
文字型の配列文字列
• 単語や文は文字型charの配列で扱うことができる.
• intやfloatの配列と違い,単語や文の終端を表す文字を設定する.(意図的にしないことも可能)
'¥0' • データとしては,全てのビットがゼロのデータ.
• '¥0' の値自体が,while, if 等の条件判断における偽(false)の値となっている.
• そもそもCでの条件判断は,判断対象の式が,ゼロかそれ以外かを判定しているに過ぎない.
• ゼロの場合「成り立たない」,それ以外は「成り立つ」と判断.
• 「文字型の配列」のことを単に「文字列」と呼ぶことも多い.
30
p.239-(明)
¥ と〵は一緒なので '〵0'
chararray1
31
// chararray1¥main.c#include <stdio.h>
int main(void){int i=0;char a[7];a[0]='H';a[1]='e';a[2]='l';a[3]='l';a[4]='o';a[5]='¥n';a[6]='¥0';
while(a[i]!='¥0') {printf("%c", a[i]); i++;}// printf("%s", a); // 上記と同じ意味return 0;
}
配列の初期値設定
• 配列の初期値設定を代入文でちまちまやると,結構めんどうくさい.
• 前ページの例のとおり.
• 宣言時点で初期値を設定することができる.
• 特に文字型の配列(文字列)の場合,"aaa" 等の二重引用符"を用いた表現を使えるのでとても楽.
• これは文字型 char だけの特例で,int や float では,このようには書けない.
• 尚,文字1個は"ではなく一重引用符'で囲う.• 例 'A'
32
printf, scanf での文字列の様式
• printfで文字配列を表示するときは,%d ではなく,%s を使ってください.
• 同様に,scanf でも %s を使ってください.
33
左と下は同じ意味
34
// chararray2¥main.c#include <stdio.h>
int main(void){int i=0;char a[7]={'H', 'e', 'l', 'l', 'o', '¥n', '¥0'};
while(a[i]) {// a[i]!='¥0' と同じprintf("%c", a[i]); i++;
}return 0;
}// chararray3¥main.c#include <stdio.h>
int main(void){char a[]="Hello¥n"; // こう書くほうが一般的
printf("%s", a);return 0;
}
普通の文字
• コンピュータで標準的に扱われる文字は,ASCII と呼ばれる英数文字と記号である.
• AからZ aからz 0から9 %, # 等の一部記号
• 標準的: ここでは,変数名,関数名等に用いることができるものとしている.
• 日本語や韓国語の文字,ドイツ語等の拡張部分( ä 等,通常アルファベットに装飾があるもの, いわゆる latin1)は標準的ではない.
• 本授業では,プログラム内では,ASCIIコードの範囲の文字のみ使ってください.
• コメント内は除く35
p.7-(明)
ASCIIの表
36
例えば,100 0001 という7bitの値を文字 A と規定している.101 1100 の\が,日本のPCにおける ¥ になっている.
復習
文字の連続性
• 前述の表をみると,文字のAの次はBとデータとして連続性があるように見える.
• char c='A'; c++; で cの中身は 'B' かも等.
• よって,C言語では,A-Z, a-z, 0-9 等の直感的な文字の連続性が保証されていると思う人もいる.
• 残念ながら,C言語では,このような文字の連続性は保証されていない.
• 実際に反例がある文字コード体系が存在する/した.
• しかし,今日,多くのコンピュータはASCIIおよびその拡張文字コード(UTF-8等)に基づいているので,実質,問題無いという人もいる.
• ASCIIに基づいていないコンピュータも存在する(した).37
連続性の例今時は正しく動くことが多い
38
/* charlist¥main.c ASCII に基づくOSで動かした場合のみに正常に動く */
#include <stdio.h>
int main(void){char c=' ';while(1){printf("[%c] ", c);if(c=='~'){break;}c++;
}printf("¥n");return 0;
}
注意: 配列の代入と参照
• 配列同士の丸ごと全部の代入はできない.
• 配列の要素を丸ごと参照することはできない.
• ただし,文字配列だけは例外的にprintf文で丸ごと参照できる.(代入とかは文字列でもダメ)
39
int a[5]={3, 1, 4, 1, 5};int b[5];
b = a; // ダメ
int a[5]={3, 1, 4, 1, 5};printf("%d", a); // ダメ というか意味が違う
char a[7]={'j', 'i', 'n', 'd', 'a', 'i', '¥0'};printf("%s", a); // これはOK
復習
キーボードからの入力の終わり
• scanf そして教科書[レ]にある gets 等は,キーボードからの入力をプログラム内に取り込む関数群である.
• C言語では,キーボードからの入力を,開始と終了があるテキストファイルとみなしている.
• よって,終了をどう入力するかが重要となる.
• 残念ながらOSによって,これが異なる!
• 標準的なWindows系• コントロールを押しながら Z
• UNIX/Linux系• コントロールを押しながら D
• この辺は歴史的経緯があるので,統一は難しいだろう.
40
文字(列)のキーボードからの入力
• 以下の二つの方法を推奨する
• scanf• ただし,空白文字を読み込むのが面倒.
• 空白は文字列の区切りとデフォルトでは判断されるため.
• そうしないための書式指定はちょっと面倒.
• 配列名のみ渡し,&はつけない.
• fgets 参考までに• 最も一般的な文字列を読み込む関数.
• 空白文字に加えて改行文字もデータとして取り込める.
• 構文が若干複雑.(汎用的にできている)• 旧教科書[レ]にある gets の利用は今は禁止されている.
• それぞれ,一長一短なので,試して欲しいが,基本,この授業では,前者のみ使えばよい.
41
scanf 定番
42
/* strscanf1¥main.cscanfで文字列を1つ読み込む定番処理細かなエラー処理は省いてある.本授業の範囲ではコレで十分.空白を使うと直前までしか読まれない*/#include <stdio.h>
int main(void){char str[BUFSIZ]; // 標準バッファーサイズscanf("%s", str); // 文字配列の場合,&はつけないprintf("[%s]¥n", str); // とりあえず読んだのを表示// 以降,必要な処理を str に対して行なうreturn 0;
}
scanfの繰り返し
43
// strscanf2¥main.c// 配列数を6としたが,読み込み文字上限は5とすべき// 長い文字があると途中で切られて,次の入力に入るのがわかる.// 空白が区切りなのもわかる// 条件判断時点で str の内容が更新されるのでお勧めしない#include <stdio.h>
int main(void){char str[6]; // ¥0分余計にサイズを確保
while(scanf("%5s",str)!=EOF){printf("[%s]¥n", str);
}
return 0;}
scanfの繰り返しお勧め版
44
// strscanf3¥main.c// 配列数を6としたが,読み込み文字上限は5とすべき// 長い文字があると途中で切られて,次の入力に入るのがわかる.// 空白が区切りなのもわかる// 玄人はこうかかないが,学習目的では妥当.#include <stdio.h>
int main(void){char str[6]; // ¥0分余計にサイズを確保while(1){
int result;result=scanf("%5s",str);if(result==EOF) {break;}printf("[%s]¥n", str);
}
return 0;}
fgetsの例
45
/* strfgets1¥main.c空白も改行もプログラムに
読み込まれているのが分かる */#include <stdio.h>
#define MAX 5
int main(void){char str[MAX+1]; // 終端文字 ¥0 が最後に必要なので,MAX+1 文字の宣言が必要// 以下は,上限MAX個の文字配列strにキーボードから入力する// という意味// stdin はキーボードに相当 (正確には標準入力)while(fgets(str, MAX+1, stdin)!=NULL){
printf("[%s]¥n", str);}return 0;
}
参考
条件判断と値更新の同時記述• C言語では,if や while 等の条件判断と同時に値更新をするプログラムを記述できる.
• しかも,かなり幅広く用いられている.• コンパクトに記述できるため.
• 本授業では,なるだけ,このような同時記述を避けるようにしている.(初学者向け講義のため)
46
while(fgets(str, MAX+1, stdin)!=NULL){printf("[%s]¥n", str);
} // strfgets1¥main.c より
// strfgets2¥main.cwhile(1){char* result;result=fgets(str, MAX+1, stdin);if(result==NULL){break;}printf("[%s]¥n", str);
}
strの更新と,fgetsの返値のチェックが,同時に行なわれている.
意図的に,更新とチェックを分けた.あまりCでは一般的ではないが,理解はしやすい.
参考
演習1• 以下の仕様に基づくプログラムを作成せよ.
• teamsに提出
• プロジェクト名 charcount
47
利用者は空白文字,タブ,改行文字を含まない英数文字の文字列を入力する.プログラムは入力された文字列中で,a および A (小文字と大文字のA)の出現回数を数える.プログラムは数えた回数を画面に表示する.
例えば,KanagawA と入力された場合,プログラムは,4と表示する.
演習2• 以下の仕様に基づくプログラムを作成せよ.
• teamsに提出
• プロジェクト名 strreverse
48
利用者は空白文字,タブ,改行文字を含まない英数文字の文字列を入力する.プログラムは,入力された文字列を逆順に表示する.
例えば,Kanagawa と入力された場合,awaganaKと表示する.
演習3• 以下の仕様に基づくプログラムを作成せよ.
• teamsに提出
• プロジェクト名 cossim
49
人間のサイズを,身長,体重,頭周の長さ,胸囲,靴のサイズの5種類の数値で特徴付けるとする.
二人の人間の外見がどれくらい類似しているかを,後述のコサイン類似度を用いた度合いで示すプログラムを作成せよ.
利用者は,二人の人間の上記5種類のデータを入力する.プログラムはコサイン類似度に基づき,類似度の数値を出力する.尚,データ型は double の配列を用いることとし,平方根の計算はsqrt関数を用いよ.データはキーボードから入力するものとする.
次のページに入力データ例と期待される結果を示す.
入力と期待される結果
• 175.2, 60.4, 60.0, 91.6, 26.5 と 170.2, 70.4, 63.0, 80.6, 27.0 の場合,類似度は,0.997446
• 175.2, 60.4, 60.0, 91.6, 26.5 と 160.2, 100.0, 70.0, 100.6, 26.0 の場合,類似度は,0.980882
• 175.2, 60.4, 60.0, 91.6, 26.5 と 87.6, 30.2, 30.0, 45.8, 13.25 の場合,類似度は,1.000000
• 丁度半分のスケールの人と比較.
50
コサイン類似度
• 2つのベクトルの向きが完全一致していれば1, 全く逆を向いていれば-1, 直行していれば0を返す指標である.
• 要は似ている(相似な)ものほど1に近い.• 向きのみ見てるので,例えば,全部の値が半分サイズの場合も同じとみなされる.
• 以下に定義を示す.
51
本日は以上
52