コンテンツにスキップ

第2章:演算と型

はじめに

もしも「身長と体重を教えてください。」と尋ねられて、「身長は175cmで体重は62kgです。」と答えたとする。しかし、それは嘘(?)である。身長が175cmピッタリということは、まずあり得ない。身長計で計って、175.3cmであったとしても、これも本当の値ではないだろう。真の値は、おそらく175.2869758…cmといった値のはずである(しかも時間の経過とともに刻一刻と変化するだろう)。

でも、通常は「身長は175cmで体重は62kgです。」で十分である。誰も真に正確な値を知る必要がないのだから。

プログラムの世界でも同じである。現実の値を必ずしも正確に表す必要はない。

この章では、C言語で数値を扱うために最低限の知識といえる、演算と型の基本について学習する。

2-1 演算

加算を行う+や、乗算を行う*などの記号は、演算子と呼ばれる。本節では、基本的な演算子を学習していく。

演算子とオペランド

前章では、加算と減算と乗算を行った。今度は、除算(割り算)もやってみる。

二つの整数値を読み込んで、その和・差・積・商・剰余を表示する。

プログラムをList 2-1に示す。

// 二つの整数値の和・差・積・商・剰余を表示
#include <stdio.h>

int main(void)
{
    int x, y;

    puts("二つの整数を入力せよ。");
    printf("整数x:");   scanf("%d", &x);
    printf("整数y:");   scanf("%d", &y);

    printf("x + y = %d\n", x + y);    // 和
    printf("x - y = %d\n", x - y);    // 差
    printf("x * y = %d\n", x * y);    // 積
    printf("x / y = %d\n", x / y);    // 商
    printf("x %% y = %d\n", x % y);    // 剰余

    return 0;
}

実行例

二つの整数を入力せよ。
整数x:57
整数y:21
x + y = 78
x - y = 36
x * y = 1197
x / y = 2
x % y = 15

注意

書式文字列内に%を2個並べると1個の%が表示される

演算を行う+や*などの記号は演算子(operator)と呼ばれ、演算の対象となる変数や定数はオペランド(operand)と呼ばれる(Fig.2-1)。

たとえば、和を求めるx + yでは、演算子は+で、そのオペランドがxとyである。

各オペランドは、次のように呼ばれる。 - 左側のオペランド:第1オペランド/左オペランド - 右側のオペランド:第2オペランド/右オペランド

Fig.2-1 演算子とオペランド

Fig2-1

C言語には数多くの演算子がある。全演算子の一覧表はp.221に示している。

なお、本プログラムでのx - yは、xからyを減じた値を求めるものであり、必ずしも差を求めるわけではない(xよりもyのほうが大きければ、x - yは負の値となる)。差を求めるプログラムは、次章のList 3-16(p.59)で学習する。

乗除演算子と加減演算子

本プログラムで使った5個の演算子は、Table 2-1の乗除演算子(multiplicative operator)とTable 2-2の加減演算子(additive operator)とに大別される。

Table 2-1 乗除演算子

演算子 記法 説明
2項*演算子 a * b aとbの積。
/演算子 a / b aをbで割った商(整数どうしの場合は小数点以下は切捨て)。
%演算子 a % b aをbで割った剰余(aとbは整数でなければならない)。

Table 2-2 加減演算子

演算子 記法 説明
2項+演算子 a + b aとbの和。
2項-演算子 a - b aからbを引いた値。

除算の商と剰余

除算を行う演算子は、2種類ある。

  • /演算子 ... 商を求める

商を求めるのが/演算子である。整数どうしを対象とした

整数 / 整数 商の整数部

では、商の整数部(小数部は切捨て)が得られる。たとえば、5 / 3は1で、3 / 5は0である。

  • %演算子 ... 剰余(あまり)を求める

剰余を求めるのが%演算子であり、オペランドは両方とも整数でなければならない。

整数 % 整数 剰余

では、剰余が整数として得られる。たとえば、5 % 3は2で、3 % 5は3である。

これら二つの演算子については、次ページのColumn 2-1で学習する。

printf関数での%文字の表示

剰余の表示を行う箇所では、書式文字列中に%%と書かれている。

書式文字列中の文字%は、変換指定の開始文字である。そのため、書式指定を行うのではなく、本当に%と表示したい場合は、%%と表記することになっている。

書式指定の機能をもたないputs関数による表示では、%%としてはいけない(%%と表示されてしまう:"chap02/percent.c")。

puts("%");      // 1個の%を表示して改行
printf("%%\n");  // 1個の%を表示して改行

最下位桁の値を求める

剰余を求める%演算子をうまく使って、次の問題を解いてみる。

読み込んだ整数値の最下位桁の数字を表示する。

プログラムをList 2-2に示す。

// 読み込んだ整数値の最下位桁の数字を表示
#include <stdio.h>

int main(void)
{
    int no;

    printf("整数を入力せよ:");
    scanf("%d", &no);    // 整数値を読み込む

    printf("最下位桁は%dです。\n", no % 10);

    return 0;
}

実行例

① 整数を入力せよ:1357
  最下位桁は7です。
② 整数を入力せよ:1780
  最下位桁は0です。

整数値noの最下位桁を、noを10で割った剰余として求めている。

演習2-1

右に示すように、二つの整数値を読み込んで、前者の値が後者の何%であるかを表示するプログラムを作成せよ。

二つの整数を入力せよ。
整数x:54
整数y:84
xの値はyの64%です。

Column 2-1 除算の演算結果

第2版以降の標準Cでは、除算を行う二つの演算子の演算結果は、次のように定義されている。

/演算子 ... 代数的な商から小数部を切り捨てた値。 %演算子 ... (a / b) * b + a % bがaと等しくなる値。

この定義を読むだけでは、特にオペランドが負の場合の結果は把握しづらいかもしれない。 Table 2C-1に、オペランドの符号ごとの具体例を示しているので、この表を参考にするとよい。

Table 2C-1 除算の演算結果の一例

x / y x % y
正 ÷ 正 例:x = 22でy = 5 4
負 ÷ 負 例:x = -22でy = -5 4
正 ÷ 負 例:x = 22でy = -5 -4
負 ÷ 正 例:x = -22でy = 5 -4

注意

第2オペランドが0の場合、両演算子の挙動がどうなるのかは、言語では定義されていない(多くの場合、プログラムの実行が中断する)。

複数の変換指定

次は、二つの整数値を読み込んで、商と剰余を表示するList 2-3を理解してみよう。

// 二つの整数値を読み込んで商と剰余を表示
#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数a:");    scanf("%d", &a);
    printf("整数b:");    scanf("%d", &b);

    printf("aをbで割ると%dあまり%dです。\n", a / b, a % b);

    return 0;
}

実行例

二つの整数を入力せよ。
整数a:57
整数b:21
aをbで割ると2あまり15です。

演算結果を表示する書式文字列に、変換指定%dが2個置かれている。Fig.2-2に示すように、先頭側から順に、第2実引数と第3実引数に対応する。

Fig.2-2 printf関数で二つの値を書式化して表示

Fig2-2

Note

もちろん、実引数と一対一で対応するのであれば、変換指定は3個以上あっても構わない。

なお、scanf関数による読込みでも、変換指定を2個以上置くことができる。

Tip

たとえば、本プログラムを次のように変更すると、変数aとbへの整数値の読込みを一度に指示できる("chap02/list203a.c")。

puts("二つの整数を入力せよ。");
scanf("%d%d", &a, &b);
入力時は、二つの整数の区切りとして、スペース、タブ、改行のいずれかを入れる必要がある。

演習2-2

右に示すように、二つの整数値を読み込んで、その和と積を表示するプログラムを作成せよ。

二つの整数を入力せよ。
整数a:54
整数b:12
それらの和は66で積は648です。

単項の算術演算子

次の問題を考えてみよう。

読み込んだ整数値と、その符号を反転した値を表示する。

たとえば、7と入力されたら7と-7を表示して、-6と入力されたら-6と6を表示する。そのプログラムがList 2-4である。

// 読み込んだ整数値の符号を反転した値を表示
#include <stdio.h>

int main(void)
{
    int num;

    printf("整数を入力せよ:");
    scanf("%d", &num);    // 整数値を読み込む

    printf("%dの符号を反転した値は%dです。\n", +num, -num);  // 単項演算子

    return 0;
}

実行例

① 整数を入力せよ:7
  7の符号を反転した値は-7です。
② 整数を入力せよ:-6
  -6の符号を反転した値は6です。

これまで利用してきた演算子のオペランドは2個であった。そのような演算子は、2項演算子(binary operator)と呼ばれる(Fig.2-3)。

その他に、オペランドを1個だけ必要とする単項演算子(unary operator)と、3個のオペランドを必要とする3項演算子(ternary operator)がある。

Fig.2-3 2項演算子と単項演算子

Fig2-3

本プログラムで使っているのは、Table 2-3に示す単項+演算子(unary + operator)と単項-演算子(unary - operator)である。

Table 2-3 単項+演算子と単項-演算子

演算子 記法 説明
単項+演算子 +a aの値。
単項-演算子 -a aの符号を反転した値。

Note

演算子+と-は、いずれも、2項版と単項版の2種類があることが分かった。

Tip

単項+演算子は、実質的には演算を行わない。そのため、プログラム水色部分の+numから+を取り除いて、単なるnumとしても動作は同じである("chap02/list204a.c")。

もう一つの単項-演算子は、オペランドの符号を反転した値を生成する。

なお、単項+演算子、単項-演算子、!演算子(p.77)、~演算子(p.202)の四つの演算子の総称が、単項算術演算子(unary arithmetic operator)である。

代入演算子

これまでのいくつかのプログラムでは、Table 2-4の単純代入演算子(simple assignment operator)と呼ばれる=演算子を利用した。

演算子の名称が長いため、一般には、代入演算子と呼ばれる。

オペランドが2個であるから、代入演算子は、2項演算子である。

Table 2-4 単純代入演算子

演算子 記法 説明
単純代入演算子 a = b bをaに代入。

式と代入式

変数や定数、さらに、それらを演算子で結合したものを、式(expression)と呼ぶ。

Example

たとえば、

x + 32    加算を行う式

では、x、32、x + 32 のいずれもが式とみなせる。また、

a = b - 5   代入式

では、a、b、5、b - 5、a = b - 5 のいずれもが式とみなせる。

代入演算子=に着目すると、aが左オペランドであって、b - 5が右オペランドである。

一般に、○○演算子を用いた式のことを、○○式と呼ぶ。そのため、代入演算子を用いた式は、代入式(assignment expression)と呼ばれる。

式文

既に学習したように、原則として、文の末尾はセミコロン;である。そのため、先ほど示した代入式は、次の形となって、初めて正しい文となる。

a = b - 5;   式文(式の後ろにセミコロン)

このように、式の後ろにセミコロン;を置いた文は、式文(expression statement)と呼ばれる。

式文に関しては、第4章(p.101)でより詳しく学習する。なお、次章以降では、if文やwhile文など、いろいろな種類の文を学習していく。

2-2 型

これまで利用してきたint型は、整数だけを取り扱う型であった。int型以外にも多くの型が提供される。本節では、実数を取り扱うdouble型や演算と型の関係などを学習する。

整数型と浮動小数点型

次の問題を考えてみよう。

二つの整数値を読み込んで、その平均値を求める。

そのプログラムをList 2-5に示す。

// 二つの整数値を読み込んで平均値を表示
#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数a:");    scanf("%d", &a);
    printf("整数b:");    scanf("%d", &b);

    printf("それらの平均は%dです。\n", (a + b) / 2);

    return 0;
}

実行例

二つの整数を入力せよ。
整数a:41
整数b:44
それらの平均は42です。

式a + bを囲む()は、演算を優先的に行うために置かれた記号である(Fig.2-4 a)。

もし、図bのように、a + b / 2となっていれば、『a』と『b / 2』の和が求められる。日常の計算と同じで、加減算よりも、乗除算のほうが優先されるからである。

Fig.2-4 ()による演算順序の変更

Fig2-4

すべての演算子と、その優先順位は、Table 7-13(p.221)にまとめている。

プログラムを実行して41と44を入力すると、平均値は42.5ではなく42と表示される。

Note

小数部が切り捨てられるのは、整数しか扱えないintという型(type)の性質である。

C言語では、実数を浮動小数点数(floating point number)という形式で表す。その型には3種類あるが、本節で学習するのは、double型である。まずは、整数のint型と浮動小数点数のdouble型との違いをList 2-6のプログラムで確認してみよう。

// 整数と浮動小数点数
#include <stdio.h>

int main(void)
{
    int n;      // 整数
    double x;   // 浮動小数点数

    n = 9.99;
    x = 9.99;

    printf("int  型変数 nの値:%d\n", n);         // 9
    printf("        n / 2:%d\n", n / 2);       // 9 / 2

    printf("double型変数 xの値:%f\n", x);         // 9.99
    printf("        x /2.0:%f\n", x / 2.0);    // 9.99 / 2.0

    return 0;
}

実行結果

int   型変数 nの値:9
         n / 2:4
double型変数 xの値:9.990000
         x/2.0:4.995000

最初にint型の変数nと、double型の変数xを宣言して、それから両方の変数に9.99を代入している。同じように見える代入も、まったく違った働きをする(Fig.2-5)。

Fig.2-5 整数と浮動小数点数

Fig2-5

  • int型変数nに対する代入

!!! note int型変数に実数値を代入する際は、小数部が切り捨てられる。そのため、nに格納される値は9である。

  もちろん、n / 2すなわち9 / 2は、『整数 / 整数』という整数どうしの演算であるから、その結果も小数部が切り捨てられた4となる。
  • double型変数xに対する代入

!!! note double型の変数xは実数値を表現できるので、格納される値は9.99である。

  それを2.0で割るx / 2.0の演算結果は4.995となる。

Tip

なお、printf関数でdouble型の値を表示するための変換指定は、%dではなく%fである。

変換指定%fのfは、浮動小数点floatingの頭文字である。小数点以下の部分が6桁表示されるが、この桁数は変更できる(p.38で学習する)。

型とオブジェクト

型と変数について、学習を進めていこう。Fig.2-6をご覧いただきたい。

Fig.2-6 型とオブジェクト

Fig2-6

この図では、int型とdouble型を点線の箱で表し、それらの型をもつ変数nと変数xを実線の箱で表している(変数の箱の大きさは、型の箱と同じである)。

int型の変数は、整数のみを表現でき、double型変数は、小数部をもつ実数値を表現できることは既に確認した。実は、表現できる値の範囲も型に依存する。たとえば、int型で確実に表現できる値は、-32767から32767までである(p.188)。

このように、各型には固有の性質がある。その性質をそっくり受け継いで作られた変数を表す専門用語が、オブジェクト(object)である。

重要

型は、その諸性質を内に秘めた設計図であり、オブジェクト(変数)は、設計図である型をもとに作られた実体である。

Example

たとえると、型はタコ焼きの力タで、カタから作られた本物のタコ焼きがオブジェクトである。

なお、オブジェクトよりも変数のほうが、一般的であって柔らかい感じである。本書では、厳密さが要求されない文脈では、オブジェクトではなく、変数という用語を使っていく。

型と定数

変数だけでなく、プログラムに埋め込まれた定数にも型がある(Fig.2-7)。

Fig.2-7 定数と型

Fig2-7

  • 整数定数(integer constant) 5や37などである。基本的にint型となる。

  • 浮動小数点定数(floating constant) 3.14や2.0などである。基本的にdouble型となる。

定数の型は、値の大きさや特別な指示によって、変わる。

詳細は第7章で学習する。

double型の演算

本章の冒頭で作ったList 2-1は、二つの整数値の加減乗除の結果を求めるプログラムであった。これを実数値に書きかえたのが、List 2-7のプログラムである。

// 二つの実数値の和・差・積・商を実数で表示
#include <stdio.h>

int main(void)
{
    double x, y;    // 浮動小数点数

    puts("二つの実数を入力せよ。");
    printf("実数x:");    scanf("%lf", &x);
    printf("実数y:");    scanf("%lf", &y);

    printf("x + y = %f\n", x + y);    // 和
    printf("x - y = %f\n", x - y);    // 差
    printf("x * y = %f\n", x * y);    // 積
    printf("x / y = %f\n", x / y);    // 商

    return 0;
}

実行例

二つの実数を入力せよ。
実数x:45.77
実数y:35.3
x + y = 81.070000
x - y = 10.470000
x * y = 1615.681000
x / y = 1.296601

まずは、キーボードからの実数値の読込みに着目する。Table 2-5にまとめているように、double型の変数に実数値を読み込む際にscanf関数に与える変換指定は%lfである。

Info

ℓは小文字のエルである(数字の1ではない)。

Table 2-5 変換指定の使い分け

10進数のint型 double型
scanf関数による読込み scanf("%d", &n); scanf("%lf", &x);
printf関数による表示 printf("%d", n); printf("%f", x);

本来は"%F"であるが、現在では"%lf"も許容される

次は、加減乗除の演算である。List 2-1では、和・差・積・商・剰余の五つの値を求めていたが、本プログラムでは剰余が求められていない。

Table 2-1(p.25)に示すように、剰余を求める%演算子は、その性格上、整数どうしの演算でのみ使えて、浮動小数点数の演算では使えない。そのため、本プログラムに

printf("x %% y = %f\n", x % y);

を追加すると、コンパイル・実行が行えなくなる("chap02/list207x.c")。

重要

剰余を求める%演算子は、整数型のオペランドにのみ適用できる。

型と演算

ここまでの学習で、『整数 / 整数』の演算では、小数部を切り捨てた整数値が得られ、浮動小数点数どうしの演算では、切り捨てが行われずに実数値が得られることが分かった。

それらの演算の様子を図にしたのが、Fig.2-8の図aと図bである。

Fig.2-8 オペランドの型と演算結果

Fig2-8

『int / int』や『double / double』といった、両方のオペランドの型が同一であれば、得られる演算結果は演算対象のオペランドと同じ型である。

重要

オペランドの型が同一であれば、得られる演算結果も同じ型となる。

それでは、二つのオペランドの型が異なっていたら、どうなるであろうか。

図cと図dは、次のことを示している。

『double / int』と『int / double』の演算では、int型のオペランドの値がdouble型に格上げされるという暗黙の型変換が行われた上で、double型どうしの演算として行われる。

図cではint型の2がdouble型の2.0へと格上げされ、図dではint型の15がdouble型の15.0へと格上げされている。

両方のオペランドがdouble型となるわけであるから、当然、その演算結果もdouble型となる。

もちろん、ここに示した規則は、/だけでなく、+や*などの演算にも適用される。

C言語には、たくさんの型があるので、細かい規則は複雑である。

詳しい規則はp.222で学習するので、それまでは、次のように理解しておくとよい。

重要

演算の対象となるオペランドの型が異なるとき、小さいほうの型のオペランドは、より大きくて懐の深いほうの型に変換された上で演算が行われる。

Note

ここで、"大きく"という表現を使っているが、必ずしもdouble型が、物理的にint型より大きいわけではない。小数部を格納する"余裕がある"という意味である。

型と演算の確認

ここで学習した規則を、List 2-8のプログラムで確認してみよう。

// 型と演算の確認
#include <stdio.h>

int main(void)
{
    int   n1, n2, n3, n4;  // 整数
    double d1, d2, d3, d4;  // 浮動小数点数

    n1 = 15   / 2;         // n1 ← 7(代入時に小数部を切捨て)
    n2 = 15.0 / 2.0;       // n2 ← 7.5(代入時に小数部を切捨て)
    n3 = 15.0 / 2;         // n3 ← 7.5(代入時に小数部を切捨て)
    n4 = 15   / 2.0;       // n4 ← 7.5(代入時に小数部を切捨て)

    d1 = 15   / 2;         // d1 ← 7
    d2 = 15.0 / 2.0;       // d2 ← 7.5
    d3 = 15.0 / 2;         // d3 ← 7.5
    d4 = 15   / 2.0;       // d4 ← 7.5

    printf("n1 = %d\n", n1);
    printf("n2 = %d\n", n2);
    printf("n3 = %d\n", n3);
    printf("n4 = %d\n\n", n4);

    printf("d1 = %f\n", d1);
    printf("d2 = %f\n", d2);
    printf("d3 = %f\n", d3);
    printf("d4 = %f\n", d4);

    return 0;
}

実行結果

n1 = 7
n2 = 7
n3 = 7
n4 = 7

d1 = 7.000000
d2 = 7.500000
d3 = 7.500000
d4 = 7.500000

本プログラムで行われている代入は、次のようになっている。

  • int型変数n1~n4への代入

Note

int型の変数n1には7が代入され、n2とn3とn4には7.5が代入される。もっとも、代入時に小数部が切り捨てられるので、四つの変数はすべて7となる。

  • double型変数d1~d4への代入

Note

double型の変数d1には7が代入される(ただし、d1の型がdouble型であるから、7は実数の7.0と解釈される)。d2とd3とd4には7.5が代入される。

演習2-3

右に示すように、読み込んだ実数値をそのまま表示するプログラムを作成せよ。

実数を入力せよ:57.3
あなたは57.300000と入力しましたね。

演習2-4

整数定数、浮動小数点定数、int型の変数、double型の変数を、掛けたり割ったりするなど、いろいろな演算を行うプログラムを作成し、本文に示した規則を確認せよ。

キャスト

List 2-5(p.30)のプログラムは、二つの整数値の平均値の整数部を求めて表示するものであった。今度は、小数部を切り捨てることなく求めて表示するようにしよう。List 2-9に示すのが、そのプログラムである。

// 二つの整数値を読み込んで平均値を実数で表示
#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数a:");    scanf("%d", &a);
    printf("整数b:");    scanf("%d", &b);

    printf("それらの平均は%fです。\n", (a + b) / 2.0);

    return 0;
}

実行例

二つの整数を入力せよ。
整数a:41
整数b:44
それらの平均は42.500000です。

平均を求める赤い式に着目しよう。

最初に行われる演算は、()で囲まれたa + bである。この演算は、『int + int』であって、その演算結果もint型である。そのため、この式の演算は、次のように行われる。

int / double   整数を実数で割る

この演算で得られる結果はdouble型である。プログラムを実行すると、41と44の平均値が42.5として求められて表示される。これで、うまくいった。

*

Tip

さて、私たちが平均を求めるときは、「2.0で割ろう。」と考えるのではなく、「2で割ろう。」と考えるのが普通である。

二つの整数の和をいったん実数に変換し、それを2で割ることによって平均値を求めるように変更しよう。それが、List 2-10のプログラムである。

// 二つの整数値を読み込んで平均値を実数で表示(キャストを利用)
printf("それらの平均は%fです。\n", (double)(a + b) / 2);    // キャスト

変更された赤い式に着目しよう。演算子/の左オペランド(double)(a + b)は、初登場の形式であり、次の形をしている。

(型)式   キャスト式

これは、式の値をもとにして、「()の中に指定された型としての値」を生成する式である。

Example

次に示すのが、具体例である。

(int)5.7 ... 浮動小数点定数5.7から小数部を切り捨てたint型の5を生成。 (double)5 ... 整数定数5からdouble型の5.0を生成。

これらの式のイメージを図で表したものを、Fig.3-7(p.55)に示している。

このような、明示的な型変換はキャスト(cast)と呼ばれる。Table 2-6に示すように、()の名称はキャスト演算子(cast operator)である。

Table 2-6 キャスト演算子

演算子 記法 説明
キャスト演算子 (型名)a aの値を型名で指定された型の値に変換したものを生成。

Info

英語のcastは数多くの意味をもつ語句である。他動詞のcastには、「役を割り当てる」「投げかける」「ひっくり返す」「計算する」「曲げる」「ねじる」などの意味がある。

Note

なお、()は、優先的に演算を行うための区切り子(p.109)、関数呼出し演算子(p.146)など、いろいろな顔をもっている(文脈によって働きが異なるわけである)。

それでは、本プログラムのキャスト式を理解しよう(aが41でbが44であるとする)。

Fig.2-9 キャスト式の値

Fig2-9

Fig.2-9に示すように、a + bの演算結果は、int型の85である。その整数値をdouble型にキャストするキャスト式(double)(a + b)の演算結果は、double型の85.0である。

そのため、平均を求める演算は、次のように行われることになる。

double / int   実数を整数で割る

右オペランドのintがdoubleに格上げされた上で、『double / double』という演算が行われる。得られる演算結果は、double型の実数である。

演習2-5

右に示すように、二つの整数値を読み込んで、前者の値が後者の何%であるかを実数で表示するプログラムを作成せよ。

二つの整数を入力せよ。
整数a:54
整数b:84
aの値はbの64.285714%です。

変換指定

次は、合計値と平均値の対象を2値ではなく3値にしよう。List 2-11に示すのが、そのプログラムである。前のプログラムと同様、キャスト演算子を使って平均を求めている。

// 三つの整数値を読み込んで合計値と平均値を表示
#include <stdio.h>

int main(void)
{
    int a, b, c;

    puts("三つの整数を入力せよ。");
    printf("整数a:");    scanf("%d", &a);
    printf("整数b:");    scanf("%d", &b);
    printf("整数c:");    scanf("%d", &c);

    int sum = a + b + c;          // 合計値
    double ave = (double)sum / 3;  // 平均値(キャスト式で求める)

    printf("それらの合計は%5dです。\n",  sum);    // 99999形式で出力
    printf("それらの平均は%5.1fです。\n", ave);    // 999.9形式で出力

    return 0;
}

実行例

三つの整数を入力せよ。
整数a:87
整数b:45
整数c:59
それらの合計は  191です。
それらの平均は 63.7です。

さて、printf関数に渡している書式文字列中の変換指定%5dと%5.1fは、初めての形式である。それぞれが、次の指示を行っている。

%5d ... 整数を少なくとも5桁の10進数で表示。 %5.1f ... 浮動小数点数を少なくとも5桁で表示。ただし、小数点以下は1桁。

Fig.2-10 変換指定の構造

Fig2-10

Fig.2-10に示すのが、変換指定の構造である。

図に示すように、変換指定は、%を含めて、5個のパーツで構成されている。

右ページのList 2-12と、その実行結果を対比しながら、各パーツの意味を理解していこう。

List 2-12

// 整数と浮動小数点数を書式化して表示
#include <stdio.h>

int main(void)
{
    printf("[%d]\n",     123);
    printf("[%.4d]\n",    123);
    printf("[%4d]\n",     123);
    printf("[%04d]\n",    123);
    printf("[%-4d]\n\n",  123);

    printf("[%d]\n",      12345);
    printf("[%.3d]\n",    12345);
    printf("[%3d]\n",     12345);
    printf("[%03d]\n",    12345);
    printf("[%-3d]\n\n",  12345);

    printf("[%f]\n",      123.13);
    printf("[%.1f]\n",    123.13);
    printf("[%6.1f]\n\n", 123.13);

    printf("[%f]\n",      123.13);
    printf("[%.1f]\n",    123.13);
    printf("[%4.1f]\n\n", 123.13);

    return 0;
}

実行結果

[123]
[0123]
[ 123]
[0123]
[123 ]

[12345]
[12345]
[12345]
[12345]
[12345]

[123.130000]
[123.1]
[ 123.1]

[123.130000]
[123.1]
[123.1]

Note

なお、-4のように、フラグに-が指定されている場合は左側にふせて表示され、指定がない場合は右側にふせられる。

A フラグ

0が指定されていると、数値の前に余白があるときに、0をつめて表示する。なお、このフラグを省略した場合は、空白がつめられる。

B 最小フィールド幅

最低限の表示文字数の指定である。少なくとも、この桁数だけの表示が行われる。この指定が省略された場合や、実際に表示する数値が指定された値を超えるときは、その数値を表示するのに必要な桁数で表示される。

C 精度

表示する最小の桁数の指定である。省略すると、整数の精度は1とみなされ、浮動小数点数の精度は6とみなされる。

D 変換指定子

ここが、もっとも重要な部分である。

d ... int型の整数を10進数で表示することの指定である。 f ... double型の浮動小数点数を10進数で表示することの指定である。

Info

ここに示した変換指定の仕様は、ごく一部である。printf関数に関する詳細は、p.376で学習する。

演習2-6

右に示すように、身長を整数値として読み込んで、標準体重を実数で表示するプログラムを作成せよ。

標準体重は(身長 - 100)* 0.9によって求め、その小数点以下を1桁だけ表示すること。

身長を入力せよ:175
標準体重は67.5です。

まとめ

  • 演算を行うための+や*などの記号は演算子である。演算の対象となるオペランドの個数に応じて、単項演算子、2項演算子、3項演算子の3種類に大別される。

  • 演算子によって優先度が異なる。たとえば、乗除算は加減算よりも優先的に行われる。特定の演算を優先的に実行するには、その演算を()で囲む。

  • 乗除演算子は、三つある。乗算を行う2項*演算子は二つのオペランドの積を求める。除算を行う/演算子は除算の商を求めて、%演算子は剰余を求める。なお、%演算子のオペランドの型は両方とも整数でなければならない。

  • 加減演算子は、加算を行う2項+演算子と、減算を行う2項-演算子の二つである。

  • 単項+演算子はオペランドそのものの値を生成する演算子であり、単項-演算子はオペランドの符号を反転した値を生成する演算子である。

  • 右オペランドの値を左オペランドに代入する=は、(単純)代入演算子と呼ばれる。

  • 変数や定数、さらに、それらを演算子で結合したものが式である。

  • 式の後ろにセミコロンを置いたものが、式文である。

  • "○○演算子"を利用する式は、"○○式"と呼ばれる。たとえば、代入演算子=を利用する式a = bは、代入式である。

  • 型は、その諸性質を内に秘めた設計図(タコ焼きのカタ)であり、オブジェクト(変数)は、設計図である型をもとに作られた実体(カタから作られた本物のタコ焼き)である。

  • 整数型のint型は、整数を表す。小数部をもつ値が代入されても、小数部は切り捨てられる。5や37などの定数は整数定数と呼ばれる。基本的にint型となる。

  • 浮動小数点型のdouble型は、浮動小数点数(小数部をもつ実数値)を表す。3.14や2.0などの小数部をもつ定数は浮動小数点定数と呼ばれる。基本的にdouble型となる。

  • 整数どうしの算術演算の結果は整数であり、浮動小数点数どうしの算術演算の結果は浮動小数点数である。

  • 異なる型のオペランドが混在した演算では、暗黙の型変換が行われる。演算の対象となるオペランドの型が異なるとき、小さいほうの型のオペランドは、より大きくて懐の深いほうの型に変換された上で演算が行われる。そのため、int型とdouble型が混在した演算は、各オペランドがdouble型に変換された上で行われる。

  • ある式の値を、別の型として表現された値に変換するには、キャスト演算子()によるキャスト(型変換)を行う。たとえば、キャスト式(double)5は、int型の整数定数の値5をdouble型に変換した値5.0を生成する。

  • double型の値をprintf関数で表示する際の変換指定が%fであるのに対し、scanf関数で読み込む際の変換指定は%lfである。

  • printf関数やscanf関数に与える書式文字列には、複数の変換指定を置ける。各変換指定は、先頭から順に、第2実引数、第3実引数、…に対応する。

  • printf関数で%文字を表示するには、書式文字列中に%%と書かなければならない。

  • 変換指定は、0フラグ、最小フィールド幅、精度、変換指定子などで構成される。

Fig2-11

演習問題

  1. BMI計算プログラム
  2. 整数の割合計算(キャスト式使用)
  3. 円の面積と周囲長
  4. 温度変換プログラム
  5. 時間の変換(キャスト式使用)

演習問題2-1:BMI計算プログラム

問題の説明

BMI(体格指数)を計算するプログラムを作成してください。プログラムは身長(cm)と体重(kg)をユーザーから入力として受け取り、BMI値を計算して小数点以下1桁まで表示します。BMI計算式は:体重(kg) ÷ (身長(m)の2乗)です。

期待される結果

身長(cm)と体重(kg)を入力してください(例:170 65):170 65
あなたのBMIは22.5です。

ヒント

  1. 身長はセンチメートルからメートルに変換する必要があります。100ではなく100.0で割ることで浮動小数点除算を確保します
  2. scanf()関数は一度に複数の入力値を読み込むことができます。入力時は空白で区切ります
  3. 結果表示時に%.1fを使用すると、小数点以下1桁まで表示できます

演習問題2-2:整数の割合計算(キャスト式使用)

問題の説明

二つの整数a、bを入力として受け取り、aがbの何パーセントであるかを計算して小数点以下1桁まで表示するプログラムを作成してください。計算には明示的な型変換(キャスト式)を使用する必要があります。

期待される結果

整数aとbを入力してください(例:75 120):75 120
aはbの62.5%です。

ヒント

  1. (double)を使用して明示的な型変換を行い、浮動小数点除算を確保します
  2. パーセントを計算する際は100を掛ける必要があります
  3. printfでパーセント記号%を表示するには%%を使用する必要があります

演習問題2-3:円の面積と周囲長

問題の説明

ユーザーが入力した円の半径(実数)を受け取り、円の面積と周囲長を計算して小数点以下2桁まで表示するプログラムを作成してください。円周率として3.14を使用します。

期待される結果

円の半径を入力してください:4.5
半径4.50の円の面積は63.59です。
半径4.50の円の周囲長は28.26です。

ヒント

  1. const double PI = 3.14で定数を定義すると、コードの可読性が向上します
  2. 浮動小数点入力には、scanfで%lfの書式指定子を使用します
  3. %.2fの書式を使用して小数点以下2桁まで表示します

演習問題2-4:温度変換プログラム

問題の説明

ユーザーから摂氏温度と華氏温度を入力として受け取り、摂氏温度を華氏温度に、華氏温度を摂氏温度に変換するプログラムを作成してください。変換式は: - 華氏 = 摂氏 × 9/5 + 32 - 摂氏 = (華氏 - 32) × 5/9 結果は小数点以下1桁まで表示します。

期待される結果

摂氏温度と華氏温度をカンマ区切りで入力してください(例:25,98.6):25,98.6
25.0°Cは77.0°Fです。
98.6°Fは37.0°Cです。

ヒント

  1. 数学計算では9.05.0など小数点付きの数値を使用して、浮動小数点計算を確保します
  2. 温度変換式の演算順序は重要です。必要に応じて括弧を使用して優先順位を明確にします
  3. 特殊文字°の使用に注意してください
  4. scanfでの入力値区切りにはカンマ(,)を使用します。フォーマット指定子は%lf,%lfとなります

演習問題2-5:時間の変換(キャスト式使用)

問題の説明

カンマ区切りで複数の秒数(整数)を入力し、それぞれを「時間:分:秒」形式に変換して表示するプログラムを作成してください。計算過程では型変換を使用する必要があります。

期待される結果

二つの秒数をカンマ区切りで入力してください(例:3665,7200):3665,7200
3665秒は 1時間 1分 5秒 です。
7200秒は 2時間 0分 0秒 です。

ヒント

  1. 整数除算(/)を使用して時間単位を計算し、余り演算(%)を使用して残りの部分を取得します
  2. 計算の順序に注意してください:まず時間を計算し、残りの秒数から分を計算し、最後に秒を計算します
  3. 1時間=3600秒、1分=60秒です
  4. カンマ区切りの入力を受け付けるため、scanf関数のフォーマット指定子は%d,%dとなります
  5. 複数の値を処理する場合は、それぞれの値に対して計算を繰り返す必要があります