第2章 変数と演算子を使って計算しよう
概要
プログラムは、計算結果などの数値を記録するために変数を使用します。ここでは計算プログラムを例に、変数の使い方と計算で使用する記号(演算子)について学びます。
この章の目標
整数など変数の使用方法について覚える。
変数によって扱える数値の範囲が異なることを覚える。
計算で使用する+や-などの記号(演算子)を覚える。
--------------------------------------------
2.1 変数と宣言
--------------------------------------------
プログラムで複雑な処理を行うためには、計算結果を記録し、必要に応じて読み出すことの出来る変数が必要となります。
まず、次のプログラムを作成して下さい。
例題2-2[p.23]、例題2-3[p.25]
C言語では、使用する変数の種類とその名前をまずはじめに記述します。これを「変数の宣言」といいます。
・ポイント(数値を記録する[p.21]、注意[p.25])
(1)変数名は、アルファベットで始まり、英数字のみを使用します。詳細は、資料A「変数名の付け方」(p.11)を参考にして下さい。
(2)プログラムの最初に、変数の宣言を必ず行います。
(3)C言語では、=は、「等しい」の記号ではありません。変数に数値を記録(代入)するという意味です。
--------------------------------------------
●代入の繰り返し
プログラムにおいて、例えば、「x = x + 1」の意味は、まず、右辺の「x + 1」の計算をし、その計算結果の値を左辺の変数「x」に代入するという意味です。
この処理の理解を深めるために、次のコラムを読んだ後、例題を作成して確認してみましょう。
コラム:プログラムの変数と方程式の変数[p.26]
例題 :例題2-4[p.27]
--------------------------------------------
●変数の型
C言語で使用する変数の種類のことを「型」と言い、次のような型があります。それぞれ扱える数値の範囲が決まっていることをよく覚えておいて下さい。
・基本的データ型
char :1バイト整数;1文字を保持
int
:整数(16ビットもしくは32ビット;機種に依存)
float :単精度浮動小数点数(32ビット;厳密には機種に依存)
double :倍精度浮動小数点数(64ビット;厳密には機種に依存)
・修飾子
short
:intに適用;短いビット数で数値を扱う
long :int,doubleに適用;長いビット数で数値を扱う
signed
:char,intに適用;符号あり(数値の範囲に負を含む)
unsigned :char,intに適用;符号なし(数値の範囲は常に正か0)
・数値の範囲
いろいろな変数[p.29]
補足:
(1)int型、double型、そして、char型の三つの型がよく使用されます。
(2)long double型は、サポートしていない処理系があります。
(3)char型の数値の範囲は、厳密には機種に依存します。
(4)intやsignedを省略することが可能です。以下は、その一例です。
signed
int -> int
signed
short int -> short int, short
signed
long int -> long int, long
・プログラム例
(P例:2.1-1)
#include<stdio.h>
main()
{
int x;
double y;
char z;
x = 123;
y = 123.567;
z
= 'A';
printf("x
= %d\n",x);
printf("y
= %lf\n",y);
printf("z
= %c\n",z);
}
--------------------------------------------
●オーバフロー
signed char型の変数は、-128から+127までの整数を扱えます。この変数に対して、次のような処理を行うプログラムを作成し、実行したときの値を見て下さい。
(P例:2.1-2)
#include<stdio.h>
main()
{
signed char
x;
x = 127;
x = x + 1;
printf("x
= %d\n",x);
}
表示結果は、正しい値(128)だったでしょうか?画面には「x = -128」と表示されたと思います。
これは、signed char型の変数が扱える数値の範囲を超えたためです。なぜこのような表示結果となったのか、資料B「2の補数表示」(pp.12-13)を参考に考えて見ましょう。
また、皆さんがプログラムを作成する際は、扱える数値の範囲を意識して計算を行って下さい。
--------------------------------------------
●変数の型変換
変数の型によって、扱える数値の範囲が異なることを学びました。では次に、異なる型の間での値の受け渡しについて見てみましょう。
まず、次のような処理を行うプログラムを作成し、実行したときの値を見て下さい。
(P例:2.1-3)
#include<stdio.h>
main()
{
int x;
double y;
x = 10;
y = x / 4;
printf("y
= %lf\n",y);
}
表示結果は、正しい値だったでしょうか?右辺の「x」と「4」は、共に整数型のため、その計算結果も整数型として、小数点以下を切り捨てて、「2」と表示されたと思います。
従って、正しい計算結果を得るためには、右辺を実数型に変換して計算する必要があります。具体的には、「y = x / 4;」の箇所を「y = (double)x / 4.0;」に修正し、実行します。これで、正しい値(2.5)が表示されたと思います。
この計算例に示すように、整数と実数が混在する計算では、注意して下さい。
(P例:2.1-4)
#include<stdio.h>
main()
{
int i;
double d;
i = d =
100/3; printf("i= %lf, d= %lf\n",(double)i,d);
d = i =
100/3; printf("i= %lf, d= %lf\n",(double)i,d);
i = d =
100/3.; printf("i= %lf, d= %lf\n",(double)i,d);
d = i =
(double)100/3; printf("i= %lf, d= %lf\n",(double)i,d);
}
(P例:2.1-5)
#include<stdio.h>
main()
{
const int
i=2;
const
double d=4.8;
int x;
double y;
x =
(y=d/i); printf("x= %lf, y= %lf\n",(double)x,y);
y = (x=d/i);
printf("x= %lf, y= %lf\n",(double)x,y);
y = d * (x
= ((int)2.4 + 2.4)/d);
printf("x=
%lf, y= %lf\n",(double)x,y);
}
--------------------------------------------
●補足
(1)型のサイズを調べよう
char型は、1バイトですが、この他の基本的データ型は、機種に依存します。下記のプログラムを実行して、自分が使用している環境における基本的データ型のバイト数を調べてみましょう。
(P例:2.1-6)
#include<stdio.h>
main()
{
printf("size
of char = %d バイト\n",sizeof(char));
printf("size
of int = %d バイト\n",sizeof(int));
printf("size
of float = %d バイト\n",sizeof(float));
printf("size
of double = %d バイト\n",sizeof(double));
}
・追加説明
1バイトは、8ビットです。
(2)数値の範囲の確認プログラム
自分が使用している環境において、それぞれの変数が扱える範囲を正確に知りたい場合は、次のプログラムを実行して下さい。
printf関数の中の%の後に続く、dやuなどについては、第3章で詳しく説明します。
(P例:2.1-7)
#include<stdio.h>
#include<limits.h>
/* 整数の範囲を定義 */
#include<float.h> /* 浮動小数点数の範囲を定義 */
main()
{
printf("整数\n");
printf("[
char ]
max:%d, min:%d\n",CHAR_MAX,CHAR_MIN);
printf("[
signed char ] max:%d,
min:%d\n",SCHAR_MAX,SCHAR_MIN);
printf("[
unsigned char ] max:%u,
min:0\n",UCHAR_MAX);
printf("[
short ]
max:%hd, min:%hd\n",SHRT_MAX,SHRT_MIN);
printf("[
unsigned short ] max:%hu, min:0\n",USHRT_MAX);
printf("[
int ]
max:%d, min:%d\n",INT_MAX,INT_MIN);
printf("[
unsigned int ] max:%u,
min:0\n",UINT_MAX);
printf("[
long ]
max:%ld, min:%ld\n",LONG_MAX,LONG_MIN);
printf("[
unsigned long ] max:%lu,
min:0\n",ULONG_MAX);
printf("\n浮動小数点数\n");
printf("[ float
]
max:%e, min:%e\n",FLT_MAX,FLT_MIN);
printf("[
double ]
max:%le, min:%le\n",DBL_MAX,DBL_MIN);
}
・出力例
整数
[ char ]
max:127, min:-128
[ signed char ] max:127, min:-128
[ unsigned char ]
max:255, min:0
[ short ]
max:32767, min:-32768
[ unsigned short ] max:65535, min:0
[ int ]
max:2147483647, min:-2147483648
[ unsigned int ] max:4294967295, min:0
[ long ]
max:2147483647, min:-2147483648
[ unsigned long ]
max:4294967295, min:0
浮動小数点数
[ float ]
max:3.402823e+038, min:1.175494e-038
[ double ]
max:1.797693e+308, min:2.225074e-308
・追加説明
浮動小数点数の表現の一つである IEEE(Institute of Electrical and
Electronics Engineews; 米国電子技術者協会、通称アイトリプルイー)の 754 規格では、浮動小数点数を、32ビットまたは、64ビットで表現します。32ビットを単精度(Single Precision)と呼び、 64ビットを倍精度(Double Precision)と呼びます。
IEEE754
[符号部(sign)][指数部(exponent)][仮数部(mantissa)]
32ビット表現(単精度):符号部を1ビット、仮数部を23ビット、指数部を8ビット
64ビット表現(倍精度):符号部を1ビット、仮数部を52ビット、指数部を11ビット
この場合、float型の有効桁数は、約6桁(10進数)で、double型の有効桁数は、約15桁(10進数)です。
--------------------------------------------
2.2 定数
--------------------------------------------
●定数の宣言
プログラムで使用する定数は、通常の変数として宣言し、プログラム中で用いることができますが、定数であることを明示するために、次のような宣言を用いるのが一般的です。
・宣言例
変数MAXを定数100として使用するプログラム例です。なお、(P例:2.2-2)は、定数の型を明確に宣言する方法です。
(P例:2.2-1)
#include<stdio.h>
#define
MAX 100
main()
{
int x;
x = MAX;
printf("%d\n",x);
}
・補足
「#define MAX 100」は、MAXの変数を使用する前であればどこでも記述することが出来ます。例えば、「int x;」の前後の行に書くことも出来ます。
(P例:2.2-2)
#include<stdio.h>
main()
{
const int
MAX = 100;
int x;
x = MAX;
printf("%d\n",x);
}
--------------------------------------------
●定数の種類
定数には、次の三つの種類があります。
・整数定数
・浮動小数点定数
・文字定数
補足:
特殊な文字定数(1文字)
'\n' 改行
'\t' (水平)タブ
'\b' 後退(バックスペース)
'\r' 復帰
'\a' ベル(警告文字)
'\\' バックスラッシュ
'\'' 単一引用符
'\"' 二重引用符
'\?' 疑問符
表2.2-1 定数の種類
--------------------------------------------
●補足
#defineは、次のように数値以外も定義できます。
(P例:2.2-3)
#include<stdio.h>
#define
PRINT printf("%d\n",x)
main()
{
int x;
x = 100;
PRINT;
}
--------------------------------------------
2.3 演算子
--------------------------------------------
その他の演算子[p.30]
計算で使用される四則演算を表す+や-の記号は演算子と呼ばれ、この他にプログラムで使用される演算子には、次のようなものがあります。
1.算術演算子
加減演算子
乗除演算子
符号演算子
インクリメント演算子/デクリメント演算子
2.代入演算子
3.型演算子
4.順序演算子
5.比較演算子
関係演算子
等価演算子
条件演算子
6.論理演算子
7.アドレス演算子
8.ビット演算子
論理演算子
シフト演算子
各演算子の説明については、資料C「演算子のまとめ」(pp.14-16)を参照して下さい。ここでは、よく使用する代表的な演算子を使用したプログラムを例に、それぞれの演算子の意味について理解を深めていきましょう。
--------------------------------------------
●色々な演算子を使用したプログラム例
それぞれのプログラムの出力結果は、どのようになるでしょうか?
1.算術演算子
(P例:2.3-1)
#include<stdio.h>
main()
{
int x;
x = 10 - -2
* 5 - 13;
printf("x = %d\n",x);
x = -8 + 4 / 2 * 9 - 3; printf("x =
%d\n",x);
x
= 1 + 3 % 5 + (8 + 7) / 5; printf("x = %d\n",x);
}
(P例:2.3-2)
#include<stdio.h>
main()
{
int x,y;
x = 1;
y = ++x;
printf("y = %d, x = %d\n",y,x);
x = 1;
y = x++;
printf("y = %d, x = %d\n",y,x);
}
--------------------------------------------
2.代入演算子
(P例:2.3-3)
#include<stdio.h>
main()
{
int x;
x = 5; printf("x = %d\n",x);
x += 2; printf("x = %d\n",x);
x
*= 3; printf("x = %d\n",x);
}
--------------------------------------------
5.比較演算子
(P例:2.3-4)
#include<stdio.h>
main()
{
int x;
x = 3 <
5; printf("x = %d\n",x);
x = 3 > 5; printf("x
= %d\n",x);
x
= 3 <= 5; printf("x = %d\n",x);
x
= 5 >= 5; printf("x = %d\n",x);
x
= 3 == 5; printf("x = %d\n",x);
x
= 3 != 5; printf("x = %d\n",x);
x
= 3 < 5 ? 10 : 20; printf("x = %d\n",x);
x
= 3 > 5 ? 10 : 20; printf("x = %d\n",x);
}
--------------------------------------------
6.論理演算子
(P例:2.3-5)
#include<stdio.h>
main()
{
int x,y;
x = 3 <
5 || 3 > 5; printf("x = %d\n",x);
x = 3 < 5 && 3 > 5; printf("x = %d\n",x);
x
= !(3 < 5);
printf("x = %d\n",x);
y
= 2000;
x
= y%4==0 && y%100>0 || y%400==0;
printf("x
= %d\n",x);
}
--------------------------------------------
8.ビット演算子
(P例:2.3-6)
#include<stdio.h>
main()
{
signed char
x;
x =
~2;
printf("x = %d\n",x);
x = 1 | 3; printf("x =
%d\n",x);
x
= 1 & 3; printf("x =
%d\n",x);
x
= 1 ^ 3; printf("x =
%d\n",x);
x
= 1 << 3; printf("x = %d\n",x);
}
--------------------------------------------
●補足
(1)計算を行う上での各演算子の優先順位は、資料C「演算子のまとめ」(pp.14-16)の末尾にある優先順位表を参考にして下さい。
(2)演算子を表す記号の読み方については、資料D「記号の読み方」(p.17)を参照して下さい。
(3)#defineを使用した出力結果の工夫
(P例:2.3-7)
#include<stdio.h>
#define
PRINT(int) printf(#int "
= %d\n",int)
main()
{
PRINT(10 -
-2 * 5 - 13);
PRINT(-8 +
4 / 2 * 9 - 3);
PRINT(1 + 3
% 5 + (8 + 7) / 5);
}
--------------------------------------------
資料A「変数名の付け方」
C言語で変数の名前に使用できる文字は、次のとおりです。
a〜z A〜Z 0〜9 _(下線)
変数名はこれらを組み合わせてつくります。ただし、変数名の先頭に数字を用いることはできません。また長さも31文字までで、それ以上長い変数名では32文字目以降は無視されます。
さらに次の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 voltile
do if static while
補足
C言語では、大文字と小文字を区別しますので、「tokyo」、「TOKYO」、そして「toKyO」は、異なる変数名として扱われます。
資料B「2の補数表示」
●扱える数の範囲
8ビットのメモリに整数を格納する場合を例に説明します。まず、簡単に全て正の整数とすると、0から28-1(255)まで、全部で256個の数を表現することができます(図参照)。
そこで、負の数も扱えるように、2の補数表示では、このうち半分を0または正の整数、残り半分を負の整数として表します。
従って、0または正の整数は、0から127まで表すことができます。また負の整数は-1から-128まで表すことができます。
一般的には、nビットの2の補数表示による符号付き整数は、-2n-1から2n-1-1までの整数を表すことができます。
図 各ビットと2進数の対応
●メモリ上での数の表現
2の補数表示で実際に整数をメモリに格納する方法は、次のとおりです。
1)
0から127までの数は符号なし整数と同じ方法でメモリに格納する。
2)
-128から-1までの数は、256を加えて、128から255までの数にして、それを符号なし整数と同じ方法でメモリに格納する。
補足:この規則に従うと負の整数は、最上記のビット、図の8ビットの場合は、8ビット目の値が1となります。
ここで2)について、一般的には、nビットの2の補数表示による場合は、-2n-1から-1までの数に2nを加えて、2n-1から2n-1までの数にし、それを符号なし整数と同じ方法でメモリに格納します。
この規則より、負の整数の各ビットの値を次のように求めることが出来ます。
まず、負符号を付けて正の整数とし、この場合の各ビットの値を求め、次に、各ビットを反転(1は0に、0は1に)したものに1を加えることで得られます。
補足:各ビットを反転することを、1の補数を求めるといいます。Xの1の補数は、~Xと記号では表します。
(証明)
今、負の整数をAとし、規則2)に従ってメモリに格納した整数をA*とします。規則の定義より、二つの整数には、次のような関係が成り立ちます。
A* = A + 256
ここで、(-A)とこの1の補数である~(-A)の和は、各ビットの値が1となることから次の式が成り立ちます。
(-A) + ~(-A) = 255
従って、二つの式をあわせると次のように展開できます。
A* = A + 255 + 1
A* = A + (-A) + ~(-A) + 1
よって、次のとおり、負符号を付けて正の整数にし、この各ビットを反転(1は0に、0は1に)したものに1を加えることで、求めるA*が得られます。
A* = ~(-A) + 1
●便利な性質
2の補数表示を用いることによって、整数の加減乗の計算が便利になります。例えば、二つの正の整数AとBの引き算を行う場合、次のように足し算として計算することができます。
A – B = A + (-B)
計算例
(A – B); A = 6, B = 3
6 : 0 0 0 0 0 1 1 0
+ -3 : 1 1 1 1 1 1 0 1
3 : (1) 0 0 0 0 0 0 1 1
8ビットの場合、8ビットを超えたものは無視されます。
掛け算についても同様に、正の整数の場合と同じように計算できます。従って、符号付き整数での加減乗の計算は、符号なし整数での加法、乗法、そして、符号の反転で計算することができることになります。
資料C「演算子のまとめ」
●演算子
●優先順位表
資料D「記号の読み方」