C言語の基礎Ⅰ

この章では、一通りの基本的な知識を学んでみることにします。詳しい解説は省きますが、だいたいの動作は理解できると思います。最初はとにかく簡単なプログラムを読むことで、そこに書いてあるコードが何を意味するのかを理解してください(説明文よりもソースコードをよく読んでください)。

printf 文字を表示する

画面に好きな文字を表示するだけのプログラムです。コメントをよく読んでください。文の最後にはセミコロン(;)を書きます。また、printf()中の文字列の\nは、改行を表します。

#include<stdio.h> /* この行は必ず書く、と覚える */

int main() /* 次からメインのプログラムですよ */
{ /* 中カッコの中がプログラム本体 */
    printf("hello, world\n"); /* hello, world と表示して改行する */
    return 0; /* プログラムを終了します */
} /* ちなみにこれは注釈(コメント)です */

以下は出力結果。

hello, world

変数を使う

今度は変数を使います。変数とは数を入れておける箱のようなものです。変数を使用するには、(中カッコの中の)一番はじめに宣言を書かねばなりません。宣言は、同じ型(「よく使うデータ型一覧」を参照)であるならカンマ(,)で区切っていくつでも書くことができます。変数の名前には、半角英数字そしてアンダースコア(_)を使うことができます。ただし、先頭の1文字に数字は使えません。

#include <stdio.h>

int main()
{
  int a, b=2; /* 整数型の aとbを宣言して、bを2で初期化 */
  char c; /* 文字型のcを宣言 */
  a = 3; /* 代入。変数bのように宣言時に初期化してもよい */
  c = 'A'; /* cに、文字Aを代入( cは整数型でなく文字型である) */
  printf("a = %d\n", a); /* a = 3 と表示して改行。%d は、整数 a と置き換わる */
  printf("b = %d\n", b); /* b = 2 と表示して改行。%d は、整数 b と置き換わる */
  printf("c = %c\n", c); /* c = A と表示して改行。%c は、文字 c と置き換わる */
  return 0;
}

変数の値をprintf()で表示するために、%dや%cといった文字列を使用しています。%で始まる文字列は、カンマで区切った後に書いてある変数の値と置き換わります。

よく使うデータ型一覧

扱える範囲 (16bitマシンの場合) printf中の表記
int -32768〜32767の整数 %d
long -2147483648〜2147483647の整数 %ld
float 有効桁数6桁の実数 %f(%e)
double 有効桁数15桁の実数 %f(%e)
 char  -127〜128(文字)  %c(1文字を表示), %d(値を表示)
 char *  配列で指定された文字数  %s(文字列を表示)

型の前にunsignedと書くことで、扱える範囲を正の整数にすることができます(char/int/longの場合)。そうすると、負の整数は扱えなくなりますが、その分、正の範囲が2倍使えるようになります。unsignedをprintf()で出力するとき、intは%u、longは%luと表記します。

文字と文字列

文字はシングルクォーテェーション(')で囲み、文字列はダブルクォーテェーション(")で囲みます。char型に入るのは文字で、文字列ではありません。ここでちょっと難しくなりますが、文字について説明します。

一言で説明するならば、文字=数字となります。例えば、'A'という文字は65という数字と等価であり、'B'という文字は66と等価であるのです。はたまた、'1'は49だったりします。前のソースで、c='A'という式がありますが、これはc=65と書き換えても全く同様に動作します。

文字にはこのような性質があるのですが、文字列はまた別の概念で表現されています。
誤解を恐れずに言えば 「文字の配列で表す」ということです。 (厳密には正しくありません。でも今は、こういうふうに理解しても支障はありません。 )
では、配列はどのように表すかというと

int a[3]; char c[5];

などのように宣言します。
最初の方は、int型の変数a[0],a[1],a[2]を、次のは、char型の変数c[0],c[1],c[2],c[3], c[4]をまとめて宣言したと考えてください([]の中の数字は、0から始まる ことに注意)。 a[2]や、c[0]などは、要素と呼ぶこともあります。 これらの要素は、普通の変数と同じに取り扱えます。 配列に、ついてはあとの章で詳しく解説しますので今は、 雰囲気だけで結構です。

では、文字列の解説です。 表したい文字列をダブル・クォーテーションで囲みます。 この囲まれた物そのものは、文字列の最初の文字の アドレスを表します。最初から文字列を宣言するときは、 次のようにします。

char *str = "ABC";

これの意味するところは、
str[0]='A',str[1]='B',str[2]='C',str[3]='\0'
と言うことです。最後の「\0 」は、NULL文字と言って 文字列の最後を表す記号だと思ってください。Cでは、 文字列の最後に、必ず¥0がつきます!

それでは例題を見てみましょう。

#include <stdio.h>

int main()
{
  char a= 'A'; /* 文字型のaを宣言 */
  char *str ="This is a pen."; /* 文字列を宣言 */

  printf("%c\n", a); /* aを表示して改行。%c は、文字 a と置き換わる */
  printf("%s\n", str); /* strを表示して改行。(*strではないことに注意)%s は、文字列str と置き換わる */
  printf(str);/*strを表示*/
  return 0;
}

文字列の宣言、及び表示の仕方はかなり特殊な物なので、今はこういうふうに宣言するとおぼえてください。又、後で出てきますが自分で文字列を入力する際は、自分で領域を確保しなければならず、
char *str[100];
のように宣言するよう十分に気をつけてください。

計算をしよう

今度は整数でなく、実数(小数点以下がある数)の計算をするために、double型(floatでも可)を使用しています。

#include <stdio.h>

int main()
{
  double radius = 10; /* 半径 */
  double pi = 3.1415926; /* π */
  double circumference; /* 円周 */
  double area; /* 面積(変数名には誰が見ても分かる名前を)*/
  circumference = radius * 2 * pi;
  area = radius * radius * pi; printf("半径= %f\n", radius); /* double を表示するには %f */
  printf("円周 = %f\n",circumference); printf("面積 = %f\n", area);
  printf("\n\n");/* 改行を2つ */
  printf("半径 = %f\n", radius = 20); /* 今度は半径20(この場で代入)*/
  printf("円周 = %f\n", radius * 2 * pi); /* この場で計算も可 */
  printf("面積 = %f\n", radius * radius * pi); /* 式は文中のどこでも書ける */
  return 0;
}

また、計算の優先度もあるので、加算を乗算より先に行いたいときはカッコでくくるようにしましょう。

よく使う演算子一覧

算術演算
* 乗算
/ 除算
+ 加算
- 減算
% 剰余(余り)
++ 1加算(単項)
-- 1減算(単項)
*= 積の代入
/= 商の代入
+= 和の代入
-= 差の代入
%= 余の代入
論理/ビット演算
&& 論理積(AND)
|| 論理和(OR)
== 等しい
!= 等しくない
< より小さい
<= 以下
> より大きい
>= 以上
! 論理否定(NOT)(単項)
& ビットごとのAND
| ビットごとのOR
^ ビットごとのXOR
~ ビットごとのNOT(単項)

単項とは、1つの変数に対して効果のある演算子のことを指します(例:a++)。単項演算子以外は、常に2つの項を必要とします(例:a+b)。

論理演算とは、普段はif文(後述)などの条件式で使用します。また、「ビットごとの〜」演算子は普段は使いませんが、一応書いておきました。これについて本稿での説明は割愛します。

「〜の代入」演算子は、次のように使います。

a += 5; /* aに5を加算した値をaに代入 。  */ a = a + 5; /* 上と同じ動作をする式 */

scanf キーボード入力を受け付ける

#include <stdio.h>

int main()
{
  int old;
  float weight;
  printf("あなたは何歳ですか? >");
  scanf("%d", &old); /* oldにキーボードからの数字を代入。&が必要 */
  printf("すると、10年後は%d歳ですね。\n",old+10);
  printf("あなたの体重は何キロ? >");
  scanf("%f", &weight);/* ほかの型も同様。 &を忘れずに */
  printf("ふーん、そうなんだ。\n");
  return 0;
}

scanf()は、キーボードからの入力を変数に格納する関数(命令)です。入力されるものが、整数なのか、文字なのか、はたまた実数(浮動小数点数という)なのかをコンピュータに教えなければならないのですが、それをprintf()と同じように%で始まる文字列で指定します。ここで注意しなければならないのは、文字列(%s)以外の格納する変数の頭に&をつけなければならないことです。これには意味があるのですが、今は「決まり」と覚えてください。

扱える範囲 (16bitマシンの場合) scanf中の表記  &
int -32768〜32767の整数 %d   必要
long -2147483648〜2147483647の整数 %ld   必要
float 有効桁数6桁の実数 %f(%e)   必要
double 有効桁数15桁の実数 %f(%e)   必要
 char  -127〜128(文字) %c(1文字を表示), %d(値を表示)   必要
 char *  配列で指定された文字数 %s(文字列を表示)   不必要


それではここで、今まで勉強したことを使ってタイピングソフトを作っていきたいと思います。
サンプル1へ

if,switch 条件分岐をする

if文は、カッコの中の条件が成立していれば、次の中カッコを実行します。条件が成立していない場合は、else以降の中カッコを実行します。必要がなければelse以降は省略することが可能です。

if文の書式は次のようになります。

if(条件式) 条件式が成立した場合に処理する文 else 条件式が成立しなかった場合に処理する文 ※else以降は無くてもいい

それでは具体例をみていきましょう。

#include <stdio.h>

int main()
{
  int old; printf("あなたの年齢は? >");
  scanf("%d",&old);
  if(old < 20){ /* oldが20未満だったら */
  printf("あなたは未だ違法である。\n");
  }else{ /* そうじゃなかったら */
    printf("今度一緒に飲みましょう。\n");
    }
  return 0;
}

switch文は、カッコの中の値に対応するcaseの位置にジャンプします。処理の終わりにはbreak文を書かないと次のcaseまで続けて実行してしまうので、必ずbreak文を書くようにしましょう(意図的に書かない場合もある)。どのcaseにも対応しない場合はdefaultにジャンプします。defaultも無い場合は何も処理しません。

switch文の書式は次のようになります。

switch(式){ case 定数式: 文 default: 文 } ※caseは何個あってもい。defaultは無くてもいい

#include <stdio.h>

int main()
{

  char neta;
  printf("いらっしゃい!何にしましょうか?\n");
  printf("a:とろ b:赤身 c:ホタテ d:げそ >");
  scanf("%c", &neta); /* 数字ではなく文字を入力させる*/
  switch(neta){
  case 'a': /* netaは文字型だから、ここは文字定数。*/
  printf("へい!とろいっちょ!\n");
  break; /* breakが無いと、次のcaseに続いて処理をしてしまう */
  case 'b': printf("はいよー!赤身おまちどうさま。\n");
  break;
  case 'c': printf("ごめんねー、ホタテきらしてるんだ。\n");
  break;
  case 'd':printf("げそなんて、お客さんめずらしいねー。\n");
  break;
  default: /* 変な文字を入力した場合 */ printf("冷やかしなら帰ってもらうよー!\n"); break;
  }
return 0;
}

それでは、ここまで勉強したことの理解を深めるためにアニメーションの解説付例題をやってみましょう。
例題1へ

次に、この章で学んだことを使ってサンプルを改良していきましょう。
サンプル2へ

for,while 繰り返し処理

ここでは、繰り返し処理の3つの書式を勉強していきましょう。

1,for文の書式。

for(式1 ; 条件式 ; 式2) 文 ※ 式1 → 条件式 → 文 → 式2 → 条件式 → ・・・ の順番

2,while文の書式。

while(条件式) 文 ※ 条件式 → 文 → 条件式 → ・・・ の順番

3,do〜while文の書式。

do 文 while(条件式); ※ 文 → 条件式 → 文 → 条件式 → ・・・ の順番

上の3つのプログラムは全く同じ動作をしています。厳密に言えば最後のdo〜whileだけ少し違うのですが、それについては後述します。

しかし、同じことをする文が2つも3つも存在することに意味があるのでしょうか?実は、「動作は同じでも、それぞれの持っている意味(解釈)が違う」から意味があるのです。

for文は、「何回繰り返す」という意味合いで使いますが、while/do〜while文は、「条件が成立している間繰り返す」という意味合いを強く持ちます。これらの意味合いを使い分けられると、他人のソースコードを読むときに大変読みやすくなります。とりあえずは、forとwhileを使えるようにしましょう。

ところで、do〜whileですが、whileの双子の兄弟と思ってください。何がwhileと違うかというと、do〜whileは、評価する条件式が文の後ろにあるから、条件がどうであろうと最低1回は命令を実行することになる、ということです。

#include<stdio.h>

int main()
{
  int i;
  for(i=0; i<20; i++){ /* 20回繰り返す。(iは0から19まで) */
  printf("i = %d\n", i); /* ここには、繰り返したい文をいくつも書くことができる */
  }
return 0;
}

まず、一番はじめにi=0が実行されます。次にi<20を評価し、条件が成立していればprintf()を実行します。それが終わるとi++を実行し、またi<20の評価に移ります。それが成立していれば、後はprintf() => i++ => i<20と、繰り返すことになります。もちろん、 i<20が成立しなくなったら、for文は終了します。

あまりいい例ではありませんが、forをwhileで書き換えると次のようになります。

#include <stdio.h>

int main()
{
  int i;
  i=0;
  while(i < 20){ /* i < 20が成立している間繰り返し */
  printf("i = %d\n", i); i++;
  }
return 0;
}

最後に、do〜while文というのを見てみましょう。

#include <stdio.h>

int main()
{
  int i=0;
  do{ /* 条件式はループの最後に書く */
  printf("i = %d\n",i); i++; }while(i < 20);
  return 0;
}

break文

break文を使うと、ループの途中でもそのループを終了することができます。使い方としてはswitch文中のbreak文と同じです(switchはループではないことが違う)。

ワンポイント〜文

if文では条件が成立した場合に処理する命令を中カッコで囲んでいましたし、for文でも繰り返す命令を中カッコで囲みました。しかし、この中カッコは省略できる場合があります。

C言語には「複文」という考え方があります。文とは式や宣言の最後にセミコロン(;)を付けたもののことを言います。それに対する複文とは、中カッコで囲まれた複数の(別に1つでもいい)文から成り立つブロックのことを指します。複文の閉じ中カッコ(})の後にセミコロン(;)は必要ありません。ifやforの後には文を書く決まりなので、通常の文でも複文でもいいのです(for文やwhile文の書き方の欄で、中カッコを使っていないのはそのため)。その例を下に示します。

/* 下のif文はどちらも同じ */

if(i != 0) printf("This is a pen.\n");

if(i != 0){
printf("This is a pen.\n");
}

/* 次の例の場合、中カッコは取り除けない */
for(i=0; i<10; i++){
printf("%d >", i); /* 複数の文を扱うときは */
scanf("%d", &p[i]); /* 中カッコで囲む */
}

それでは、このテーマのアニメーションでの解説付例題をやってみましょう。
例題2へ


次に、この章で学んだことを使ってサンプルを改良していきましょう。
サンプル3へ