狠狠撸

狠狠撸Share a Scribd company logo
C言語講習会 第2回
ロボット技術研究会
情報工学科
@odenhadengaku
今日やること
? 変数,型の続き
? 制御構文
? 関数
変数 型(復習)
? 情報を数値や文字とし
て保存する必要がある
? ロボットが何回線を通過
したか
? 成績の合計値
? C言語では数値や文字な
どの情報を変数として
保持することができる
a 3
変数 型(復習)
? 変数にはどのデータを入れて
もいいわけではない
? 整数,小数,文字などタイプを
指定する必要がある
→型
? 変数を定義するには,
int a;
(型)(変数名)
のように記述する
? 定義せずに,いきなりaを利用す
ることはできない
? 変数名は基本自由
? int b,c,d,e;のようにまとめて定義
もできる.この場合すべてint型
変数 型 [注意]
? ここで,右のコードに
ついて考えてみる
? double型の変数dを表示
させるには,
printf(“%f?n”,d);
とする
? 一見すると,d,eの値は
同じであるように見え
るが…?
変数 型 [注意]
? 出力結果は
? 結果が違う.なぜ?
? 異なる型同士の演算も
出来る場合もあり,そ
の場合は精度の高い方
の型
? intとdouble → double
? a/b はdouble型の値
変数 型 [注意]
? 8行目の,a/cではint型
同士の計算のため,答
えはint型.除算の際に
小数部分が切り捨てら
れてしまう.切り捨て
られた後にeに代入され
る
? よくあるミスで,
エラーも出ないので注
意
変数 型 [注意]
? じゃあどうすれば?
→キャスト演算子
? (double) a;
? と書くと,変数aがこの
命令に限りdouble型とし
て扱われる
? 8行目を
? double e = (double) a/c;
? とすればdとeは同じ値に
変数 型 [注意]
? 右のプログラムはただ
2147483644から1ずつ足す
だけ
? もちろん答えは…?
変数 型 [注意]
? 実行結果
? 突然負の値に
? 壊れた?
変数 型 [注意]
? 数は無限には扱えない.上限,下限がある
? 変数はコンピュータのメモリ上にあるから
? よくあるバグの1つ
? 上限を超えることをオーバーフローという
? 逆に下限を下回ることをアンダーフローという
? long int,long long int とすると…?
変数の型 最小値 最大値
char -2^7(-128) 2^7-1(127)
int (32bit) -2^31(-2147483648) -2^31(2147483647)
float ±10^(-38)くらい ±10^(38)くらい
double ±10^(-308)くらい ±10^(308)くらい
演習というほどのものではない何か
? ちょっと考えてみよう
1. char型の変数cを文字’p’で初期化し,「初期化した文字
はpです」と出力させよう
? 文字の場合は ‘(シングルクォーテーション)で囲む
? printfでchar型の変数を表示させるには,%cを使う
2. double型の変数p,qを定義し,好きな値を代入してから,
1次方程式px + q = 0の解を出力せよ.
? printfでdouble型の変数を表示させるには,%fを使う
演習というほどのものではない何か
1.
2.
unsigned,const,volatile [応用]
? C言語では扱える数に制限がある
? 負の数にはならないから,正で扱える数を増や
したい場合がある
? unsigned を使う
? 型の前につける
? unsigned char, unsigned int…
変数の型 最小値 最大値
unsigned char 0 255
unsigned int (32bit) 0 4294967295
unsigned,const,volatile [応用]
? 1度定義した変数の値を絶対に変わらないことを
保証したい場合がある
? 自分で定義した定数とか
? const を使う
? 型の前につける
? const char, const int…
? constをつけた変数は,値を変更できない.
? 定義するときに,初期化しておく必要あり
unsigned,const,volatile [応用]
? 実はコンパイルする際に,コンパイラはソース
コードを最適化することでパフォーマンスを向
上させている
? 無駄な処理を省く,使われてない変数を消去…
? この最適化は,時として仇になる
? マイコンには割り込みという機能がある
? ある処理をしてる時に,その処理に割り込む形で他の処理をす
ること
? 変数が最適化されてしまうことにより,割り込み処理が期待通
りに動かないことがある.
unsigned,const,volatile [応用]
? 最適化したくない場合は,その変数の宣言時に
volatile int a;
? とすることで,この変数は最適化の影響を受け
ない
? もし,マイコンの割り込み処理が期待通り行かない場合は,
これを疑ってみるとよい
通常時処理 通常時処理
割り込み
処理
ここで一区切り
? 今までは上から下の一本道のコードだった
? 一本道だと変数の中身によってコードを変えら
れない
– aが偶数/奇数だったらこの処理を…ができない
? 同じような処理を何回もしたい場合は何回も似
たコードを書かなければならない
– a[0] = 1; a[1] = 1;…a[99]=1; 100回も書くの?
? これからは1本道ではなく,分岐や繰り返しを
する処理を学ぼう
制御構文(if)
? 右のソースコードを書い
て実行しよう
– 答えは省略
– でもなんとなくわかるよね
…?
? できた人は,4行目の数
字を変えて,自分の予想
と合っているか確かめて
みよう
制御構文(if)
? もし~だったら~する
? こういうのはif文を用いる
if(条件式){
処理;
}
else if(条件式){
処理;
}
…
else{
処理;
}
制御構文(if)
? if-elseは省略可/複数可
? else は省略可
? 条件式は非0の時,真
– if(1)は必ず中身の処理を行う
– if(0)は必ず中身の処理を行わない
制御構文(if)
? 関係演算子とは
d > 4
? のように2つの値を比較す
る演算子
– 条件が真ならば1を
– 条件が偽ならば0を返す.
? 複数の条件(AかつBなど)を
使いたい場合は,論理演
算子を使う
制御構文(if)
関係演算子 意味
<,> より大きい/小さい
<=,>= 以上,以下
==,!= 等しい,等しくない
論理演算子 意味
&&,|| かつ,または
! 否定
? if(x == 1 && y == 2)
? xが1かつyが2の時は真
? if(x == 1 || y == 2)
? xが1もしくはyが2の時は真
? if(!(x == 1 && y == 2))
? xが1かつyが2の時でない時は
真
制御構文(if)[注意]
? if(d == 4)をif(d = 4)
としてしまうミスが多い
? d = 4は,代入を意味し,
「d = 4」を評価すると代
入した値が返ってくる.
– if(d = 4) はif(4)となり常に真
– コンパイルエラーにならない
制御構文(switch)
? 右のコードを書いてみよう
? これも答えを予想してみよ
う
– caseの行の最後は「;」では
なく「:」です
制御構文(switch)
? 右のように変数dが1か,
2か3か…を判断するのに
if-elseを用いると冗長
– else ifをたくさん繋げることになる
– switch文で綺麗に
? switchで指定された条件式
の値と同じ値のcaseにジャ
ンプする
? break;に達するとswitch文
の{}から脱出
? どのcaseにも一致しない場
合,defaultにジャンプ
制御構文(switch)[注意]
? switch文は整数値しか判定
できない
– double,char型などの判定は
できない
? break; のつけ忘れに注意
– 付け忘れると,そのまま下の
行の命令を実行してしまう
– 8行目のbreakがないと,
case1の場合に,「dは1で
す」と「dは2です」が両方
出力される
制御構文(switch)[注意]
? 逆に,”わざと”breakを付
けないことで,次のような
プログラムもかける
制御構文(if,switch)[注意]
? double,float型など,実数
を扱う型で==,!=を用いる
と厄介
? 右のプログラムを実行する
と”aとbは同じ”と出力され
そうだが,実際は…
– 理由は,内部的には2進数で
表現されているが,それでは
10進数が正確に表せないから
– コンピュータサイエンスの
授業で詳しくやる(はず)
? 実数型では,==,!=を使う
べきでない
忘れてたやつをいくつか???
? ideoneのホームを開いた時にある
//your code goes here
? はコメントといい,プログラムの動作には関係
ない
– だから残したままでもいい
– ここでこんなことをしていると書くことで,後で見返
したり,他の人が見るときにわかりやすくする
– 「//」はその行の//以降がコメントされる
– 「/*」と「*/」の間はすべてがコメントされる
忘れてたやつをいくつか???
? if-else文を1行で簡潔に書きたい場合がある
? 三項演算子(関係演算子)
? (条件式) ? (A) : (B)
– 条件式が真のときはAが,偽のときはBが実行される
– int abs_a = (a >= 0) ? a : -a;
– 可読性があまり良くないので,使うべきでない派と使ってもいい
だろ派がいたりいなかったりする(気がする)
忘れてたやつをいくつか???
? 今まで様々な演算子を取り扱ってきた
– =,+,-,*,/,++,--,<,…
– これらには順序/優先度がある
– (2 + 3) * 4 なら()が先
– とりあえず()が一番
– 詳しいことは,必要なときにググれば良い
制御構文(for)
? 今までは分岐につ
いて
? これからはループ
について
? 右のコードを書い
て実行しよう
制御構文(for)
? for文は繰り返しを
実現する機能
for(i = 1; i <= 10; i++){
処理;
}
初期化 条件式 更新
制御構文(for)
? for文は繰り返しを
実現する機能
? 「初期化」で変数
の値を決定
? 「条件式」が真の
間変数を「更新」
し続けながら処理
を繰り返す
初期化
条件式
更新
処理ループを抜ける
偽 真
制御構文(for)
? 具体的には,
初期化 iに1を代入 i : 1
条件式 i<=10は真 i : 1
処理 printfを実行 i : 1
更新 i++; i : 2
条件式 i<=10は真 i : 2
??????
更新 i++; i : 11
条件式 i<=10は偽 ループを抜ける 10回繰り返される
制御構文(for)
? break;を使うとfor
文の{}の中から抜け
出せる
– switch文の{}を抜け
出せたのと同じ
? 右下のプログラム
は,iが5の時に強制
的にループから抜
ける
– Hello World 5回目
は出力される…?
制御構文(for)
? 実行結果は以下の
様になるはず
制御構文(for)
? 前回少しだけ話した配列
– 箱がたくさんあるイメージのやつ
– int a[100];のように宣言する
– for文と相性がよい
右のように[]の中にiという
変数を使うことで1度の記
述ですべての箱(変数)
にアクセスできる
制御構文(while)
? 以下のコードを実行してみよう
制御構文(while)
? ループの回数が不明である場合がある
– 下のプログラムは,1からいくつまでの値を足すと100を超え
るか計算するもの.しかし,何回ループすればいいのかは不
明
– このようなときに飞丑颈濒别文は便利
制御構文(while)
? while文は,条件式が真であるかぎりループし続ける
? 下では,sum < 100であるかぎり,countに1を足し,
sumにcountをたすという処理をし続ける.
? for文と同様に内部で,break;も使用できる
while(条件式){
処理;
}
制御構文(while)
? 条件式は,0以外なら真,0ならば偽となる(ことを前に
説明).つまり,右下のようにすると無限ループになる.
– 常時処理をループさせて,必要なときにbreak;を用いてループ
から抜けるなどの手法を用いることもある.
while(1){
処理;
if(何か)
break;
}
制御構文(do-while)
? while文では,最初から条件式が偽だった場合は,中身
の処理は行われない
? 条件式の結果に関わらず,最低1回は処理をしたい場合
がある
? そのときは,do-while文を用いる
? あまり使わない
do{
処理;
}while(条件式);
制御構文(while)
? 以下のコードを実行した結果は次のようになる
? 気づいた人もいるかもしれないが,for文とwhile文は
書き換え可能
制御構文の演習
1. 1から2015までの和を求めるプログラムを,for文を
使って書いてみよう.
2. 1から2015までの和を求めるプログラムを,while文を
使って書いてみよう.
3. 1000 未満の 3 か 5 の倍数になっている数字の合計を
求めよ.(PE1より)
? 3の倍数かどうかはn % 3の余りを見れば…
? 「3か5の倍数」よりor,つまり「||」(論理和)が必要
制御構文の演習
sum: 2031120
制御構文の演習
sum: 233168
忘れてたやつをここで???
? if,for,while文の中身の処理が1行である場合は,
{}を省略できる
? 右はif文の例.他も同様
? しかし注意して欲しいのは,
{}がないと,1行しかif文の効果が適用されな
いということ
再びのvolatile[応用]
? 以前出てきた最適化をしないよう命令する
volatileはどう使われるのか
? マイコンにおいて,割り込み処理によってflag
変数が1となるまでプログラムを停止させてお
く方法として下が考えられる
? flagが0であるかぎり無限ループ
? 処理すらない場合
…
…
…
while(flag == 0);
…
再びのvolatile[応用]
? コンパイラから見ると,変数
flagは変更されない値にしか
見えない
? 割り込み処理はマイコンによる
処理のため
? flagが変更されないので,コンパ
イラは非効率と判断する
? わざわざ1回ループするごとにflagを
評価しているため
? よってコンパイラは勝手に右
のように最適化をする場合が
ある
? flagの評価は1回で済む
…
…
…
while(flag == 0);
…
…
…
…
if(flag == 0)
while(1);
…
再びのvolatile[応用]
? このように書き換えられると,
割り込み処理でflagが1になっ
てもループからは抜け出せな
い
? flag変数にvolatileをつけるこ
とで,最適化を防ぐ!
? 他にも,変数の代入順序を最
適化により勝手に変えられた
くない場合などにも有効
…
…
…
while(flag == 0);
…
…
…
…
if(flag == 0)
while(1);
…
関数
? 今まで,if,switch,for,while文を学んできた
? これだけで結構なことができる.
? しかしこれだと,プログラムをすべてmainの中
に記述することになる.
? プログラムが非常に見難くなり,バグに対処しにくい
? 例えば「1からkまでの和」を求めるプログラムを何度も使う
時,そこにバグがあったらすべて書きなおさねばならない
? 特定の処理をするプログラムを部品として使い
たい→関数
関数
? 関数の定義方法
? 関数には,引数と戻り値
(返り値)があり,returnに
達すると関数は終了
int add(int a, int b){
…
処理;
…
return a + b;
}
戻り値の型 関数名 引数
戻り値
関数
? 右では,8行目でadd(3,4)を
評価する際に,14行目の関
数の実体を呼び出す.このと
き,aには3,bには4が入る.
? returnに到達すると,関数は
終了し,戻り値を持って8行
目に戻る.cには7が代入され
る
? 戻り値は1つしか返せない
関数
引数
引数
引数
戻り値
関数
? 引数や戻り値がないような関
数の場合はvoidを指定する.
? この関数を呼び出す際には,
引数の情報はいらないが()は
省略できないので,10行目
のように
? printfHW();
? のように呼び出す
関数
? 実は,今まで使ってきた
mainは,main関数という関
数
? 引数はなく,戻り値として0を
返す関数と解釈できる
? 文字を表示するのに使ってい
たprintfも関数
? 中身を記述しているのがstdio.h
関数
? コンパイラはソースコードを上か
ら解釈するので,予め「こういっ
た関数を使う」と宣言をしないと,
いざ関数を使うときにコンパイル
エラーが発生
? ideoneでは問題なく実行できるが,こ
れは特殊.gccや他のIDEではエラー
? 予め宣言しておくことを,プロト
タイプ宣言という.
? 3,4行目の部分
関数
? 実行結果は以下の様になるはず
関数
? 右のプログラムについて考え
る
? 変数localと変数globalの挙動
の違いを考える.
関数
? 実は,変数には主に2種類ある
? ローカル変数
? グローバル変数
? ローカル変数は,関数の内部
で宣言,定義される変数
? 宣言した関数内でしか参照できな
い
? 先ほど紹介したadd関数の変数a,b
も,今までmain関数内で定義し
た変数もすべてローカル変数
? 関数が終了すると,メモリが消滅
するので値が保存されない
? 変数は定義しないと使えない
ので,関数の最初で通常定義
する
関数
? グローバル変数は,関数の{}の
ブロックの外側で定義される
変数
? いろんな関数から参照できる
? プログラムが終了するまでメモリ
が消滅しないので,値が保存され
る
? プログラム全体で,普遍的な変数
を表現するのに便利
? どこからでも参照できるとい
うことは,どこからでも変え
ることができてしまうので,
むやみに利用すべきではない.
関数
? 右のプログラムでは
? のように動作する
global local
1回目func() 0 → 1 0 → 1
2回目func() 1 → 2 0 → 1
3回目func() 2 → 3 0 → 1
保存
保存
破棄
破棄
関数
? したがって実行結果は
? のようになる
関数[応用]
? 先ほど変数は2種類といった
が,もう1種類存在
? 静的なローカル変数
? 右の17行目のローカル変数を
? static int local = 0;
? とすればいい
? ローカル変数とグローバル変数の
中間の性質を持ち,宣言した関数
からしか呼び出せないが,関数が
終了しても値は保存される.
? プログラムの実行結果はglobalと
同じ結果に
関数[応用]
? 関数は自分自身を呼び出して
使うことができる.→再帰
? 再帰を使うことで繰り返し処
理(for,while)を用いるよりもプ
ログラムが簡潔に書ける場合
がある
? 右は,nの階乗を再帰あり/な
しで求める関数
? 漸化式を想像するとわかりや
すい?
関数[応用]
? 例えばfactorial(3);とすると,
factorial(3)
3 * factorial(2)
2*factorial(1)
1*factorial(0)
1
となるので,
3 * (2 * (1 * (1))) → 6 となる
おまけ
? ローカル変数は関数内でのみ参照できる
? それは,変数にはスコープ(有効範囲)があるから
? {}で囲まれた部分がスコープになる
? スコープを超えて参照できない.
? 右のプログラムを見ると,変数kの
スコープは6行目の}まで
? なのでコンパイルエラーが起こる
? スコープに注意すると,右下
の7,9行目は何が出力される?
おまけ
? 今まで条件文を習ったが,無条件分岐をするgoto文と
いうものもある
? しかしこれは禁じられた条件文と言われるほど(?)
使うべきでないという暗黙の約束がある
? goto文を使うと,プログラムに一貫性がなくなり,構造が崩れ
るため
? どうしても知りたいならググってください
演習
1. 次の関数を作ってみよう
1. 整数型の引数aをとり,1からaまでの合計を戻り値
として返す関数
2. 整数型の引数a,bをとり,a^2 + b^2を返す関数
2. [難?]引数nを与え,素数ならば1,そうでないならば0
を返す関数を作成し,それを利用して10001番目の素
数を求めよ.(PE7)
? なぜ素数ならば1で,そうでないなら0なのかというと,素数
判定する関数をisPrime(int n)とすると if(isPrime(n))で「nが素
数ならば」を表現できるため
? 他の言語だと真偽を表すbool型というのがある
予告
? 配列再び
? ビット演算
? マクロ
本日は以上です
ありがとうございました

More Related Content

颁言语讲习会2