|
|
参考書として,98年度の大阪市立大学インターネット講座「UNIXで学ぶC言語」 をあげておく.
main()
{
int i;
for (i = 0 ; i < 10 ; i = i + 1) {
printf("count %d\n", i);
}
}
|
Cのプログラムは,main関数から実行される.とりあえず,最初はmain関数しか使わない.
- 正確に書かないと,コンパイルできない
- 思ったように動くのではなく,書いてある通りに動く :-)
|
疑似言語 |
C言語 |
| 変数 |
型がない |
型がある.使う前に宣言が必要 |
| 配列 |
型がない |
型がある.使う前に要素の数を決めておく必要がある.宣言が必要 |
| 定数 |
型がない |
型がある |
| 変数への代入 |
← |
= (イコール1つ) |
| 演算 |
+, -, *, /, % 等 |
整数型で演算すると,結果は切り捨てられる |
| 比較 |
= |
== (イコール2つ) |
| 比較 |
≠ |
!= |
| 論理演算 |
A かつ B |
A && B |
| 論理演算 |
A または B |
A || B (縦棒2つ) |
| 関数 |
input() |
scanf(...) 等 |
| 関数 |
output(...) |
printf(...) 等 |
| 制御構造 |
if, while |
同じ |
| 制御構造 |
for (i ← A ... B) |
for (i = A ; i <= B ; i++) |
| 文末 |
特になし |
文の終わりには,; (セミコロン)が必要 |
|
- /* 〜 */ で囲まれた部分は,コメントとして扱われる.
- コンパイラは,コメントを無視する.
- "文字列"の中以外では,どこにでも書ける.
- 積極的にコメントを書いて,プログラムを読みやすくするべき.
- 教室の環境では,コメントとして日本語も書ける.
/* This is sample program */
main()
{
/* main関数の中身 */
}
|
変数は宣言が必要.
基本的な型
| 整数型 |
int |
4バイト |
-2,147,483,648〜2,147,483,647 |
| long |
4バイト |
-2,147,483,648〜2,147,483,647 |
| short |
2バイト |
-32,768〜32,767 |
| char |
1バイト |
-128〜127 |
| 実数型 |
float |
4バイト |
-3.40282*1038 〜 3.40282*1038 |
| double |
8バイト |
省略(倍精度) |
(注意:実数といっても,無限の精度があるわけではない)
|
- 変数の宣言は,関数の最初で行う.(本当は { の後ならどこでも良い)
- 変数の方は,変数がとりうる値の種類に応じて選ぶ.基本的に,今のところは int と float がメイン
- 変数の宣言は,型名の後に変数名を書く.
- 変数名は,アルファベットと数字, _ (アンダースコア)が使える.ただし,先頭に数字は使えない.できるだけ分かりやすい変数名をつけること.
- 幾つでも続けて宣言できる.
main()
{
int i; /* int 型の変数 i の宣言 */
int j; /* int 型の変数 j の宣言 */
long x, y, z; /* long 型の変数3つ x, y, z の宣言 */
....
}
|
C言語では,全ての入力(キーボードやファイルから)や出力(画面やファイルへ)を,関数を用いて行う.
printf関数は,画面に出力するための関数で,疑似言語の output にほぼ対応する.
/* output("i = ", i, "j = ", j) に対応 */
printf("i = %d j = %d\n", i, j);
|
- 文字列は "ダブルクオート" で囲む.
- C言語では,文字列中の \n は,改行を意味する.
- 最初の引数 "count %d\n" の部分が表示される.
- %d は,その次の引数をここに埋め込んで表示するという意味.
よく使われる特殊文字.C言語では,文字列中の \ は特別扱いされる.
| \n |
改行 |
| \t |
タブ |
| \" |
ダブルクオート(文字列中に"を入れるために使う) |
| \\ |
バックスラッシュ(文字列中に\を入れるために使う) |
(注意) \ はもともとバックスラッシュであるが,日本の計算機では円記号で表示される場合がある.
|
printf での書式指定文字(当面使うもののみ)
| %d |
10進数で表示 |
| %f |
実数として表示 |
| %3d |
3桁の10進数 |
| %6.2f |
6桁の実数(小数点以下2桁) |
|
|
printf("count %d %d\n", i, i * 10)
|
|
i, j の二つの整数型変数に,適当な値を代入し,それらの和,差,積,商を表示するプログラムを書け.
また,i, j を実数に変更して実行してみよ.
|
scanf関数は,キーボードから入力を行う関数,疑似言語の input にほぼ対応する.
int i;
float f;
double d;
/* i ← input() に対応 */
scanf("%d", &i) /* i に整数値を入力する */
/* f ← input() に対応 */
scanf("%f", &f) /* f に実数値を入力する */
/* d ← input() に対応 */
scanf("%lf", &d) /* d に実数値を入力する */
|
- &を忘れないように.& の意味は今は気にしない.
- printf と異なり,書式指定文字列(%?)以外は書かない.
main()
{
int i;
print("Input an integer: ");
scanf("%d", &i);
if (i > 100) {
printf("Too large\n");
} else if (i > 50) {
printf("Large\n");
} else {
printf("Small\n");
}
printf("End\n");
}
|
キーボードから2つの整数を入力し,それらの和,差,積,商を表示するプログラムを書け.
また,i, j を実数に変更して実行してみよ.
|
- 条件の回りの括弧 () は必須
- 文の本体の中括弧 {} も必須(本当は,つけなくて良い場合もあるが..)
if (a == 0) {
printf("a は 0 です\n");
} else {
printf("a は 0 ではありません\n");
}
a = 10;
while (a > 0) {
printf("a = %d\n", a);
a = a - 1;
}
|
C言語の for 文は,いろいろと複雑なことができるが,今は
/* for (i ← 0 ... 20) と同じ意味 */
for (i = 0 ; i <= 20 ; i++) {
...
}
|
の形だけ使う.間の ; (セミコロン) を忘れないように.
疑似言語の「ループからの脱出」は break 文になる.
for (i = 0 ; i <= 20 ; i++) {
if (i == 10) {
break; /* for 文を抜ける(XXX に飛ぶ) */
}
}
/* XXX */
|
|
2つの数を入力させ,それらの和,差,積,商を出力せよ.
2数として0,0が入力されるまで,この処理を続けよ.
|
で宣言する.
- int ryokin[10]; だと ryokin[0] 〜 ryokin[9]までの10個のint型の変数ができる.
- 要素数には変数は使えない.定数のみ.
- 変数と同様,配列の要素の初期値は不定.
- C言語では,添字(インデックス)の範囲のチェックは行われない.
int ryokin[10]; に対して,ryokin[100] = 0; としてもコンパイラは文句をいわない.
以下のプログラムを,実行する前にどのような結果が出るかを考えてから,実行してみよ.
main()
{
int a;
int ryokin[10];
a = 1234;
ryokin[10] = 2345; /* ryokin[10]は配列の範囲外! */
printf("a = %d\n", a);
}
|
数列
- A[1] = 1
- A[k] = 2 * A[k-1] + 3
の第100項を求めよ.
0 〜 231-1 までの間で乱数を発生させる関数.この関数を呼ぶ度に,乱数を返す.(a = random();)
ある範囲 (例えば0〜5) の乱数が欲しいときは,6 で割った余りを使えば良い.randomが返す値は,実際は乱数のように見える数列.以下のプログラムを何回か実行してみよ.
main()
{
int i;
for (i = 1 ; i < 10 ; i++) {
printf("%d\n", random());
}
}
|
乱数の「種」を初期化するために,srandom関数がある.srandomの引数が,乱数の種になる.プログラムの実行の度に,なるべく異なった値を入れる.簡単に済ますには,time関数を使う.
time 関数は,1970年1月1日からの秒数を返す関数.time(0) の形で使うこと.int i; と for の間に,srandom(time(0)); を追加してみよ.
- 0から9までの整数の乱数を100個発生させ,それぞれの出現頻度を表示せよ.乱数を1000個,10000個にしたときはどうなるか?
main()
{
int i;
int a;
int hindo[10];
/*・配列 hindo を御破算にする */
for (i = 0 ; i <= 9 ; i++) {
hindo[i] = 0;
}
/*・以下の処理を100回繰り返す(for) */
for (i = 1 ; i <= 100 ; i++) {
/* 0-9までの乱数を発生させる(aとする) */
a = random() % 10;
/* 配列 hindo を a に応じて +1 する
(つまり,hindo[a] = hindo[a] + 1) */
hindo[a] = hindo[a] + 1;
}
/*・hindoの中身を出力する */
for (i = 0 ; i <= 9 ; i++) {
printf("%d の頻度 : %d\n", i, hindo[i]);
}
}
|
「!(a == 0)」と書くと,「a == 0 でない」という意味になる(つまり,a != 0 と同じ).
主に,if文やwhile文の条件で使う.
例: !(a == 0 && b == 0) (これは,論理的に a != 0 || b != 0 と同じ)
一般に,
- !(A && B) ←→ !A || !B
- !(A || B) ←→ !A && !B
が成り立つ.
疑似言語で無限にループするために while (永遠に) と書いたが,C言語では,while (1) あるいはfor (;;) と書けば良い.
main()
{
while (1) {
...
}
/* こっちでも良い */
for (;;) {
...
}
}
|
#define XXX YYY と書くと,以後の XXX が YYY に置き換えられてからコンパイルされる.
- ある数値(例えば10)が,プログラム中で複数の個所で使われるような場合,
例えば #define NUM 10 と書いておきと,後から変更するときに #define
の行だけを変更すれば良いので便利.
-
プログラム中に突然数値が出てくると,他人には意味が分かりにくい.
#define 分かりやすい名前 数値
としておき,「分かりやすい名前」を使えば,他人から読みやすいプログラムになる(重要).
-
#define にはセミコロン(;)はつけない.
-
#define は通常行頭から書く.
-
XXX の部分が"文字列の中"に現れても,置換されない.
-
XXX を「マクロ」と呼ぶ.#define することを,「マクロを定義する」と呼ぶ.
#define NUM_OF_RANDOM 10
main()
{
int i;
for (i = 1 ; i < NUM_OF_RANDOM ; i++) {
printf("%d\n", random());
}
printf("全部で %d 個の乱数を発生しました\n", NUM_OF_RANDOM);
}
|
コンピュータで扱うそれぞれの文字には,文字コードが割り当てられている.多くのコンピュータでは ASCIIコードと呼ばれる文字コードを使っている.
コンピュータは,内部的に文字コードという数値を使うことで文字を扱っている.
ASCIIコード表
| 0 NUL | 1 SOH | 2 STX | 3 ETX | 4 EOT | 5 ENQ | 6 ACK | 7 BEL |
| 8 BS | 9 HT(タブ) | 10 NL(改行) | 11 VT | 12 NP | 13 CR | 14 SO | 15 SI |
| 16 DLE | 17 DC1 | 18 DC2 | 19 DC3 | 20 DC4 | 21 NAK | 22 SYN | 23 ETB |
| 24 CAN | 25 EM | 26 SUB | 27 ESC | 28 FS | 29 GS | 30 RS | 31 US |
| 32 SP | 33 ! | 34 " | 35 # | 36 $ | 37 % | 38 & | 39 ' |
| 40 ( | 41 ) | 42 * | 43 + | 44 , | 45 - | 46 . | 47 / |
| 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 ? |
| 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 _ |
| 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 ~ | 127 DEL |
|
改行(NL, New Line)等にもコード(10)が割り当てられている.
日本語の文字コードには日本語EUCコード,JIS漢字コード,シフトJISコード等が使われている.
C言語で文字を扱うためには char 型の変数を使うことが多い.char 型は,ASCII文字1文字を入れておくことができるサイズ.日本語の文字は入らない.
C言語では,'シングルクオート' で文字を囲むと,その文字のコードを表す.
char c; /* 変数の宣言 */
c = 65; /* A という文字を記憶 */
c = 'A'; /* シングルクオートして書いても良い(こちらのほうがベター) */
c = '\n'; /* 改行のコード10 */
c = 'AB'; /* これは許されない */
c = 'あ'; /* 日本語もダメ */
|
printf で文字コードを引数に与えて文字として表示するためには,%c を使う.
char c; /* 変数の宣言 */
c = 'A';
printf("a の文字は %c, 文字コードだと %d\n", c, c);
|
多くのプログラムはキーボードから入力して画面に出力するようにできている.
UNIXでは,プログラムに変更を加えなくても入力装置(通常はキーボード)や出力装置(通常は画面)を簡単に切り替えることができる.
% prog < file1 (キーボードの代わりに file1 から入力)
% prog > file2 (画面の代わりに file2 へ出力)
% prog < file1 > file2 (file1 から入力して file2 へ出力)
|
このため,プログラムの入力装置(普通はキーボード)を標準入力,出力装置(普通は画面)を標準出力と呼んでいる.多くのプログラムは,標準入力から入力を受取り,標準出力へ出力を行う.
例えばprintfは標準出力に書き出す関数.scanfは標準入力からフォーマットに従って入力を受け付ける関数である.
標準入力から1文字入力するためにはgetchar関数を使う.入力した文字のコードが返り値になる.(ただしリターンキーを押さないと入力した文字がプログラムに渡されないことに注意).
int a; /* int 型の変数を使っていることに注意 */
a = getchar(); /* 1文字入力 */
|
- 標準入力には,「終わり」という概念がある.キーボードから「終わり」を入力するに
Control-D を入力する(UNIX の場合).
- 「終わり」になると,getchar 関数は EOF という値を返す.(実際は EOF はマクロで,-1
という値).EOF は End Of File の意味.
- getchar は -1 〜 255 の値を返す.-1 が char の範囲に入りきらないので,int
型の変数に代入している.
- Cのプログラムで,#include <stdio.h>と書くと,そこに stdio.h を取り込むという指示になる.stdio.h は UNIX では /usr/include/stdio.h にある.
- 〜.h のファイルをへッダファイルあるいはインクルードファイルと呼ぶ.
- stdio は STandard I/O (Input/Output) (標準入出力) という意味.C言語の標準的な入出力のための関数やマクロが宣言されている.
- EOF は stdio.h で定義(#define)されているマクロなので,#include <stdio.h> がないとコンパイルできない.
/*
* 標準入力から受け取った文字のコードを表示するプログラム
* 入力が「終わり」になるまで続ける
*/
#include <stdio.h> /* へッダファイルの取り込み */
main()
{
int code;
for (;;) { /* break 文が実行されるまで繰り返す */
code = getchar();
if (code == EOF) { /* 「終わり」になったらループから脱出 */
break;
}
printf("%c のコードは %d です\n", code, code);
}
}
|
/*
* 標準入力から受け取った文字から空白の数を数えるプログラム
* 入力が「終わり」になるまで続ける
*/
#include <stdio.h> /* へッダファイルの取り込み */
main()
{
int code;
int count = 0;
for (;;) { /* break 文が実行されるまで繰り返す */
code = getchar();
if (code == EOF) { /* 「終わり」になったらループから脱出 */
break;
}
if (code == ' ') { /* 空白を見つけたらカウンタを増やす */
count++;
}
}
printf("Number of blanks = %d\n", count);
}
|
標準入力から入力した文字のうち,スペース ' ' の数と行数を数えるプログラムを書け.
This is a pen(リターン)
That is a book(リターン)
(ここでControl-Dを入力)
スペースの数 = 6, 行数 = 2
|
行数を数えるには,改行('\n')の数を数えれば良い.
標準入力から入力した各行に行番号を付与するプログラムを書け.
This is a pen(リターン)
1: This is a pen
That is a book(リターン)
2: This is a book
(ここでControl-Dを入力)
|
|