スライド 1 - 静岡大学情報学部 峰野研究室

これまでの要点の確認
科学科プログラミング
1
課題への取り組み姿勢について
 何のための勉強なのか理解しましょう
 こちらの要求事項をくみ取ってレポートに書こう
 必須検討事項しかやらないのではダメ




社会で必要とされる人は?
教わっていないから分からない,では通用しない
好奇心と論理的思考力・行動力を養いましょう
教えがいのある人間に育って下さい
 コツコツ頑張ることが重要
 素朴な疑問も積極的に教員やTAに質問しよう

何も恥ずかしいことではありません
2
レポート受理システムの警告メッセージ
コンパイルオプションで以下を指定し,全ての警
告メッセージを表示させています
自分でも『-Wall』オプションを付けてコンパイルし
てプログラムを確認してからレポート提出しまし
ょう
$ gcc –Wall -o rp5b rp5b.c
もしくは
$ gcc -pedantic –ansi –O -Wall -o
rp5b rp5b.c
3
エラーメッセージと警告メッセージ
エラーメッセージ(Error)





誤った記述の報告なので全て解消しないとダメ
エラーと指示された行にエラーがあるとは限らない
2次的なエラーが発生することがある
よくあるエラーは「{」と「}」や「(」と「)」の対応,二重
引用符「”」の対応,文末の「;」を忘れている,など
リンク時エラーは関数名の綴り誤りが多い
警告メッセージ(Warning)


誤りではないが望ましくない記述の報告
初心者はとりあえず無視していてよいが,動作が変
なときは最終的に疑ってみよう
4
コンパイル時のエラーの例
行番号
エラーメッセージ
5
コンパイル時のエラーの例
行番号
エラーメッセージ
左の例は ‘;’(セミコロン) を
全角で入力してしまっている
例である
6
変数の型と
書式指定子
7
型と書式指定子
種類
文字型
(整数型(短整数)
整数型
(長整数)
単精度浮動小数点数型
倍精度浮動小数点数型
宣言
char
short int
int
long int
float
double
printf
%c
%hd
%d
%ld
%f
%f
sscanf
%c
%hd)
%d
%ld
%f
%lf
浮動小数点数について
 非常に大きな実数値などは,指数表記すれば無駄な
0…000という桁を表記しなくて済む


12345678900000000000000000000 = 1.23456789 * 10 28
0.00000000000000000000123456789 = 1.23456789 * 10 -21
【float(単精度):32bit(OS依存)】
仮数
指数
【double(倍精度):64bit(OS依存)】
型名
対象
表現できる範囲
有効桁
int
整数
%d
-214748364~2147483647
---
float
小数
%f
±10-38~1038
約7桁
double
小数
%f
±10-308~10308
約15桁
メモリ使用量,必要
演算精度を考慮して
変数の型を考える
9
異なる型間での演算結果
 整数型同士の演算結果は整数


1+1 は 2
3 * 4 は 12
3 – 4 は -1
4 / 5 は 0 (0.8 や 1 ではない)
 整数型と浮動小数点数の演算結果は浮動小数点数


1 + 2.3 は 3.3
2 * 3.14 は 6.28
3 – 4.4 は -1.4
2 / 0.25 は8.0 (8ではない)
 整数型と浮動小数点数の演算結果は浮動小数点数


1.3 + 2 は 3.3
3.14 * 2 は 6.28
3.4 – 4 は -0.6
4.3 / 2 は2.15
 浮動小数点数同士の演算結果は浮動小数点数


1.3 + 2.1 は 3.4
3.14 * 2.0 は 6.28
3.4 – 4.4 は -1.0 (-1ではない)
4.3 / 0.5 は 8.6
浮動小数点数の表示
浮動小数点数の表示
printf("radius = %f", radius);
radius = 53.6759
小数点以下の桁数を指定する
printf("radius = %.2f", radius);
radius = 53.68
変数宣言と
初期化について
12
初期化
初期化について



初期化とは,『その変数を使う前にその変数にデフォ
ルト値(標準値)を代入すること』
変数は宣言時には何が入っているかわからない!
初期化をしておかないと予期しない動作をすること
がある
プログラムの実行の流れ
プログラムの実行


main の中の1行目から,1行ずつ実行される
以下の例では,プログラム実行時には,1. 2. 3. の
順番で1つずつ実行される
#include <stdio.h>
int main(void) {
1. ⇒ int thisy;
2. ⇒ thisy = 2006;
3. ⇒ printf("this year = %d \n",thisy);
return 0;
}
画面
$ ./newyear
14
プログラムの実行の流れ(1)
プログラムの実行


main の中の1行目から,1行ずつ実行される
1. では,thisy という整数型の変数が用意される
#include <stdio.h>
int main(void) {
1. ⇒ int thisy;
2. ⇒ thisy = 2006;
3. ⇒ printf("this year = %d \n",thisy);
return 0;
}
整数型
thisy
値:不明
画面
$ ./newyear
15
プログラムの実行の流れ(2)
プログラムの実行


main の中の1行目から,1行ずつ実行される
2. では,thisy という整数型の変数に2006が代入さ
れる
#include <stdio.h>
int main(void) {
1. ⇒ int thisy;
2. ⇒ thisy = 2006;
3. ⇒ printf("this year = %d \n",thisy);
return 0;
}
整数型
thisy
値:2006
画面
$ ./newyear
16
プログラムの実行の流れ(3)
プログラムの実行


main の中の1行目から,1行ずつ実行される
3. では,"thisy = " という文字列と,整数型変数
thisy の値を表示する
#include <stdio.h>
int main(void) {
1. ⇒ int thisy;
2. ⇒ thisy = 2006;
3. ⇒ printf("thisy = %d \n",thisy);
return 0;
}
整数型
thisy
値:2006
画面
$ ./newyear
thisy = 2006
$
17
初期化
1から100の総和を求めるプログラム(正解)
#include <stdio.h>
int main(void){
int i;
/* ループ用 */
int sum; /* 合計用 */
i = 1;
/* 初期化 */
sum = 0; /* 合計の初期化 */
while(i<101){ /* 100までループ */
sum = sum + i;
i = i + 1;
}
/* 結果の表示 */
printf("1+2+..+99+100=%d\n", sum);
return 0;
}
初期化 (宣言と同時バージョン)
1から100の総和を求めるプログラム(正解)
#include <stdio.h>
int main(void){
int i = 1;
/* ループ用 */
int sum = 0;
/* 合計用 */
while(i<101){
/* 100までループ */
sum = sum + i;
i = i + 1;
}
/* 結果の表示 */
printf("1+2+..+99+100=%d\n", sum);
return 0;
}
各型のサイズ(処理系にも依存)

printf(“ char(%dバイト)”, sizeof(char));
変数の型
32bitMPU用OS
printf変換
仮数部
char
1byte(8bit)
“%c”
-
short int
2byte(16bit)
“%hd”
-
int
4byte(32bit)
“%d”
-
long int
4byte(32bit)
“%ld”
-
long long int
8byte(64bit)
“%lld”
-
float
4byte(32bit)
“%f”
23bit
double
8byte(64bit)
“%f”
52bit
long double
12byte(96bit)
“%Lf”
64bit
単精度浮動
小数点形式
E
M
(1.0) S  M  2E B
20
浮動小数点数について
 非常に大きな実数値などは,指数表記すれば無駄な
0…000という桁を表記しなくて済む


12345678900000000000000000000 = 1.23456789 * 10 28
0.00000000000000000000123456789 = 1.23456789 * 10 -21
【float(単精度):32bit(OS依存)】
仮数
指数
【double(倍精度):64bit(OS依存)】
型名
対象
表現できる範囲
有効桁
int
整数
%d
-214748364~2147483647
---
float
小数
%f
±10-38~1038
約7桁
double
小数
%f
±10-308~10308
約15桁
メモリ使用量,必要
演算精度を考慮して
変数の型を考える
21
型キャスト
score と,科目数 num の両方
が整数型で,平均点 ave を浮動小数点数で求
めたいとき (仮に score = 648, num = 7)
例えば,総得点
float ave;
.
ave = score / num;
printf("ave = %f", ave);
ave = 92.0000
あれ? 割り切れないはず
型キャスト
score と,科目数 num の両方
が整数型で,平均点 ave を浮動小数点数で求
めたいとき (仮に score = 648, num = 7)
例えば,総得点
float ave;
.
ave = (float)score / num;
printf("ave = %f", ave);
ave = 92.5714
今度は正解
型キャスト
score と,科目数 num の両方
が整数型で,平均点 ave を浮動小数点数で求
めたいとき (仮に score = 648, num = 7)
例えば,総得点
float ave;
.
ave = (float)score / num;
printf("ave = %.1f", ave);
ave = 92.6
表示桁数を1桁にしてみた
型キャスト
score と,科目数 num の両方
が整数型で,平均点 ave を浮動小数点数で求
めたいとき (仮に score = 648, num = 7)
例えば,総得点
ave = (float)score / num;
printf("ave = %f", ave);
下のでも同じ
score / (float)num
(float) score / (float) num
sscanf()
26
sscanf の使い方
sscanf
は文字列(第1引数)から書式に従って
データを読み出し、変数(第3引数)に格納する

整数を入力する
int abc;
sscanf(line, "%d",&abc);

浮動小数点数を入力する
float radius;
sscanf(line, "%f",&radius);
sscanf
で変数を指定する場合変数の前に&
を記述すること
27
sscanf の使い方(1)
printf で表示させてから,fgets,
sscanf でキーボードから入力させるとよい
入力内容を
#include <stdio.h>
int main(void) {
char line[100];
1. ⇒ int thisy;
2. ⇒ printf("thisy = ");
fgets(line, sizeof(line), stdin);
3. ⇒ sscanf(line, "%d", &thisy);
4. ⇒ printf("Thisy is %d. \n", thisy);
return 0;
}
28
sscanf の使い方(2)
printf で表示させてから,fgets,
sscanf でキーボードから入力させるとよい
入力内容を

1. ⇒
2. ⇒
3. ⇒
4. ⇒
}
2. では画面に "thisy = " と表示する
char line[100];
int thisy;
printf("thisy = ");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d",&thisy);
printf("Thisy is %d.\n", thisy);
return 0;
整数型
thisy
値:不明
画面
$ ./newyear
thisy =
29
sscanf の使い方(3)
printf で表示させてから,fgets,
sscanf でキーボードから入力させるとよい
入力内容を

1. ⇒
2. ⇒
3. ⇒
4. ⇒
}
3. ではキーボードから入力された整数を整数型の
変数 thisy に代入する
char line[100];
int thisy;
printf("thisy = ");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &thisy);
printf("Thisy is %d.\n", thisy);
return 0;
整数型
thisy
値:2006
値:不明
画面
$ ./newyear
thisy = 2006
30
sscanf の使い方(4)
printf で表示させてから,fgets,
sscanf でキーボードから入力させるとよい
入力内容を

1. ⇒
2. ⇒
3. ⇒
4. ⇒
}
4. では "Thisy is " という文字列,整数型の変数
thisyの値,"." を表示して改行する
char line[100];
int thisy;
printf("thisy = ");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &thisy);
printf("Thisy is %d.\n", thisy);
return 0;
整数型
thisy
値:2006
画面
$ ./newyear
thisy = 2006
Thisy is 2006.
31
sscanf について (1)
sscanf()
はシステム側が用意している関数
使う場合には,#include <stdio.h> とし,
整数値: sscanf(line, “%d”, &month);
浮動小数点数: sscanf(line, “%f”, &celsius);



第1引数:文字列(取り込みたい文字列)
第2引数:文字列(変数の型指定)
第3引数:変数 (&の意味はポインタの授業で)
では返り値は?
32
sscanf について (2)
sscanf()
の返り値は『変数をどれだけ取り
込めたか』となる
char line[50] = "-500-";
int num;
のとき
char line[50] = "s-500-";
int num;
のとき
sscanf(line,"%d",&num);
の返り値は?
1
# num に -500 が入ります
sscanf(line,"%d",&num);
の返り値は?
0
# num は変化しません
33
sscanf について (3)
以下のようにすると複数の変数を一度に入力
できる
sscanf(line, “%d/%d/%d”, &year, &month,
&day);
line
返り値
year
month
day
1975/4/28
3
1975
4
28
2004/11/11
3
2004
11
11
2004/11
2
2004
11 変化なし
199911
1
199911 変化なし 変化なし
34
sscanf について (4)
sscanf()
の返り値は『変数をどれだけ取り
込めたか』となる
char line[100] = “-500-”;
char str[100];
int num;
のとき
char line[100] = “s-500-”;
char str[100];
int num;
のとき
sscanf(line,“%d%s”,
&num, str);
の返り値は?
2
# num に -500 が入ります
# str に “-” が入ります
sscanf(line,“%s%d”, str,
&num);
の返り値は?
1
# str に “s-500-” が入ります
# num は変化しません
35
sscanf について (5)
sscanf(line,
“%d%s”, &n, dummy); を実
行すると...
line
200*5
sscanfの返り値
2
n
dummy
200 "*5"
2,000
2
Namihei
0
変化なし 変化なし
500.0
2
500 ".0"
-500-
2
-500 "-"
-500
1
-500 変化なし
2 ",000"
36
文字列の長さ
文字列の長さを求めるには,strlen()
を用いる
char line[10] = "Hello!";
以下のように初期化される
line[0] line[1] line[2] line[3] line[4] line[5] line[6]
line[7]line[8]line[9]
‘H’
‘e’
‘l’
‘l’
‘o’
‘!’
‘\0’
この場合,strlen(line)
によって,6という数値
が得られる
#include <string.h>を指定しておく必要あり
37
fgets() と改行コード
fgets
で文字列を取り込む場合,入力した文字
列の最後に改行が追加されるので注意
fgets(line, 10, stdin);
line[0] line[1] line[2] line[3] line[4] line[5] line[6] line[7]
line[8]line[9]
‘H’
‘e’
‘l’
‘l’
‘o’
‘!’
‘\n’
‘\0’
38
改行コードの削除
fgets
で "Hello!" と入力したときは以下のよう
になる
line[0] line[1] line[2] line[3] line[4] line[5] line[6] line[7]
line[8]line[9]
‘H’
‘e’
‘l’
‘l’
‘o’
‘!’
‘\n’
'\0'
この場合,strlen(line)
によって,6 ではなく,7
という数値が得られる
line[strlen(line)-1] に ‘\0’ を入れ改行削除
line[0] line[1] line[2] line[3] line[4] line[5] line[6] line[7]
line[8]line[9]
‘H’
‘e’
‘l’
‘l’
‘o’
‘!’
‘\0’
'\0'
39
複数の変数の表示について
浮動小数点数を2つ同時に表示
float square;
float length;
square = 3.14159;
length = 6.28310;
printf(“squ. = %f , leng. = %f \n”, square, length);
最初の%fには,square
の値が,2番目の%fに
はlength の値が入る
squ. = 3.14159, leng. = 6.28310
複数の変数の表示について
整数と浮動小数点数を2つ同時に表示
int number;
float ave;
number = 4;
ave = 84.34;
printf(“[%d]ave. = %f \n”, number, ave);
最初の%dには,number
にはave の値が入る
[4]ave. = 84.3400
の値が,2番目の%f
データ型・演算子・式
書式指定子
例
意味
%nd
%6d
整数を n 桁 (符号を含む) で表示
%n.mf
%6.2f
浮動小数点数を小数点以下
m 桁で全体 (符号や小数点を
含む) をn 桁で表示
桁数を指定した変数の表示
桁数を指定しない場合
表示桁数を2桁に指定した場合
for(i=8;i<=12;i++){
printf(“%d\n”,i);
}
実行結果
8
9
10
11
12
for(i=8;i<=12;i++){
printf(“%2d\n”,i);
}
実行結果
8
9
10
11
12
43
-15~15の整数を表示する場合
表示桁数を指定しない場合
#表示は左詰
for(i=-15;i<=15;i++){
printf(“%d\n”,i);
}
実行結果
-15
:
-1
0
1
:
15
表示桁数を3桁に指定した場合
#表示は右詰,余白には空白
for(i=-15;i<=15;i++){
printf(“%3d\n”i);
}
実行結果
-15
:
-1
0
1
:
15
44
for()
と
while()
45
for 文と while 文の確認
総和を求めるような,ループ回数がわかりきって
いるような場合の繰り返し(指定回数反復処理)
は while よりも for を使うのが望ましい
while は
for で置き換えることが可能である
これまでに例題や課題で出てきた
例を次に示す
46
インクリメント・デクリメント演算子
インクリメント演算子


i=i+1; など,1を加える演算は頻繁に行われる
C言語では,この演算を,i++; と記述可能
デクリメント演算子

同様に,i=i–1; のように,1を引く演算も同じように,
i--; と記述可能
47
while と for の比較(基本)
num = 0;
/* 5科目の点数の合計を求める */
while( num < 5){
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &score);
sum = sum + score;
num++;
/* num = num + 1 */
}
for (num = 0; num < 5; num++){
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &score);
sum = sum + score;
}
48
while と for の比較(推奨しない例)
num = 0;
while( num<=0 ){
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &num);
}
ループ制御変数に依存しない繰り返し
for (i = 0; num<=0; i++){
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &num);
}
49
while と for の比較(推奨しない例)
score = -1;
/* 0点から100点までの入力 */
while( score<0 || 100<score){
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &score);
}
記述3の省略
for (score = -1; score<0 || 100<score; ){
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &score);
}
50
while と for の比較(推奨しない例)
while( 1 ){
・・・
無限ループ
}
for ( ;; ){
・・・
}
記述1,2も省略して表現は可能
while:不定回数反復処理
for:指定回数反復処理,while的反復処理
51
剰余
(整数計算の余り)
について
52
剰余 (整数割算の余り)
整数同士の割り算は整数になる
100/3  33
余りを求める演算も利用できる
100 % 3  1
剰余の定義


N1 % N2  N1 - (N1/N2)*N2
100 % 3 = 100 – (100/3)*3 = 100 – 33*3 = 1
剰余演算子
% は整数型でしか利用できない
53
剰余演算の例 (n1とn2の剰余)
$ ./amari
n1 = 100
n2 = 3
100 – 33*3 = 1
100 / 3 = 33 ... 1
$ ./amari
n1 = 100
n2 = -3 100 – (-33)*(-3) = 1
100 / -3 = -33 ... 1
$ ./amari
n1 = -100
n2 = 3 -100 –(-33)*3 = -1
-100 / 3 = -33 ... -1
$ ./amari
n1 = -100
n2 = -3 -100 – 33*(-3) = -1
-100 / -3 = 33 ... -1
54
変数の
スコープ
55
変数のスコープの確認
宣言した変数が使える範囲のことを,変数のス
コープと呼びます
#include <stdio.h>
int main(void) {
int x;
printf("x = ");
scanf("%d", &x);
if (x == 5) {
int a;
変数 a の
スコープ
a = x + 2;
}
printf("a = ", a); /* エラー */
return 0;
}
変数 x の
スコープ
56
変数のスコープの確認
sample() のローカル変数 x をいくら変更しても,
関数
各関数で同じ名前の変数を宣言した場合,それ
main() のローカル変数 x は何の影響も受けません!
ぞれは別の変数として扱われる!
#include <stdio.h>
void sample(int);
int main(void) {
int x;
関数 main
scanf("%d",&x); 変数 x のスコープ
sample(x);
printf("x = %d\n", x);
return 0;
}
void sample(int a){
int x = a;
関数 sample()
変数 x のスコープ
x = x + 100;
return;
}
実行結果
$ ./a
98
x = 98
↑
x = 198 とでる?
それとも
x = 98 とでる?
57
配列の要素数を超えてアクセス
 他の変数の値を参照,書き込むと破壊される
 不許可のメモリ領域へアクセスした場合、強制終了
プロセスY
プロセスX
プロセスA
多
重
仮
想
記
憶
の
概
念
コードセグメント
コードセグメント
コードセグメント
プログラム自身
(読み出し専用)
データセグメント
データセグメント
データセグメント
グローバル変数,静的変数
(読み書きOK) (static変数)
スタックセグメント
スタックセグメント
スタックセグメント
ローカル変数,関数の引数,
戻り値など(読み書きOK) 58
例題: ex4a
整数の値が有効値(min~maxの間)かどうかを
判定する関数 int RangeValidator(int num,
int min, int max) をつくろう
関数の仕様は以下の通り


num が min 以上 max 以下の範囲内なら 0 を返す
それ以外なら: 0 以外の数字を返す
59
例題: ex4a
main 関数
do{
printf( "Input Number (1 - 100): " ); 関数 main
-------------fgets( line, sizeof( line ), stdin );
result != 0
sscanf( line, "%d", &num );
}while( RangeValidator( num, 1, 100) != 0 ); 関数
RangeValidator 関数
int RangeValidator(int num, int min, int max)
if (num が min 以上 max 以下なら) return 0;
return -1;
}
main
-------------num = num;
min = 1;
{
max = 100;
60
例題: ex4a (引数の検査)

指定された範囲からどれだけ離れているかを返す
main 関数 (num:300)
do{
printf( "Input Number (1 - 100): " );
fgets( line, sizeof( line ), stdin );
sscanf( line, "%d", &num );
result = RangeValidator(num, 1,
100);
if (result が 50 以上 または -50 以下な
ら){
printf("めっせーじ");
}else if (10以上または-10以下なら) {
printf("めっせーじ");
}else {
printf("めっせーじ");
}
}while( result != 0 );
main
-------------result = 200;
RangeValidator 関数
int RangeValidator(int num, int min, int
max) {
int result;
if (num が min 未満なら){
result = num - min;
}else if (num が max よりも大きけれ
ば){
result = num - max;
}else{
result = 0;
}
関数
return result;
}
--------------
num = 300;
min = 1;
max = 100;
result = 200;
61
疑似乱数
の生成
62
擬似乱数の発生について
srand(time(NULL));
for(y = 0;y < 10;y++){
for(x = 0;x < 10;x++){
c[y][x] = rand()%3;
・・・
srand(time(NULL));をc[y][x] = rand()%3;の前
に置いたら全て同じ擬似乱数となった
現在時刻(秒単位)をseedに設定しているため!
63
time() 関数の使い方
time()


とは?
1970年1月1日0時0分0秒(世界標準時)からの経過
時間を教えてくれる標準関数
例えば,整数型の変数 timer にその値を入れたい
場合
timer = (int)time(NULL);
(詳しくは, "MANPAGE time" でネット検索してください)
日本時に直すには? JST は GMT時間に9時間足せばよ
い
timer = (int)time(NULL) + 9*60*60;
64
偶数と奇数の判定法
偶数か奇数かを判定するには,その数が2で割
り切れるかどうかを調べればよい
 2で割った余りが0
奇数:2で割り切れない  2で割った余りが1
偶数:2で割り切れる
int
page; とした場合,page が偶数か奇数か
は page % 2 の結果が 0か 1かどうかで判定
すればよい
65
#include <stdio.h> の意味
#:コンパイラに指示を与える命令
include:指定したファイルをプログラムに含める
stdio:標準入出力(standard
input output)
.h:ヘッダファイル

cd /usr/include; ls std*; less stdio.h で確認可能
例)<stdio.h>
printf(), fgets(), sscanf() など標準入出力関係
<stdlib.h>
srand(), rand() など標準ライブラリ関係
<time.h>
time() など時間関係
66
日本語の文字コード
 Shift-JIS

MS-DOSで日本語用コードとして採用後,広く普及
 ISO-2022-JP

(JIS)
特に電子メールでよく利用される日本語用コード
 EUC-JP

UNIX上で日本語用コードとして広く利用
 UTF-8



近年の多くのLinux OSの標準文字コードとして利用
世界の主要な言語で扱われる文字のほとんどを収録
漢字や仮名などの表現に3バイト要する
67
for の二重ループの実行例
j=
j=
j=
j=
j=
j=
for(i = 0 ; i < 5 ; i++){ /* 外ループ */
for(j = 0 ; j < 5 ; j++){ /* 内ループ */
printf("%3d",i*5+j);
}
0 1 2 3 4 5
printf("\n"); /* 改行 */
i=0
0 1 2 3 4 X
}
→
→
→
→
→
→
i=1
i=2
i=3
i=4
i=5
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
X
X
X
X
X
68
インデントを付けましょう
文の埋め込み構造が基本
#include <stdio.h>
int main(void){
int i, j;
main関数は変数宣言文
for文
return文
の3文構成
for (i = 1; i <= 9; i++) {
for (j = 1; j <= 9; j++) {
printf(“ %2d”, i * j);
}
printf(“\n”);
}
}
return 0;
for文の中に、
for文
printf文
が埋め込まれ
for文の中に、
printf文
が埋め込まれている
エスケープシーケンス
27番に割り当てられている
[ESC] コードから始まるシーケンス (コードの並
び) をエスケープシーケンスと呼びます
アスキーコード

特に,コンソールアプリケーションを作成する際に,
画面を消去したり,画面の好きな位置にカーソルを
移動したりできます.
今回は以下2つのエスケープシーケンスを紹介


画面に表示さている文字をすべて消去して,カーソ
ルを左上に移動する
指定された数だけカーソルを左に移動する
70
#define とエスケープシーケンス
#define CLR
printf("\033[2J")
#define LOCATION(x,y) printf("\033[%d,%dH",(x), (u))
#define LEFT(x)
printf("\033[%dD" ,(x))
\033 は,33(8) であり,アスキーコード27番
/* 画面の文字を全部消す */
CLR;
=> gcc がコンパイル時に
printf("\033[2J"); に変換する
/* 次のprintf による画面表示を左上からにする */
LOCATION(1,1); => printf("\033[%d,%dH",(1),(1));
/* 次のprintfによる画面表示を同じ行の左14文字前に移動する */
LEFT(14); => printf("\033[%dD", (14));
71
ASCIIコード
文字型



(char 型)
メモリ上に用意されるサイズは1Byte で,数値で表
すと,-128~127 の値を表現できる
特に,0 ~ 127 を利用して,文字を数値として管理
している(ASCIIコード)
例えば,32番には ‘ ’(空白),65番には ‘A’, 97番
には ‘a’ が割り当てられている

ASCIIコード表参照(教科書P.407 付録A)
72
ASCIIコード
文字型の変数の宣言
char ch;
文字の代入
ch = 'A'; /* 文字を代入(直接指定) */
ch = 65; /* 文字を代入(ASCIIコード指定) */
文字の表示
printf("文字='%c' , ASCIIコード=%d", ch, ch);
文字='A' , ASCIIコード=65
73
ASCIIコード
0
から 31 には,制御コードと呼ばれるものが割
り当てられている

基本的には表示するための文字ではなく,モニタや
プリンタなどを制御するために用いられる
特に以下の2つが重要である


0番: '\0' (文字列終端コード)
10番: '\n' (改行)

その他,NUL,SPとかあるが,実際は1文字
74
ASCIIコードに対応する文字
32
48
から 47:記号や算術演算子等
ASCIIコード
対応する文字
32
(空白)
33
!
34
"
35
#
36
$
37
%
38
&
39
'
40
(
41
)
42
*
43
+
44
,
45
-
46
.
47
/
から 63:数字や論理演算子等
48
'0'
49
'1'
50
'2'
51
'3'
52
'4'
53
'5'
54
'6'
55
'7'
56
'8'
57
'9'
58
':'
59
';'
60
'<'
61
'='
62
'>'
63
'?'
75
ASCIIコードに対応する文字
64
から 95:英大文字と鍵括弧等
ASCIIコード
対応する文字
64
'@'
65
'A'
66
'B'
67
'C'
68
'D'
69
'E'
70
'F'
71
'G'
72
'H'
73
'I'
74
'J'
75
'K'
76
'L'
77
'M'
78
'N'
79
'O'
80
'P'
81
'Q'
82
'R'
83
'S'
84
'T'
85
'U'
86
'V'
87
'W'
88
'X'
89
'Y'
90
'Z'
91
'['
92
'\'
93
']'
94
'^'
95
'_'
76
ASCIIコードに対応する文字
96
から 126:英小文字と中括弧等
127

ASCIIコード
対応する文字
96
'`'
97
'a'
98
'b'
99
'c'
100
'd'
101
'e'
102
'f'
103
'g'
104
'h'
105
'i'
106
'j'
107
'k'
108
'l'
109
'm'
110
'n'
111
'o'
112
'p'
113
'q'
114
'r'
115
's'
116
't'
117
'u'
118
'v'
119
'w'
120
'x'
121
'y'
122
'z'
123
'{'
124
'|'
125
'}'
126
'~'
は制御コード (DELETEキー)
パンチカードの時代は全ビット1(穴)をDELとしてい
たための名残り
77
文字の判定への応用
文字の判定の仕方

数字かどうか
if ('0' <= ch && ch <= '9')

大文字アルファベットかどうか
if ('A' <= ch && ch <= 'Z')
例えば下側は以下のようにASCIIコードでも記述
可能である
if (65 <= ch && ch <= 90)
78
if 文の動作
条件A
No
Yes
命令A
条件B
Yes
命令B
No
if (条件A) {
命令A;
}
if (条件B) {
命令B;
}
考えられる状況 (4通り)
1. 条件A も 条件B も成り立つ
2. 条件A が成り立ち,条件B は成り立たない
3. 条件A は成り立たたず,条件B は成り立つ
4. 条件A も 条件B も成り立たない
79
if, else 文の動作
条件A
if (条件A) {
動作A;
} else {
動作B;
}
No
Yes
動作A
動作B
考えられる状況 (2通り)
1. 条件A が成り立つ
2. 条件A が成り立たない
80
if, else if 文の動作
条件A
No
Yes
処理A
条件B
Yes
処理B
No
if (条件A) {
処理A;
} else if (条件B) {
処理B;
}
考えられる状況 (3通り)
1. 条件A が成り立つ
2. 条件A は成り立たたず,条件B は成り立つ
3. 条件A も 条件B も成り立たない
条件Aが成り立たないときだけ
else if (条件B) が判定される点に注意
81
if文 ー発展:関係演算子
演算子
<
>
<=
>=
==
!=
意味
より大きい
より小さい
以上
以下
等しい
等しくない
使用例
a<b
a>b
a <= b
a >= b
a == b
a != b
if文 ー発展:論理演算子
演算子
&&
||
!
意味
かつ(AND)
または(OR)
~でない(NOT)
使用例
a && b
a || b
!a
2の補数とは
 基数の補数を負の数の表記法として採用すると,最上
位桁からの桁上がり(オーバーフロー)を無視すれば,通
常の加算処理で負の数の加算(つまり正の数の減算)が
行え,2の補数は多くのコンピュータで負の数の内部表
現に採用されている
01111111111111111111111111111111(intの最大値)
+ 01111111111111111111111111111111(intの最大値)
11111111111111111111111111111110
00000000000000000000000000000010
コンピュータ内では,負の数-nは,正の数nの2の補数で表現され,
先頭の符号ビットは1となる.逆に言えば,先頭の符号ビットが1なら
2の補数表現である.つまり,ビット反転して1足せばnが分かる.
微分とは?
 滑らかに運動している物体の速度は,「移動距離÷経過時間
」で与えられる
 物体の位置xが時刻tの関数であるとすると,ある時刻tからΔt
の間にx(t0)からx(t0+Δt)まで移動したときの平均速度Vは,
x(t0  t )  x(t0 )
V
t
 Δtを0へ近づけた極限を考えると
x(t  t )  x(t )
V (t )  lim
t
t 0
dx(t )
任意の時刻tにおける速度は,位置を表

すx(t)が微分可能であれば求められる
dt
(x(t)の形が未知であろうが)
85
解析解と数値解
dx (t )
V (t ) 
dt
 解析解(厳密解)


微分方程式を満たす関数x(t)の式を求めて得た解
x(t )  V (t )t  C
一般解


両辺をtで積分して得られる解の形式
特殊解

x(t )  V (t )t  1
初期条件(t=0においてx(0)=1など)から定数Cが一意に定まっ
た解の形式
 数値解

微分方程式を満たす関数x(t)の値を求めて得た解

Δtをある有限の大きさを持つと考え,微分の定義式からlimを外
して近似(離散化)
dx (t ) x(t  t )  x(t )
V (t ) 

dt
t
86
数値シミュレーション
 世の中の様々な物理現象の多くは,数学的には微
分方程式によって記述できる
 しかし,代数的に解(解析解(厳密解))を得ることが
不可能な場合もある
 数値解析(数値シミュレーション)


代数的に解(解析解(厳密解))を得ることが不可能な解
析上の問題を近似的に解く(数値解)手法
√2のように,正確な解を有限時間で求めることは不可能
なため,ある程度の誤差範囲内で近似解を求める
誤差 = 「解析解」と「数値解」のズレ
analytical
numerical
87
放物運動(水平投射)の解析解
 初速度v0[m/s]で水平に投げ出された物体は,水平方向
には速度v0[m/s]の等速直線運動をし,鉛直方向には自
由落下運動をする
 時刻t[s]における速度v[m/s]の物体のx成分vx[m/s],y
成分vy[m/s],座標(x,y)は,
水平投射の公式
(解析解(厳密解))
vx  v0
x  x0  v0t
v y   gt
1 2
y  y0  gt
2
88
放物運動(水平投射)の数値解析

y方向の速度は,微分の定義式からlimを外して近似(離散化)した次の微分
方程式を満たす
dy (t ) y (t  t )  y (t )
V (t ) 

dt
t


また,時刻0において重力加速度gの等加速度運動なので,
よって,以下の差分方程式が得られる
y (t  t )  y (t )
  gt
t
y(t  t )  y(t )   gt  t
y(t  t )  y(t )  gt  t
v y   gt
整理すると漸化式が
得られ,数値解を求
められる
Δt を時間刻み(時間分解能)と呼び,解析者が任意に決定
89
時間分解能(数値解析)
y(t  t )  y(t )  gt  t
<時間分解能 Δt=1秒 とすると>
y(1)=y(0+1)=y(0)- g・0・1=100,000
y(2)=y(1+1)=y(1)- g・1・1= 99,990
y(3)=y(2+1)=y(2)- g・2・1= 99,970
y(4)=y(3+1)=y(3)- g・3・1= 99,940
y(5)=y(4+1)=y(4)- g・4・1= 99,900
・・・・
一方,解析解より
t=0のとき,y(0)=100,000 [m]
簡単のため,重力加速度gを -10[m/s2] とする
<時間分解能 Δt=1/10秒 とすると>
y(0.1)=y(0+0.1)=y(0)- g・0・0.1=100,000
y(0.2)=y(0.1+0.1)=y(0.1)- g・0.1・0.1=99,999.9
y(0.3)=y(0.2+0.1)=y(0.2)- g・0.2・0.1=99,999.7
y(0.4)=y(0.3+0.1)=y(0.3)- g・0.3・0.1=99,999.4
y(0.5)=y(0.4+0.1)=y(0.4)- g・0.4・0.1=99,999.0
y(0.6)=y(0.5+0.1)=y(0.5)- g・0.5・0.1=99,998.5
y(0.7)=y(0.6+0.1)=y(0.6)- g・0.6・0.1=99,997.9
y(0.8)=y(0.7+0.1)=y(0.7)- g・0.7・0.1=99,997.2
y(0.9)=y(0.8+0.1)=y(0.8)- g・0.8・0.1=99,996.4
y(1.0)=y(0.9+0.1)=y(0.9)- g・0.9・0.1=99,995.5
1 2
1
y  y0  gt  100 ,000  10  (1) 2  99,995
2
2
離散化誤差
時間分解能が粗いと精度は低いが計算は速い,
細かいと精度は高いが計算に時間がかかる
90
解析解と数値解
離散化誤差 = 「解析解」と「数値解」のズレ
analytical
時間分解能Δt=0.1
numerical
時間分解能Δt=0.025
http://oshima.eng.niigata-u.ac.jp/OpenFOAM/ja/basicsDivided.pdf
91