bp07

University of Electro-Communications
Human Interface section
基礎プログラミングおよび演習
第7回
University of Electro-Communications
Human Interface section
関数と変数のスコープ
復習: ブロックと変数の有効範囲(スコープ)
 変数はブロック({から}の間)の中だけで有効です。
int main(){
int a;
{
int x;
x = 2*3;
printf(”%d\n”, x);
}
printf(”%d\n”, x);
return 0;
}
a
xの有効範囲
(スコープ
といいます)
aの有効範囲
(スコープ
といいます)
x
コンパイルエラー:
`x' undeclared (first use in this function)
 変数の有効範囲をスコープといいます。
関数とブロックと変数のスコープ
#include <stdio.h>
各変数のスコープ
// 2乗を計算する。
double square(double d){
squareのブロック d
return d*d;
double d が有効
}
// n^2個の*を表示。 n^2を返す。
printSqのブロック
int printSq(int n){
n
int nn = square(n);
int n, int nn, int count が有効
int count = nn;
while(count){
whileのブロック
printf(”*”);
int n, int nn, int count に加えて、
int c = count-1;
int c が有効
count = c;
}
printf(”\n”);
return nn;
}
int main(){
printSq(5);
mainのブロック
return 0;
}
nn
count
c
グローバル変数とスコープ
 グローバル変数⇒関数の外に書く変数
msの
スコープ
pointの
スコープ
#include ”curses_subset.h”
どのブロックにも入ってない
#include <math.h>
⇒どのブロックでも使える
int point=0;
int sleep_by_point(){
sleep_by_point のブロック
int ms = 1000 / log(point);
2つのmsは
sleep_ms (ms);
まったく別の変数
return sleep;
}
2つのpointは、
int main(){
main のブロック
まったく
int ms;
while(point){
while のブロック 別の変数。
int point;
sleep_by_point();
}
ここの int point;のせいで、
if (当たり判定){
if のブロック このブロックでは、3行目の
point = point – 100;
int point=0;のpointが
}
見えなくなる。
}
グローバル変数とスコープ
#include ”curses_subset.h”
#include <math.h>
int point=0;
point
int sleep_by_point(){
ms
int ms = 1000 / log(point);
sleep_ms (ms);
return sleep;
}
int main(){
int ms;
while(point){
int point;
sleep_by_point();
}
if (当たり判定){
point = point – 100;
}
}
ms
point
University of Electro-Communications
Human Interface section
雑多な文法
代入と計算のまとめ書き演算子
 なくても困らない演算子 だが、他人の書いたソースを読むために必要
 n = n – 1; のような計算は、繰り返しなどで良く出てくる。
⇒便利な代入演算子があります。
n += 2; // n=n+2;と同じ n -= 2; // n=n-2;と同じ
n *= 2; // n=n*2;と同じ
n /= 2; // n=n/2;と同じ
n ++; // n=n+1;と同じ
n --; // n=n-1;と同じ
++n; // n=n+1;と同じ
--n;
// n=n-1;と同じ
 n++と ++n は非常に微妙に違います。
int a=1; int n;
n = (a++)*10;
// n=10 先に計算してさいごに ++
n = (++a)*10;
// n=20 先に++して後で計算
while 以外の繰り返し
 なくても困らないが、forくらいは便利かも
for(式1; 式2; 式3)
文かブロック
1. 式1を実行
2. 式2の値が0なら文
かブロックを飛ばし
て次へ
3. 文かブロックを実行
4. 式3を実行
5. 2.から繰り返し
for(int c=0; c<3; c++){
printf(”*”);
}
***
do 文かブロック
while(式);
1. 文かブロックを実行
2. 式の値が0なら次へ
そうでなければ1へ
do{
int k = getchar();
}while(k!=100);
break;
continue;
break文が実行される
とその時点でループ
を抜ける
continue文が実行され
ると、以降を実行せず、
ループを続ける。
while(1){
int k = getchar();
if (k==100) break;
if (k==101) continue;
printf(”key is not 101\n”);
};
printf(”key is 100\n”);
switch 文
switch(式){
int a = 1;
case 数値1:
switch(a){
文かブロック1case 1: printf(”aは1です。\n”);
1;
case 2: printf(”aは1か2です。\n”);
文かブロック1default: printf(”最後です。 \n");
2;
}
:
aは1です。
case 数値2:
aは1か2です。
文かブロック2最後です。
1;
case 1 にジャンプした場合、その後の、
文かブロック2case 2 の文も default の文も実行してしまう。
2;
⇒ ので、普通は break; と組み合わせて使う。
:
default:
文かブロックd1. 式の値を求める
1;
2. 数値n と値が等しければ、
文かブロックdcase
数値n: の文にジャンプ
2;
3. 等しい数値がなければ defaultの
:
文にジャンプ
switch 文 / goto 文
int a = 1;
switch(a){
case 1: printf(”aは1\n”);
break;
case 2: printf(”aは2\n”);
break;
default: printf(”1,2ではない \n");
}
aは1です。
case 1 にジャンプした場合、
その後のbreak;を実行すると
switch 文を抜ける。
if 文; else if 文; … の方が便利だし分かり
やすい。
while(1){
ラベル: 文;
}
goto ラベル;
goto ラベル; を実行すると、
ラベル:文; の文にジャンプする。
同じ関数の中なら、どこにでも
ジャンプできる。
while(式){
while(式){
while(式){
if (式) goto next;
}
}
}
next: printf(”ループを抜けました\n”);
プログラムの流れが分かりにくくなる
ので多用するとよくない。上の例の
ようなときぐらいにしておくのが良い。
if else の連鎖
 switch文を使わなくても if else で同じことがかけます。
 どっちでもよいので、プログラマはその都度カッコよいと
思うほうを使っています。
int a = 1;
switch(a){
case 1: printf(”aは1\n”);
break;
case 2: printf(”aは2\n”);
break;
default: printf(”1,2ではない \n");
}
int a = 1;
if (a==1){
printf(”aは1\n”);
}else if (a==2){
printf(”aは2\n”);
}else{
printf(” 1,2ではない \n");
}
課題11 ターミナルで動くゲームを作る
 課題のページにターミナルで動くシューティングゲー
ム? の雛形があります.
 まずはex11sampleプロジェクトを作って,
コンパイルして動かしてみてください.
 スクロールの向きを変えてください.
 ついでに
 構造体と関数を使って書いてください.
 使用するキーと機能を増やしてください.
(例えば倍速移動とか)
 どんなゲームにしたのか,説明を必ず書いてください.
 説明がないと採点時に見落としてしまうので.
課題11:資料
curses_subset.h は基礎プロの課題のために長谷川が作った独自の
ヘッダファイルです.unixのcursesというカーソルを動かすライブラ
リの機能の一部+αを持ちます.
 curses_subset.h が提供する関数
initscr()
endwin()
cbreak()
nocbreak()
echo()
noecho()
ターミナルの現在のモードを記録。
ターミナルの状態を元に戻す。
編集なしモード。getchar()が1文字ごとにすぐに返ってくる。
編集ありモード。[ENTER]まで、getchar()が返ってこない。
エコーあり。キー入力した文字を表示する。
エコーなし。キー入力した文字を表示しない。
kbhit()
待たずに読み出せるキー入力があれば 0 以外を返す。
clear()
move(y,x)
画面クリア
カーソルを上から y 行左からx桁に移動する。
sleep_ms(t)
t ミリ秒プログラムを停止する。
文字コード
文字コード
実は、文字には番号がつけられています。
getchar() が返す整数はこの文字の番号です。
文字をシングルクォーテーション(’)で囲むと、文字
コード値のことになります。
printf()の文字列に%cを入れておくと、整数を文字
コードだと解釈したときの、文字が表示されます。
int main(){
int charCode = ’A’;
// charCodeには、Aの文字コード 65が入る。
printf(”%d\n”, charCode); // 65と表示される。
printf(”%c\n”, charCode); // Aと表示される。
}
65
A
課題12:文字コード表を作る
 文字コードの表を作ってみてください。
 文字コードは(たぶん)0から255までの整数です。
 機種やOSや言語モードによります。
 表示できない文字や改行してしまう文字もあります。
 http://ja.wikipedia.org/wiki/ASCII に英語文字コード表があります。
 文字コードの整数と文字を表示させてください。
 8文字ごとに改行を入れると見やすいです。
 桁数をそろえて表示するには、printfの%dの代わりに
%3d などを使います。
詳しくは BasicP04.pdf を参照
表示例の抜粋:
32
33 !
40 ( 41 )
48 0 49 1
56 8 57 9
34 "
42 *
50 2
58 :
35 #
43 +
51 3
59 ;
36 $
44 ,
52 4
60 <
37 %
45 53 5
61 =
38 &
46 .
54 6
62 >
39 '
47 /
55 7
63 ?