C言語解説

1. プログラムってなに?

2. C言語の基本的な知識と用語

3. C言語文法の解説

4. グラフィック

1. プログラムってなに?

【 プログラムってなに? 】


◇プログラムとは何か
 ・コンピュータに対して, どのような手順で仕事をすべきかを, 書いたもの
 ・あなたのコンピュータが動いているのは, 誰かがプログラムを書いてくれたおかげ

◇プログラミング言語
 ・プログラムを記述するのに用いられる人工言語

  人 ========⇒ コンピュータ
    プログラミング言語

◇プログラミング言語の種類
 ・外国語にいろいろな種類があるように, プログラミング言語にも用途に応じて
  いろいろな種類がある
 ・この授業では「C言語」を勉強する
 ・C言語はUNIXの開発のために作られたプログラミング言語で, 広い範囲で使われて
  いる

【 プログラムはどう書くの? 】

◇コンピュータは融通がきかない
 ・順番にしたがって書かないといけません.
 ・細かく書かないといけません. だいたいではいけません.

◇コンピュータは我慢強い
 ・指示されたことを1万回でも100万回でも繰り返す.

◇コンピュータも(少しは)かんがえる
 ・条件にしたがって行うことを変えることができる
 ・条件はあらかじめ人間が教えてやらないといけない

【 簡単なプログラム 】

◇hello, world
 と印字するプログラムを書いてみよう.

◇プログラム
  #include <stdio.h>
  main()
  {
    printf("hello, world\n");
  }
◇説明
  ・#include <stdio.h> --------- 標準ライブラリを使うという決まり文句
  ・main() --------------------- プログラム本体の始まり
  ・{ ... } -------------------- プログラム本体がどこからどこまでかを囲む
 ・printf("hello, world\n"); -- "..."で囲まれた文字列をそのまま印字する
                 \n は次の行に進みなさいという意味. 改行.
 先頭の空白はプログラムを読みやすくするため
 空白, 改行は適当に入れてよい
 ただし、#include の行は途中で改行してはいけない

【コンパイル(compile)ってなに?】

◇プログラムを実行する(動かす)には, コンパイルという操作が必要
 ・実は, コンピュータはC言語を直接理解できない
 ・コンピュータが理解できるのは機械語(人間には理解できない)
 ・C言語を機械語に翻訳することが必要

◇プログラムを実行する手順
 1. プログラムの入ったファイルを用意する.
    ファイル名は hello.c のように '.c' で終わらないといけない.
    これをソースファイルという.
  2. 次のようにしてコンパイルする.
  > sgcc hello
    実行可能型ファイル hello.exe ができる.
 3. 次のようにして実行する.
  > hello.exe
      hello.c              hello.exe
 人 ==========⇒ コンピュータ ======⇒ プログラム
    プログラミング言語   コンパイル   機械語

【ライブラリ(library)って何?】

◇C言語そのものは必要最低限の機能しかない
 ・便利な部品(C言語では関数と呼ぶ)を集めたものがライブラリ
 ・printf は stdio(標準入出力)というライブラリに入っている関数
 ・他に数学用のライブラリ, 通信用のライブラリなどがある

◇#include <stdio.h> は何をするか
 ・stdio.h は stdio ライブラリを使うための準備ファイル
 ・#include <...> で自分のファイルを取り込むと printf などの関数が使える
  ようになる

◇SGLグラフィックス・ライブラリ
 ・情報処理1bc用に開発されたライブラリ(市販の参考書には載っていない)
 ・準備ファイルは sfcgl.h

【コンパイルできない!】

◇コンパイル・エラー
  #include <stdio.h>
  main()
  {
    printf("hello, world\n")     ← ここに';'を忘れていた!
  }

2. C言語の基本的な知識と用語

セミコロンの役目

【説明】 セミコロンは分の終端マークとなっています。そのためいくつ文が連続して書
いても、それぞれの文を識別することができます。ちなみにセミコロンだけを書くと空
文といわれるものになります。確かに文が一つあるけど何の効果もありません。

【用例】 

a = 100; b = 100; …… 同じ行に文が2つありますが、;で区切られているので文が2つ
あると識別できます。
for(i=0;i<1000; i++)
  ; 
 
……これが空文。1000回単なる繰り返しを行わせたいときに使います。

ひとつの文

 Cではforやifなどの制御文は後続する一つの文を制御(実行)することになってい
ます。このとき「ひとつの文」には次のようなバリエーションがあります。   

単純文
a = 10;

複合文
{ a = 10; b = 20; }

コンマ演算子で結合された文
a = 10, b = 20; 

【用例】 
for(i=0;i<1000; i++)
{
 printf("hello\n");
 printf("world!\n");
} 
 ……これは複合文の例です。for文はその後に書かれた1文しか実行できませんが、{ }
 を用いることで複数の文を制御することが出来るようになります。

バックスラッシュ問題

【説明】 Cではエスケープ文字列を表現するのにバックスラッシュを用います。たとえ
ば、改行文字(復改文字)は、

\n(バックスラッシュは半角文字)

ですが、バックスラッシュはJISキーボードには割り当てられていません。つまりキー
ボードによっては、バックスラッシュ文字を出力できないわけです。そのためJISキー
ボードの場合は、バックスラッシュの代わりに \ という文字を使っています。従って
改行文字は 

\n

を使います。

注釈(コメント)


【説明】 注釈は次のように範囲指定を行います。

/* コメントの開始
*/ コメントの終了

指定された部分(コメント)はコンパイルの際に無視されます。コメントはソースファ
イルの説明のために用います。一度 /* が出てきたら、行の切れ目に関係なく次に */ 
が出てくるまでコメントになります。/* 〜 */ の間にさらに/* 〜 */ があってはいけ
ません。

【用例】 
/* 情報処理1bc 課題 
79519578 山田英史 */

main()
{
 /* keioと出力 */
 printf("keio\n");
 /* printf("hello\n"); */
}

 ……ソースファイル(.c)にいろいろなコメントを加えられます。コメントは
複数行にまたがっていてもかまいません。またコメントはコンパイルの際に
無視されるので、左の例では hello は出力されません。

予約語

【説明】 予約語とはC言語側ですでに利用している名前で、これを変数名などに指定す
るとコンパイルエラーが出ます。

auto double int struct break else long switch case enum register typedef char 
extern return union const float short unsigned continue for signed void default
 goto sizeof volatile do if static while 

全角空白と半角空白の扱い


【説明】 全角の空白と半角の空白はまったく別物です。ソースファイルにこの全角空
白文字を入れると見かけ上は分かりにくいのですが、コンパイルをすると次のようなエ
ラーが出ます。
C:\Home>gcc test.c C:/cygnus/glut-cygwin/lib/sfcgl.o -o test -DWIN32 -D_WIN32 -
I C:/cygnus/glut-cygwin/include -LC:/cygnus/glut-cygwin/LIB -lglut32 -lglu32 -l
op engl32
test.c: In function `main':
test.c:3: parse error before character 0201
プログラムを見ても全角スペースを見つけにくいので、始めのうちは考えこむことにな
ります。

#include は何をするか

【説明】 stdio.h は stdio ライブラリを使うための準備ファイルです。 #include <..
.> で自分のファイルに取り込むと printf などの関数が使えるようになります。

#defineとは?

【説明】 defineは文字列の置き換えを行うものです。次のような書式になります。

#define 文字列1 文字列2

たとえば、次のように定義します。

#define SIZE 500

こうするとプログラム中の"SIZE"という文字はコンパイルの時に"500"という数値に置
き換わります。たとえば以下のように用います。

#define SIZE 500

int a;
a = SIZE + 50;

こうすると、aには550が入りますね。一般にdefineで定義される名前(上の例ではSIZE)
は普通の変数と区別するために大文字で書くのが慣例です。

3. C言語文法の解説

変数と代入演算子 - その1

【説明】 変数とは、値を保存しておく箱のようなもので与えられた数値を保 持します。変数は型を宣言してから用いなければなりません。型とはその変数 がどのような種類の値を持つかを区別する物です。int というのは整数の型と いう意味です。他にはchar (文字)、double(小数)などがあります。変数の宣 言の書式は以下のようになります。


変数の型 変数名;
ex) int i;

変数に値をセットするには"="を用います。"="を代入演算子といいます。"="記号の左
側に値がセットされる変数名、右側に入れる値を指定します。

変数名 = 値;

変数名は自由に決めることができますが、名前に用いることのできる文字は決まってい
ます。それは次の通りです。

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
1 2 3 4 5 6 7 8 9 _ (下線) 

・ 変数名は英文字または_(下線)で始まらなければならない。
・ 名前の長さは先頭から31文字まで識別される。
・ 予約語を使ってはいけないが、予約語を含む名前はよい。

【用例】 
main() {
  int i;        /* 整数を保持する変数 i を宣言する */
  int j;        /* 整数を保持する変数 j を宣言する */
  i = 3;        /* i という変数に3をセットする */
  j = i;        /* j という変数にi の持っている値を渡す。jには3が入ります */
} 

printf()関数 - その1

【説明】 printf 関数は引数の内容を出力してくれます。


【用例】 

printf("hello\n"); …… helloと出力します。\nは改行を意味します。スペースも出
                        力できます。

scanf()関数 - その1

【説明】 キーボードからの入力を受け付け変数にその値をセットします。プログラム の実行がこの行に達するとプログラムは一端そこで停止し、キーボードからの入力待ち 状態に入ります。

【用例】 

int n;
scanf("%d",&n); …… キーボードから入力された整数を n という変数にセットします。

for文 - その1

【説明】 forは指定回数の繰り返しを行うための文です。

 for( 初期値設定 ; 継続条件 ; 増分 )
 {
    文
 } 
・ 処理に入る前に、まず「初期値を設定」します。
・ その後、「継続条件」が成り立つ間、文を繰り返し実行します。
・ 文の実行後、「増分」に従って変数を変化させます。


【用例】 

int i;
for(i=0; i<3; i++) {
   printf("hello\n");  …… for(i=0; i<3; i++) とありこれは i が0から2まで1
}                             ずつ変化することを意味します。つまり i は 0、1、2
                              と変化し、printf が 3 回分実行されます。 

関数 - その1

【説明】 Cプログラムは関数の寄せ集めとして構成されます。プログラムは mainだけでも十分に機能します。実際、小さなプログラムは、mainだけで記述 されるのが普通です。しかしプログラムが大きくなると、巨大な一つのmain 関数だけでは、プログラムの見通しが悪くなります。そこでプログラムを手頃 な大きさの関数に分割してやります。

関数の定義に最低限必要なものは関数名だけです。それは以下のような形になります。

function_name ()
{
}

関数には自由に名前をつけてかまいませんが、"main"だけは特別な名前で、プログラム
の中には必ず"main"という名前の関数が必要です。プログラムはこのmain関数から実行
開始されます。 

【用例】 

#include <stdio.h>


print() {                 …… printf()を実行するprint関数を定義する。
   printf("hello\n");
}

main() {
   print();              …… print()関数を呼び出す。 
}

関数 - その2 (関数の引数)

【説明】 関数の呼び出し側と関数本体側でデータのやりとりをするには引数 を用います。引数は関数名に接続するかっこの中に、データ型と変数名を書い てやります。たとえば次のように書きます。

  add(int a, int b)
  {
  ....
  }
このときの変数 a や b を「仮引数」と呼んでいます。それはどんな値が
渡されるか分からない仮の引数だからです。一方この関数を呼び出す側では、

add(100, 200);      …… 実際の値を記述する。

add(y, z);          …… 実際の変数名を記述する。

のように実際のデータを記述します。これを「実引数」と呼んでいます。

【用例】 

print(int n) {             …… 引数を持つ関数を定義する。
 int i;
 for(i = 0; i < n; i++) { …… 引数 n の値の回数だけ文 printf() を実行する。
   printf("hello\n");
 } 
}

main() {
 int i;
 i = 5;
 print(3);                …… 実数を引数として関数を呼び出す。
 print(i);                …… 変数を引数として関数を呼び出す。
} 

変数 - その2 (小数)

【説明】 データ(数値)を記憶しておく箱を変数と言いました。変数は使用 する前に保持するデータの型を指定して宣言しなければなりません。すでに整 数を保存するデータ型として int を紹介しましたが、小数を保存するデータ 型として float、double というデータ型があります。C言語では小数のデー タ型のことを「浮動小数点型」と呼んでいます。floatとdoubleの違いは小数 を保存するサイズでdoubleの方がより多くの桁数を保持できます。絶対的なサ イズ(何桁までデータを保持するか)は処理系に依存します。

【用例】 

double x;                 …… double型の変数xを宣言する。
x = 0.05;                 …… 変数に値を代入する。

変数 - その3 (グローバル変数)

【説明】 Cでは関数の内部で宣言した変数は、その関数の中だけで有効です。 逆に言えばある関数から、別の関数の内部で宣言されている変数をつかうこと はできません。このような変数の機能はローカル(局所的)なものですのでこれ を「ローカル変数」と呼んでいます。それに対してどの関数からでも使うこと のできる変数を「グローバル変数」と呼んでいます。グローバル変数は関数の 外で定義されます。

【用例】

ローカル変数は特定関数の内部でしか使うことができません。このことは逆に言うと、
他の関数の内部で同じ名前の変数を使っても衝突が起きないということです。下の例で
は、functionという関数とmain関数の中で変数 a を定義していますが、この2つの変数
 a は全く関係のない独立した変数として働きます。

#include <stdio.h>
int g;               …… グローバル変数 g を定義する。ここから
                                    ↓
function() {                        ↓
  int a;             …… ローカル変数 a を定義する。    ↓
    ‥                    ↓            ↓
    ‥                       ここまで有効            ↓
}                                                         ↓
                                                          ↓
main() {                                                  ↓
  int a, b;          ……ローカル変数 a、b を定義する。   ↓
    ‥                       ↓                   ↓
    ‥                  ここまで有効         ↓
}                                                         ↓
                                       ここまで有効 

算術演算子 - その1 (+ - * / %)

【説明】 
演算子説明
+正符号+a
-負符号-a
*乗算(かけ算)a = b * c;
/除算(割り算)a = b / c;
%剰余(あまり)a = b % c;
+加算(足し算)a = b + c;
-減算(引き算)a = b - c;

算術演算子は数値を計算するものです。結果として数値を得ます。整数除算を行うと余
りは切り捨てられます。また整数に対して % 演算子を使うと余りを求められます。
0で除算すると結果は不定になります。

【用例】

int a, b, c;          /* int型の変数a、b、cを宣言する */
double d, e, f;       /* double型の変数d、e、fを宣言する */
b = 5; c = 3;         /* 変数b、cに値をセットする */
e = 5.0; f = 3.0;     /* 変数e、fに値をセットする */

a = b + c;            /* 加算。a には 8 が入る */
a = b - c;            /* 除算。a には 2 が入る */
a = b * c;            /* 乗算。a には 15 が入る */
a = b / c;            /* 整数の除算。a には 1 が入る */
d = e / f;            /* 小数の除算。a には 1.6666..が入る */
a = b % c;            /* 余り。a には 2 が入る */

if文

【説明】 if文の基本的な動作は、条件にしたがって処理を2方向に分岐することです 。省略や多重構造にすることによって3つのバリエーションがあります。

書式1 

if(条件)
  文 

もし条件が真(0以外)なら文を実行する 。偽(0)ならなにもしない。 
被制御文が複数のときは { } を用いる。


書式2 

if(条件)
  文1
else 
  文2 

もし条件が真(0以外)なら文1を実行する。偽(0)なら文2を実行する。 

書式3 

if(条件1)
  文1
else if(条件2)
  文2
  ・
  ・
else if(条件n)
  文n
else 
  文 
 

もし条件1が真(0以外)なら文1を実行する。 
そうではなく条件2が真(0以外)なら文2を実行する。 

そうではなく条件nが真(0以外)なら文nを実行する。 
そうでなければ(0)文を実行する。 

【用例】

int i;
for(i=0; i<10; i++) {         …… for文を用いiの値によって処理を分岐する。
  if(i==1) {                  …… iが1のときはhelloを出力する。
    printf("hello\n");        …… i = 1 のとき
  }
  else if(i<5) {            …… iが5未満のときworldを出力する。
    printf("world\n");        …… i = 0, 2, 3, 4のとき
  }
  else {                      …… それ以外のときkeioを出力する。
    printf("keio\n");         …… i = 5, 6, 7, 8, 9のとき
  }
}

関係演算子

【説明】 関係演算子は、2つのオペランド(演算の対象)の大小関係(どち らの数が多いか)や等値関係(2つの数値が等しいか)を判定して、真偽値 (式が成り立つかどうか)を得るものです。2つの数の関係が正しければ1、 正しくなければ0になります。

 演算子    説明              例 

    <         小さい             if(a < b)
    <=        小さいか等しい     if(a <= b)
    >         大きい             if(a > b)
    >=        大きいか等しい     if(a >= b)
    ==        等しい             if(a == b)
    !=        等しくない         if(a != b)

数学関数(sin、cos)

【説明】 Cにはさまざまな数学関数が用意されていますが、ここでは sin と cos について説明します。sin は引数にラジアン値を与えると、サイン値を返 します。cos は同様にコサイン値を返します。引数が度数ではなくラジアン値 であることに注意してください。ラジアン、sin、cosについては高校の数学の 教科書を参照して思い出してください。簡単に書くと、180度は 3.14159… ラ ジアン、360度は 6.28318… ラジアンです。


【用例】 

#define P 3.141592            /* P は π の意味です */

main() {
  double a, b, c;
  a = 75.0;                   /* a には角度(75)を代入します */
  b = sin(a/180*P);           /* 角度 a をラジアンに計算してからsinの引数
                                   として与えています。 */
  c = cos(a/180*P);           /* 同様に cos を計算しています */
}

算術演算子 - その2 (優先順位と結合法則)

【説明】 これまでに説明した算術演算子(他にも演算子はあるが)には、優 先順位があります。これはたとえば、「1+2*3」では 2*3が先に計算されて、 結果は7になるといったことです。もし「1+2」を優先して演算したいときは、 優先順位がもっとも高い ( ) を用いて、順位を切り替えます。すなわち 「(1+2)*3」とします。

もうひとつ演算子には結合規則というものがあります。一つの式の中に同順位の演算子 が存在した場合、結合法則に基づいて優先評価されます。

a = 10;
b = 20;
a = b = 30;

では変数 a と b の値は共に 30 になります。これは演算子 ' = ' の結合規則が右結
合的(右から左に結合する)となっているからです。このため式はまず右側の「 b = 30
 」が実行され、そのあと「 a = b 」 が実行されます。また

8 / 4 * 2

という式では '/' と '*' の優先順位は等しいけれど左結合的であるため、

( 8 / 4 ) * 2

として働き、結果は 4 となります。

種類         演算子                結合法則 

カッコ      ( )                         → 
乗除        * / %                       → 
加減        + -                         → 
比較        < <= > >=                → 
等値        == !=                      → 
代入        = += -= *= /= %=       ← 
コンマ      ,                           → 

printf()、scanf()関数 - その2 (書式指定)

【説明】 printf() や scanf() は単純に文字を出力したり読み込んだりする だけではなく、数値を10桁表示するとか、数値を小数として読み込むといった ことを設定できます。以下では授業で必要そうな書式設定を紹介します。

printf() で出力できるのは、
・ 一般文字列 (hello, keioとか普通の文字)
・ ¥で始まるエスケープ文字列(\nなど)
・ %で始まる変換文字列() 

printfの利用例                  出力結果             コメント 

printf("hello\n");              hello                文字列と改行の出力 
int i = 10;
printf("i = %d", i);            i = 10               整数の出力 
printf("123%%456");             123%456              %自身の出力 
double d = 1.5793;
printf("%f", d);                1.579300             小数の出力 
double d = 0.5793369;
printf("%.2f", d);              0.57                 小数点以下2桁を出力 
int i=10; 
double d = 1.579393
printf("i=%d, d=%f\n", i, d);   i=10, d=1.579993     複数の変換文字の出力 

scanf() はキーボードから書式付きで文字列や数値を入力する関数です。scanfは機能
としてはprintf の逆の働きをします。変換文字なども printf のものと共通部分が多
くあります。標準ではデータの入力は、スペースで区切られます。

変換文字の利用例                入力データ            コメント 

int n;
scanf("%d", &n);                10                    整数(10進数)を入力 
int a, b;
scanf("%d%d", &a, &b);          20 30                 2つの数字の入力 
double d;
scanf("%lf", &d);               1.45323               小数の入力 

配列 - その1 (1次元配列)

【説明】 配列は、同じ名前で操作される同じ型のデータを集めたものです。 1次元配列の宣言の基本的な書式は次のとおりです。

データ型名 変数名[サイズ];

配列確保の例をあげます。 

int a[10];               int型変数80個からなる配列a 
int b[10], c[5];         int型変数10個からなる配列bと5個からなる配列 c 
double d[20];            double 型変数20個からなる配列 d 

このとき確保される要素は0からはじまります。ですから「int a[10];」と宣言したと
き利用できる配列は、a[0]〜a[9]までの10個です。配列の使い方は普通の変数と同様で
、a[5]とすればaという配列の6番目の要素に代入したり値を参照したりできます。

またコンパイラは、実行時に配列の境界をチェックしません。それは、「int a[10];」
の宣言で使える配列要素はa[0]〜a[9]までですが、このときに、

  a[10] = 100;
  a[25] = 100;

といった代入をしても、強引に実行されます。それはa[0]から10番目や25番目の要素に
該当するアドレスの内容を無理矢理書き換えることになります。ですから、プログラマ
は境界を越えた代入をしないように注意しなければなりません。

【用例】

4. グラフィック

ウィンドウ座標

【説明】 ウィンドウの任意の一点を指定するためには, 2つの独立の値が必要 である. 指定され2つの値の組を座標 (coordinate) という. 一般に原点に直 交する2つの軸をx軸, y軸と呼ぶことが多い. SGL で SG2DMode() を指定した 場合はウィンドウの左上を原点とし, 右方向にx軸, 下方向にy軸が定められる. 座標は, ウィンドウのサイズがそのまま採用される. SG2DMode() を指定しな い(何も指定しない)場合は, ウィンドウの中心を原点とし, 右方向にx軸, 上 方向にy軸が定められる. ウィンドウの縦と横の短い方を4の長さにして座標 が決定される.

coordinate system for SG2DModecoordinate system not specified

曲線の描画

【説明】 ディスプレイ上に曲線を直接表示することはできないので, 折れ線 (直線の集合)によって曲線を近似して表示します. 曲線を近似するのに, 多数 の直線を用いれば滑らかに表示されますが、その分処理が重くなってしまいま す. 適切な直線の数で近似する必要があります.

2 segmented curve4 segmented curve8 segmented curve