狠狠撸

狠狠撸Share a Scribd company logo
C言語講習会 第3回
ロボット技術研究会
@odenhadengaku
前回のまとめ
? 変数,型
? 制御構文(if,switch,for,while)
? 関数
今日やること
? 配列再び
? ビット演算
? プリプロセッサをちょっと
? マイコンのプログラミングをちょっと
関数[復習]
? 今まで,if,switch,for,while文を学んできた
? これだけで結構なことができる.
? しかしこれだと,プログラムをすべてmainの
中に記述することになる.
? プログラムが非常に見難くなり,バグに対処しにくい
? 例えば「1からkまでの和」を求めるプログラムを何度も
使う時,そこにバグがあったらすべて書きなおさねばな
らない
? 特定の処理をするプログラムを部品として使
いたい→関数
関数[復習]
? 関数の定義方法
? 関数には,引数と戻り値
(返り値)があり,returnに
達すると関数は終了
int add(int a, int b){
…
処理;
…
return a + b;
}
戻り値の型 関数名 引数
戻り値
関数[復習]
? コンパイラはソースコードを上か
ら解釈するので,予め「こういっ
た関数を使う」と宣言をしないと,
いざ関数を使うときにコンパイル
エラーが発生
? ideoneでは問題なく実行できるが,こ
れは特殊.gccや他のIDEではエラー
? 予め宣言しておくことを,プロト
タイプ宣言という.
? 3,4行目の部分
関数[復習]
? 実は,変数には主に2種類ある
? ローカル変数
? グローバル変数
? ローカル変数は,関数の内部
で宣言,定義される変数
? 宣言した関数内でしか参照できな
い
? 先ほど紹介したadd関数の変数a,b
も,今までmain関数内で定義し
た変数もすべてローカル変数
? 関数が終了すると,メモリが消滅
するので値が保存されない
? 変数は定義しないと使えない
ので,関数の最初で通常定義
する
関数[復習]
? グローバル変数は,関数の{}の
ブロックの外側で定義される
変数
? いろんな関数から参照できる
? プログラムが終了するまでメモリ
が消滅しないので,値が保存され
る
? プログラム全体で,普遍的な変数
を表現するのに便利
? どこからでも参照できるとい
うことは,どこからでも変え
ることができてしまうので,
むやみに利用すべきではない.
演習
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型というのがある
演習
1.
演習
2.
104743
配列再び
? 前回,前々回で少しだけ登場している配列
? 「データを入れる箱」変数を1度にたくさん宣
言する方法として,配列がある
? 変数を100個も一々宣言するのは大変
? int型で名前がdata,要素数が20の配列を宣言
するには以下のようにする
int data[20];
型 配列名 要素数
配列再び
配列再び
? int data[20];と宣言した時,data[k]と書くこと
でk番目の要素にアクセスできる.
? 配列は0番目から始まる
? そして(要素数-1)番目までアクセスできる
? 1番目からではない
? data[20]だとdata[0] ~ data[19]にアクセスできる
? data[20]にはアクセスできない(?)
? 配列の要素数は,コンパイル時に決まっている
定数でしか指定できない.
? ユーザーが入力した値を[]内に入れて宣言することができ
ない
? const int としても変数として扱われるのでダメ(コンパイ
ラによってはできる)
配列再び
? 配列にも初期化する方法があり、
int hoge[] = {2,4,6};
? とすると、値が初期化された要素数3の配列が
できる
? この例はint hoge[3];として、hoge[0] = 2;hoge[1] = 4;
hoge[2] = 6;としたのと同じ
? []内に要素数を書かなくても良い
? 宣言時にしか初期化できない
配列再び
? 実際に実行して
みよう
? これは有名な…?
配列再び
? 実行結果
文字列と配列[応用]
? 右のコードは1番はじめに登
場したHello World
? そもそも”Hello World?n”
ってなに?
? 文字(char)ではなく文字列
? C言語にはStringという文字
列の型は存在しない(他の言
語にはある)
? 文字列は文字の配列、つまり
char型の配列
? 文字列はchar型の配列なので
、右のように変数helloに代入
できる
文字列と配列[応用]
? 文字列 = 文字の配列なので、下のように書き換
えることもできる
? hello[0] = ‘H’ ,hello[1] = ‘e’といった具合
? 一番右の’?0’は、ヌル文字と呼ばれ、文字列の終
端を表す記号
? このヌル文字を使って、文字列の終端を検知する場合が多い
文字列と配列[応用]
? printf関数に渡していた引数はchar型の配列
? 実は、’a’,’b’といった文字はC言語内部では数字と
対応付けされている
? ASCII(アスキー)コードという規格が存在する
? これにより、下の2つのコードは同義
? 実はb = ’a’ + 1みたいなのもできる.
多重配列[応用]
? 配列のなかに配列を作るこ
ともできる
? 多重配列
? 多重配列を用いることによ
り、n次元に広がるデータを
扱える
? 例えば、行列、将棋の盤面
? 定義は、
int matrix[3][3];
? のように書く
型名 配列名 要素数
配列[演習]
1. int型で要素数が100の配列を宣言し,それぞれの要素に
対し,インデックスが奇数ならば0,偶数ならば1を代入
し,出力せよ.
? hoge[0] = 1;
? hoge[1] = 0;
2. 好きな型で好きな要素数の配列を好きな数で初期化し,
(型:int,要素数:3ならint a[] = {2,4,6};)インデックスが大き
い方から出力する.(上だと6,4,2と出力)
? for文を上手に利用する
? いつもはi++でインデックスが小さい方からだが…
? わからなかったら「C言語 hoge」とググれば,大体答えが
載っている
配列[演習]
1.
配列[演習]
2.
おまけ
? 今まではprintf関数で出力ばっかりしてきた
? 入力はないの?ーもちろんある
? 入出力関数を使用するためにstdio.hというヘッ
ダファイルをincludeする必要があった
? ヘッダファイルとは,特定の機能を持った関数を使いやすい
ようにファイル分割したもの(?)
? ↑うまく説明できてないかもしれない
? 入出力関数はたくさんあるので,代表的なもの
だけ紹介する
おまけ
? scanf関数
? 標準入力(キーボード)からの入力を変数へ読み
込む機能をもつ
? printf()の入力版?
? &については今は説明省略
? これはideoneで説明するのが難しい
おまけ
? fopen関数
? ファイルからデータを読み出す準備をする関数
? 読み取りモード,書き込みモードなど様々なモー
ドを設定できる
? ファイルを使い終わったらfclose()でクローズする
? ファイル操作についてはこれ以上詳しく説明しな
い
ビット演算(の前に)
? C言語ではなく,一般的な話
? bit(ビット)とbyte(バイト)について
? bit(ビット)とは0と1によるデータの単位のこと
? 1bitで0と1の2種類のデータが表現できる
? binary digitの略らしい
? 1byteは8bitであるのが一般的
? 1byteで2^8=256種類のデータを表現できる
? 1KB = 1024B(byte)
? 基本的にコンピュータの内部では,データは2進
数,つまりbit単位で扱われる
? 001010111101011010010001110…
ビット演算(の前に)
? しかし,0と1を羅列して2進数を表現するのは長
ったらしい
? 16進数という表現がある
? 0-9,A(10),B,C,D,E,F(15)の数で表現
? 例をいくつか
– 3A = 3 * 16 + 10 = 58
– FF = 15 * 16 + 15 = 255
? 2進数と16進数との関係
– 58 = 0011 1010 (2)
3 A
00000000 0
00000001 1
00000010 2
00000011 3
…
11111110 126
11111111 127
ビット演算(の前に)
? C言語では,先頭に0xをつける
ことでその数が16進数である
ことを示す
– 8進数の場合先頭に0をつけ
る
– (コンパイラによっては)先
頭に0bをつけることで2進
数を示せる
? 右のプログラムは,変数
hoge,piyoにそれぞれ16進数で
3A,FFを代入している
ビット演算(の前に)
? 変数の値に対し,2進数(0と1)を表すビット単位
でデータ操作を行うことをビット演算と呼ぶ
? n桁目のビットを1にする
? すべてのビットを左に1つずらす
? ビット演算は,特にマイコンを扱うにあたって欠
かせないものなので,今のうちに触れておく
? 欠かせない理由は後ほど
ビット演算
? 右のプログラムを実行し
てみよう
ビット演算
? unsigned char型は0~255ま
での値を格納できる
– 前回説明した
– 16進数だと0x00~0xFFまで
– char型は-128~127
? ビット演算子には,次のよう
なものがある
– 論理演算子(&&,||,!)とは違う
ビット演算子 意味
& AND
| OR
~ NOT
^ XOR
<< , >> ビットシフト
!aと~aはまったく違う
ビット演算
? AND演算子(&)は各桁のビッ
トに対して次の演算を行う
– &&と間違えないように
? 0 & 0 = 0
? 0 & 1 = 0
? 1 & 0 = 0
? 1 & 1 = 1
ビット演算
? OR演算子( | )は各桁のビット
に対して次の演算を行う
– ||と間違えないように
? 0 | 0 = 0
? 0 | 1 = 1
? 1 | 0 = 1
? 1 | 1 = 1
ビット演算
? NOT演算子( ~ )は各桁のビッ
トに対して次の演算を行う
– !と間違えないように
? ~0 = 1
? ~1 = 0
? ビットの反転
ビット演算
? XOR演算子(^)は各桁のビッ
トに対して次の演算を行う
– 累乗ではない
– 排他的論理和といわれる
? 0 ^ 0 = 0
? 0 ^ 1 = 1
? 1 ^ 0 = 1
? 1 ^ 1 = 0
ビット演算
? ビットシフト演算子(<<,>>)
は全体のビットを左/右に指
定回数分だけずらす
– 左ビットシフトの場合,ずらし
た後の空白は0が入る
– 右ビットシフトの場合,ずらし
た後の空白は処理系によって変
わる
? 1010010110100
(左へ1ビットシフト)
? 0100101101000
ビット演算
? printfで%xを用いると,変数の値
を16進数で表示できる
– %dは変数の値を10進数で表示するもの
だった
? 結果が次のようになることを確認
しよう
? 10ではない.0x10(=10進数だと
16)
ビット演算
? これらの演算子は, +=,-=の演算
子のように,省略して書くことが
できる
unsigned char a;
a = 0x2F;
a &= 0x3c;
a |= 0xC0;
…
a &= 0x3C;
a = a & 0x3C;
ビット演算[演習]
1. 次の計算を行うとどうなるか,16進数で値を求
めよ.ただし,値は0x00~0xFF(unsigned char)
とする.自分で変数を作って表示しよう.
1. 0x13 & 0x34;
2. ~0x1D;
3. 0xE2 << 2;
2. ある数に関して,特定の位置のビットだけ1に
変えるためにはどのような演算を行えばよいか
.同様に,特定の位置のビットだけを0に変え
るためにはどのような演算を行えばよいか考え
よう.
(例) 100101 → 101101
おまけ
? 先ほどprintf()内で%xを用い
て変数を16進数表示した
– %dは変数を10進で表示するもの
だった
– このような表示形式を指定する
ものをフォーマット指定子とい
う
– 代表例は右に掲載
? 他にも,小数点の桁数を指定
する方法や左詰/右詰,0埋め
など色々なことをprintf内で
指定できる
– 使い方はググって
指
定
子
対応する型 説明
%c char 1文字を出力
%s char *
char []
文字列を出力
%d int,short 整数を10進数
で出力
%u unsigned int
unsigned short
符号なし整数
を10進で出力
%o (整数値を扱え
る型)
整数を8進数で
出力
%x (整数値を扱え
る型)
整数を16進数
で出力
%f float 実数を出力
%lf double 倍精度実数を
出力
おまけ
? 「!」は論理演算子で否定(NOT)を表す.
– 「!a」の場合,aが偽なら真を,真なら偽を返す
? 「~」はビット演算子で反転を表す.
– 「~a」でa = 0xF0(11110000)の場合,
0x0F(00001111)
a if(a) if(~a) if(!a)
0 else文 if文 if文
1 if文 if文 else文
123 if文 if文 else文
-1 if文 else文 else文
対応
おまけ[応用]
? 先ほどの表でa = -1のときの
~aは0だった
– 0をビットで表すと
00000…00000
– だとすると-1は
11111…11111???
– そもそも負の数を2進数でどう
表すの?
? unsignedなどの指定がない場
合は,2進数の最上位ビット
(1番左)で正負を判断している
– 詳しくは2の補数でググろう
char binary
+127 01111111
+126 01111110
…
+2 00000010
+1 00000001
0 00000000
-1 11111111
-2 11111110
…
-127 10000001
-128 10000000
おまけ[応用]
? 2の補数表現の利点は,減算
を加算で行えること
– たとえば,1-1をしたい
– 1-1 = 1 + (-1)
– すると,1 00000000となるが,char
型は8ビットなので最上位の1は捨て
られる
– よって答えは00000000となる
? 右ビットシフト演算子(>>)をした
場合の空白に何が入るかは処理系
依存.
– 一般的には符号あり=>最上位ビット
,符号なし=>0が埋められる
– 処理系によってはいきなり負の数が正
になったり?
char binary
+127 01111111
+126 01111110
…
+2 00000010
+1 00000001
0 00000000
-1 11111111
-2 11111110
…
-127 10000001
-128 10000000
プリプロセッサについてちょっと
? C言語によるプログラミング(GCCの場合)
1. ソースコードの作成
2. コンパイル
? ソースコード(プログラミング言語)を機械語に変換すること
? 機械語に変換するツールをコンパイラという
3. 実行ファイルが生成される
4. 実行!!
実行結果
プリプロセッサについてちょっと
? C言語によるプログラミング(GCCの場合)
1. ソースコードの作成
2. プリプロセス
3. コンパイル
? ソースコード(プログラミング言語)を機械語に変換すること
? 機械語に変換するツールをコンパイラという
4. 実行ファイルが生成される
5. 実行!!
実行結果
プリプロセッサについてちょっと
? コンパイルされる前に,ソースコードに対して
行われる処理をプリプロセスという.そして,
プリプロセスをするものをプリプロセッサとい
う
– コンパイルとコンパイラの関係
? プリプロセッサは,#includeしたファイルを読み込んだ
り,コメントを消したりしてくれる.
– コメントは実際の動作には関係ない
– コメントは機械語に変換するのにはいらない
プリプロセッサについてちょっと
? 実行して確かめてみる
プリプロセッサについてちょっと
? 毎回かいていた
#include<~>
は<>内に指定したファイル
を読み込むという意味があ
る
– 今回はstdio.h(printfなどの
入出力の宣言が入っている)
を読み込んでいる
– stdio.hのようなファイルを
ヘッダファイルという
プリプロセッサについてちょっと
? #define (A) (B)
? と書くことで,(A)がすべ
て(B)に置き換わる
– マクロという
– 右の例だとNUMはプリプロ
セッサによって10になる
– (B)に当たる部分は省略可
– #defineを用いると簡単な関
数のようなものが(作ろうと
思えば)作れる
プリプロセッサについてちょっと
#ifdef (A)
…
#endif
? で挟まれた部分のコード
は,(A)が#defineによっ
て宣言されていれば読み
込まれるが,宣言されて
いないと読み込まれない
? 逆に#ifndefにすると宣言
しないと読み込まれる
プリプロセッサについてちょっと[注意]
? #defineは,文字列をその
まま置き換える作業をし
ているので,注意しない
とバグを引き起こしやす
い
– そのため#defineは多用しな
いほうがよい
– 定数を表現したいならば,
const を用いればよい
マイコンプログラミング
? 今までC言語の文法について色々と学んできたが,
具体的にマイコンにどう指示を与えるのかにつ
いてはあまり触れなかった
? ほんの少しだけどのようにしてマイコンに対し
てプログラムをするのかを考える
– 详しい内容はマイコン讲习会にて
マイコンプログラミング
マイコン
?マイコンの働き
外部スイッチ
ラインセンサー
AD変換
モーター駆動
モーター
ドライバ
LED点灯ピンの電位
変化
デジタル値
PWM出力
ピンの電位
変化
マイコンプログラミング
? 基本的に,マイコンには様々な種類の「レジス
タ」と呼ばれるものがあり,これらを操作する
ことで様々な設定を行う
– 下の表はAVRの入出力ポートB(Atmelデータシートより)
– わからない?俺もわからない
マイコンプログラミング
? このレジスタを操作する際に,ビット演算の知識をとて
も使う
– マイコン講習会ではビット演算を駆使するらしい
– 例えば,PORTBに0x2Aを代入すると…
– 0x2A = 00101010なのでPORTB1,PORTB3,PORTB5に相当するピ
ンが出力(1)になる
0 0 1 0 1 0 1 0
マイコンプログラミング
? 出力が1となったピンは,電圧がオン(5V) にな
る
– 下の例はマイコン础迟迟颈苍测2313
マイコンプログラミング
? 特定のピンだけ(例えばPORTB2)を1に変えるに
は,
? PORTB |= ( 1 << 2);
? と書けば良い
? 特定のピンだけ(例えばPORTB2)を0に変えるに
は
? PORTB &= ~(1 << 2);
? と書けば良い
? どちらもビット演算で登場した演算子
マイコンプログラミング
? AVRでLチカをするコード
? 何やってるかはわからなくて
よい
– マイコン講習会で丁寧に教えて
くれるはず
– ビット演算めっちゃしてるな~
くらいに思っておけば良い
予告
? 今までの復習
? 構造体?共用体
? ポインタ
本日は以上です
ありがとうございました

More Related Content

颁言语讲习会3