C言語での演算処理

演算

第一日目では、printf()関数を用いて、様々な演算をしてみました。その中で、C言語を用いれば、簡単な計算が出来ることがわかりました。そこで、ここでは、C言語を用いた計算について学んでいくことにしましょう。

プログラミングの世界では、こういった計算のことを、専門用語で演算と呼びます。これは、以下、簡単な演算のプログラムをみてみることにしましょう。

サンプロプログラム

list2-1:簡単な演算処理(main.c)
#include <stdio.h>
/*
	演算子を用いた計算のプログラム
*/

void main()
{
	// 各種演算
	printf("%d + %d = %d¥n",5,2,5+2);				/* 足し算 */
	printf("%d - %d = %d¥n",5,2,5-2);				/* 引き算 */
	printf("%d * %d = %d¥n",5,2,5*2);				/* 掛け算 */
	printf("%d / %d = %d 余り %d ¥n",5,2,5/2, 5 % 2); /* 割り算 */	
}
実行結果
5 + 2 = 7
5 - 2 = 3
5 * 2 = 10
5 / 2 = 2 余り 1

実行結果からもわかるとおり、このプログラムを実行すると、様々な計算結果が出てきます。

演算子

このように、C言語で様々な演算を行う記号のことを演算子(えんざんし)と呼びます。足し算の+や、引き算の-はわかるものの、その他の記号は何でしょう?C言語で使用する演算子は以下の表2-1のようなものがあります。

表2-1:C言語の計算で用いられる主な演算子
演算子 読み方 意味 使用例
+ プラス 足し算を行う演算子 5 + 5
- マイナス 引き算を行う演算子 7 - 3
* アスタリスク 掛け算を行う演算子 7 * 3
/ スラッシュ 割り算を行う演算子 7 / 3
% パーセント 剰余(じょうよ)演算子。割り算の余り 7 % 3

評価和わかるとおり、*が掛算、/が割り算を表す記号であることがわかると思います。また、%の記号は、かなりC言語のプログラミングでは使用頻度が高いので、覚えておきましょう。

コメント

ところで、このプログラムの中に、出てくる//や、/*  */という記号が出てきます。しかも、その中には、文章が書いていますが、プログラムの実行結果には何も関係ないように見えます。この記号のことを、コメントと言います。

コメントは、プログラムの注釈を付けるためのもので、プログラマーが、プログラムの各所に書いて、処理の意味などを記述する時に用いられます。実行結果には何ら影響を与えませんが、これを付けるとプログラムが非常にわかりやすくなります。

そのため、プログラマーは、出来るだけコメントをつけるようにすることが勧められています。なお、コメントには、以下(表2-2)のような種類があります。

表2-2:C言語で用いられるコメント
記述方法 名前 特徴 使用例
/*  */ ブロックコメント /*と、*/の間に囲まれた部分がコメントになる。
複数行にわたってコメントをつけることが出来る。
/* 
   このように複数行
   コメント可能です。
*/
// 行コメント 一行にコメントをつけることが出来る。 // コメント

変数

C言語と変数

C言語を用いれば、様々な演算ができることはすでにわかりました。しかし、これでは、決められた値の計算しかできません。実際は、色々な数値を用いて計算することが想定されるため、これでは不便です。 このように、値が定まった数のことを、定数と言いますが、それに対し、C言語には、値を常に変えることができる数が存在するのです。これを、変数と言います。

サンプルプログラム

まずは、以下のサンプルを実行してみてください。

list2-2:変数を用いた演算処理(main.c)
#include <stdio.h>
/*
	変数を用いた計算
*/

void main()
{
	/* 使用する変数の定義 */
	int a;	// 変数の宣言
	int b = 3;		//	初期化と代入を同時に行う。
	int add,sub;	//	複数の変数を同時に宣言
	double avg;		//	int以外の変数を宣言
	a = 6;	//	代入(最初に値を入れるので、”初期化”と言う。
	add = a + b;			//	a,bの和を求める。
	sub = a - b;			//	a,bの差を求める。
	avg = (a + b) / 2.0;	//	a,bの平均値を求める。
	printf("%d + %d = %d¥n",a,b,add);
	printf("%d - %d = %d¥n",a,b,sub);
	printf("%dと%dの平均値:%f¥n",a,b,avg);
}
実行結果
6 + 3 = 9
6 - 3 = 3
6と3の平均値 4.500000

プログラムの中にabaddsubavgといった文字列が出ていますが、これが変数です。int aとある部分を、変数の宣言と言います。そのあと、a=6のようにすると、値が入ります。これを代入と言います。(図2-1)特に、変数を宣言したときに、最初に行う代入のことを、初期化と言います。

代入

数値が代入された変数は、その数値として扱う事が出来ます。例えば、a=6とすれば、aは別の値が代入されるまで、"6"として扱う事が出来ます。変数は原則的に何度も値を変えることが可能です。つまり、変数は値を変えることが出来るのです。

変数の初期化と代入
int a; ← 変数の初期化(aという変数を使えるようにする)
a = 6; ← 代入。(変数に値を入れる)

図2-1.変数の宣言と代入のイメージ

変数の宣言と代入のイメージ

演算の優先順位

プログラム中に、()(括弧)がありますが、これは、計算の優先順位を変更するものです。通常、

括弧が無い場合の計算
1 + 2 * 3 → 結果は7

とすると、最初に掛け算の演算である「2*3」が実行され、その結果の6に1が加算されます。したがって、結果は7になります。しかし、

括弧を用いた計算
(1 + 2) * 3 → 結果は9

とすると、()内の計算を先に行い、その結果である、3と次の3が掛けられることになります。このように、C言語にも、数学と同じような演算子の優先順位があります。 C言語には様々な演算があるため、ここでは全てを説明するのは省略しますが、加減乗除といった基本的な数値計算に関しては、数学と同じルールに従うと思ってほぼ間違いありません。(図2-2)

図2-2.()を使用した場合と、使用しない場合の演算の処理

C言語での ()が無い演算と、ある演算

データ型

では、初期化の際に変数の先頭についている、intや、doubleといった文字列は何でしょうか?このような文字列のことを、データ型と言い、その変数がどのような値を扱うのかを示しています。 例えば、intは、整数型のデータ型を表し、"int a"とすると、"aは整数の値が入る変数である。"ことを意味します。なお、データ型には以下のようなものがあります。(表2-3

表2-3:C言語で用いられるデータ型
データ型 説明
char 1バイトの符号付整数。ASCIIコードといった文字コードに使用。
unsigned char 1バイトの符号なし整数。
short 2バイトの符号付整数。
unsigned short 2バイトの符号なし整数。
long 4バイトの符号付整数。
unsigned long 4バイトの符号なし整数。
int 2または4バイトの符号付整数。(コンパイラに依存)
unsigned 2バイトまた4バイトの符号なし整数。(コンパイラに依存)
float 4バイトの単精度浮動小数点実数。
double 8バイトの倍精度浮動小数点実数。

表に出ているように、intは、2バイトか4バイトのどちらかであり、2バイトとの場合は、shortと、4バイトの場合は、longと一致します。 近頃のコンパイラや実行環境は、4バイト、つまりlongとおなじにしているものがほとんどのようです。

初期化

再び変数の話に戻りましょう。変数は、宣言時に値を代入(初期化)することが出来ます。記述方法は以下のとおりです。

変数の宣言と初期化を同時に行う
int a = 6;← 変数の宣言と同時に値を代入(初期化)

また、以下のように、,(コンマ)で区切ることにより同時に複数の変数を宣言したり、初期化することも可能です。

複数の変数を同時に宣言
int a,b;← 変数a,bを宣言
int a=1,b=2;← 変数a,bを初期化
int a,b=1;← 変数a,bを宣言、bのみを初期化

なお、プログラミングにおいて、変数は必ず初期化して使うというルールがあります。初期化していない変数を使用すると、プログラムが異常終了することがありますので、気をつけてください。

変数の初期化の位置

また、変数の宣言をする場所ですが、必ず{}の先頭の部分で行わなくてはなりません。以下のように、何らかの処理が行われた後で変数を定義すると、エラーになりますので、注意が必要です。

変数の宣言の位置に関する注意
void main()
{
    // 先頭の部分で変数の宣言を行う。
    int a,b=1;
    double d=0.1,e;
    printf("hello¥n");
    int c;  ←×何らかの処理を行った後に変数の宣言を入れることはできない。
    ・・・
}

この規則は、C言語の上位互換言語であるC++では撤廃されましたが、C言語でプログラムを作るうえでは必要なので、注意してください。

変数の命名規則

C言語の変数の命名規則

変数の名前は、基本的にプログラマーが自由につけることが許されています。通常、アルファベット一文字か、その組み合わせといったものが使われる場合がほとんどです。しかし、何でも良いというわけではなく、以下のようなルールがあります。

予約語

なお、予約語とは言語の仕様で使い方が決められている単語のことで、C言語の予約語は以下のとおりです。(表2-4)

表2-4: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

代入演算子

代入と演算

すでに述べたとおり、変数に値を入れることを代入と言いました。代入とは例えば以下のように記述します。

代入処理
a = 1;← 変数aに1を代入
a = b;← 変数aに変数bの値を代入
d = 4.0;← 変数dに4.0を代入

ここで気をつけたいのが、代入で使用する=(イコール)記号の意味です。数学で、=記号は、左辺と右辺の値が等しい、という場合に用いられる記号です。しかし、C言語で代入に用いる=は、少し意味が違います。

代入におけるイコールは、右辺の値を左辺の変数に代入するという意味になるのです。そのため、例えば

自身を用いた計算結果を代入する
a = a + 1;← ① aに、a+1の値を代入する。
b = b * 5;← ② bに、b*5の値を代入する。

といった記述方法も可能になります。例えば、①ですが、仮に最初の段階でaに4が入っていたとすると、そこに1を足した5がaに代入されます。についても同様で、bに2が入っていたら、2に5をかけた値、つまり10がbに入ります。

list2-3:変数を用いた演算処理(main.c)
#include <stdio.h>
/*
	代入演算子をを用いた計算
*/

void main()
{
	/* 使用する変数の定義 */
	int a1=2,b1=2,c1=2,d1=2;	// 変数の宣言(1)
	int a2=2,b2=2,c2=2,d2=2;	// 変数の宣言(2)
	//	普通の演算による計算と代入
	a1 = a1 + 1;
	b1 = b1 - 1;
	c1 = c1 * 2;
	d1 = d1 / 2;
	//	代入演算による計算
	a2 += 1;
	b2 -= 1;
	c2 *= 2;
	d2 /= 2;	
	printf("a1=%d b1=%d c1=%d d1=%d¥n",a1,b1,c1,d1);
	printf("a2=%d b2=%d c2=%d d2=%d¥n",a2,b2,c2,d2);
}
実行結果
a1=3 b1=1 c1=4 d1=1
a2=3 b2=1 c2=4 d2=1

代入演算子

実行結果を見れば判る通り、a1とa2~d1とd2の組み合わせはそれぞれ、記述の仕方が違うだけで、結果が同じであることが判ります。このように、代入演算を用いれば、短い記述で同様の結果を得ることが出来ることがわかります。

なお、C言語における主な代入演算は、以下のとおりです(表2-5)。

表2-5:C言語の主な代入演算子
演算子 使用例 意味
+= a+=1; a=a+1;
-= a-=1; a=a-1;
*= a*=2; a=a*2;
/= a/=2; a=a/2;
%= a%=2; a=a%2;

キャストとデータの型変換

サンプルプログラム

次に、型の異なる変数に値を代入するケースを見てみましょう。例えば、整数型の変数の値を実数型の変数に代入するような処理です。以下のサンプルを見てみましょう。

list2-4:キャストとデータの型変換(main.c)
#include <stdio.h>

void main(){
	int i1,i2,j1,j2;
	double d1,d2,e1,e2;
	//	j1,j2に値を代入
	j1 = 3;
	j2 = 3;
	//	d1,d2に値を代入。
	d1 = 1.23;
	d2 = 1.23;
	//	i1,i2にd1,d2の値を代入
	i1 = d1;			//	普通に代入
	i2 = (int)d2;		//	キャストして代入
	//	e1,e2にj1,j2の値を代入
	e1 = j1;			//	普通に代入
	e2 = (double)j2;	//	キャストして代入
	printf("d1 = %f d2 = %f¥n",d1,d2);
	printf("i1 = %d i2 = %d¥n",i1,i2);
	printf("j1 = %d j2 = %d¥n",j1,j2);	
	printf("e1 = %f e2 = %f¥n",e1,e2);
}
実行結果
d1=1.230000 d2=1.230000
i1 = 1 i2 = 1
j1 = 3 j2 = 3
e1=3.000000 e2=3.000000

キャスト

このプログラムでは、double型からint型の変換(d1,d2から、i1,i2)と、int型から変換からdouble型への変換(j1,j2から、e1,e2)を行っています。 実行結果から見てわかるとおり、前者の場合、小数点以下の数値が切り捨てられ、後者の場合は、該当する整数のあとに「.000000」がつく実数に変換されていることがわかります。

14行目と、17行目では、変換する値への型変換(キャスト)が行われています。

変数の型変換(キャスト)
i2 = (int)d2;
e2 = (double)j2;

i2はint型の変換なので、double型の変数を代入する際、先頭に(int)とつけ、e2は(double)なので、先頭に(int)とつけることにより、型の変換を行います。 整数から実数への変換の場合は特に必要ありませんが、実数から整数の変換のように、桁落ちなど、データの一部が損なわれる可能性がある場合必要です。

警告

キャストがなくても、結果は変わりませんが、13行目で、キャストなしの処理を入れると、以下のような警告が発せられます。

実数→整数の変換でコンパイル時に出る警告
warning C4244: '=' : 'double' から 'int' への変換です。データが失われる可能性があります。

これ自体はエラーではありませんが、通常ソフトウェアを開発する場合、警告を完全に取り去る必要があるので、同様の処理を行う際には、キャストを行うようにしましょう。

以上で、演算と変数に関するお話は終了です。次からは、この変数を用いていろいろな処理を行っていくことにしましょう。

練習問題 : 問題2.