C言語超入門② 変数と入力を使おう
int、double、charによる変数宣言と、printf・scanfを使った入力と計算を学びます。
同じ数字を表示するだけだと、まだプログラムという感じがしないかもしれません。入力した値で計算が変わると、ぐっと道具らしくなります。
今回は「2つの数を受け取り、合計を表示する」ところまで進みます。途中で、文字と数の違い、scanfの&、整数の割り算を整理しましょう。
コードはC11以降を想定しています。短いコードは、特に断りがなければ第1回のmainの中へ書きます。#includeから始まる例は、そのまま1本のプログラムです。
1. 変数を作って、値に名前を付ける
int price = 150;
int count = 3;
int total = price * count;
printf("%d\n", total);
結果は450です。priceが価格、countが個数、totalが合計。こうした値の置き場所に付ける名前が変数です。
int price = 150;を3つに分けます。
int:整数を扱う型price:自分で付けた名前= 150:最初の値を150にする初期化
変数を使えるようにするのが宣言、最初の値を決めるのが初期化です。後からprice = 180;と書く操作は代入と呼びます。
=は「右の値を左に入れる」
数学の等号と違い、右側を先に計算します。
int count = 3;
count = count + 1;
printf("%d\n", count);
右側のcount + 1は3 + 1なので4。その4を左側のcountへ入れ、結果は4です。「自分自身に1を足す」と読めば自然ですね。
totalを計算した後でcountを変えても、過去のtotalは自動更新されません。合計も変えたいなら、もう一度計算する必要があります。
2. int・double・charは何が違う?
型は扱うデータの種類です。
| 型 | 今回の用途 | 宣言例 |
|---|---|---|
int |
個数、点数などの整数 | int score = 80; |
double |
長さ、平均など小数を含む数 | double height = 168.5; |
char |
英数字など1バイトの文字コード | char grade = 'A'; |
charを「どんな言語でも1文字」と覚えるのは少し危険です。UTF-8の日本語は、通常1文字に複数バイトを使います。文章は配列と文字列の回で扱います。
'A'はシングルクォーテーション、"A"はダブルクォーテーションです。C言語では、前者は文字定数、後者は終端を持つ文字列で、同じものではありません。
初期化を省くとどうなる?
関数の中でint score;とだけ書いた変数は、0が入るとは限りません。値を設定する前に読み出してはいけません。
int score = 0;のように最初の値を決めておくと、コードを追いやすくなります。ただし、初期化していても入力失敗を無視してよいわけではありません。
3. printfの「%」は表示する場所
#include <stdio.h>
int main(void) {
int age = 18;
double height = 168.5;
char grade = 'A';
printf("age: %d\n", age);
printf("height: %.1f cm\n", height);
printf("grade: %c\n", grade);
return 0;
}
age: 18
height: 168.5 cm
grade: A
%dなどを書式指定子と呼びます。「後ろに渡した値を、どんな形で表示するか」という指定です。
printf("age: %d\n", age);なら、文字列の%dの位置にageの値が入ります。複数の指定子を置く場合は、後ろの値も同じ順番に並べます。
%.1fの.1は小数点以下を1桁で表示する指定。変数そのものを1桁へ変更するわけではありません。
4. scanfで入力する。ただし成功を確かめる
#include <stdio.h>
int main(void) {
int age = 0;
printf("age (0-120): ");
if (scanf("%3d", &age) != 1) {
printf("整数を入力してください。\n");
return 1;
}
if (age < 0 || age > 120) {
printf("0から120の範囲で入力してください。\n");
return 1;
}
printf("来年は%d歳です。\n", age + 1);
return 0;
}
18を入力してEnterを押すと、来年は19歳です。と表示されます。abcなら計算せず終了します。
まだifを習っていないので、ここでは「入力できなかったときに止める確認」と読んでください。次の回で仕組みを学びます。
入力の流れを4段階に分ける
printfで何を入力するか表示するscanfが入力を数として読み取る- 読み取れたら
ageの場所へ書き込む - 成功と範囲を確認してから計算する
scanfの戻り値は、値を代入できた項目の数です。1つの数なら、成功は1。0や入力終端を示す値だったら、そのまま計算へ進みません。
&ageは「書き込み先の場所」
printfには表示する値を渡しますが、scanfには値を書き込む場所を渡します。&ageはageのアドレスです。詳しくはポインタの回へ進んでからで大丈夫です。
scanfは入力を丸ごと検査するわけではない
%3dの3は、読み取る文字数の上限です。この練習では読み取り部分が大きな整数にならないようにしています。通常の%dでは、型の範囲を超える巨大な数を安全に扱えるとは限りません。
また、18abcのような入力では先頭の18だけを数として読める場合があります。後ろの文字は入力側に残ります。今回の例は「指定範囲の整数を1つ入力する」練習用で、厳密な入力検査の完成形ではありません。
1行全部を確認する方法は、最終回でfgetsとstrtolを使って扱います。
5. 入力と表示では、小数の指定が違う
| 扱うもの | printfで表示 | scanfで入力 |
|---|---|---|
int |
%d |
%dとint* |
double |
%f、%.1fなど |
%lfとdouble* |
char |
%c |
%cとchar* |
特にdoubleの入力は%lfです。printfの表だけを見てscanfを書かないようにしましょう。型と書式が合わないと、単なる表示崩れではなく、動作が保証されない場合があります。
scanf("%c", &grade)は改行なども読み取ります。前の入力の改行を飛ばしたい場合の" %c"には先頭に空白があります。今回は数値入力を中心にして、入力方法をむやみに混ぜないようにします。
6. 計算で引っかかりやすい3つの点
+、-、*、/は足し算・引き算・掛け算・割り算、%は整数の余りです。
printf("%d\n", 10 / 3);
printf("%.2f\n", 10.0 / 3);
printf("%d\n", 10 % 3);
結果は順に3、3.33、1です。
割る前に小数へ変える
整数同士の割り算は、0へ近づく向きに小数部分を取り除きます。-7 / 2は-3です。負の数でも、必ず小さい側へ丸めるわけではありません。
double answer = 5 / 2;としても、右側で先に整数の2ができるので2.0になります。2.5が必要なら5.0 / 2とします。
0で割らない
整数の0除算は未定義動作です。未定義動作とは、言語として結果を保証できない処理のこと。「必ずエラーが表示される」とは限らないため、割る前に確認します。
intで無制限の金額は計算できない
intには範囲があります。大きな数の足し算や掛け算で範囲を超えると、符号付き整数では未定義動作になります。練習では小さな値を使い、実用化では入力範囲と計算結果の範囲を設計します。
これらの規則はC11公開委員会草案の6.5.5と7.21.6.2で確認できます。
7. 練習:2つの整数の合計を表示しよう
それぞれ-999から999までの整数を入力し、合計を表示します。abcのように先頭から整数を読み取れなかった場合や、読み取った値が範囲外の場合は終了してください。この小さな範囲なら、C規格が保証するintの範囲内で合計できます。
今回は1回の入力に整数を1つ、余計な文字を付けずに入れる前提です。12abcのような末尾の文字まで検査する課題ではありません。
模範解答
#include <stdio.h>
int main(void) {
int a = 0;
int b = 0;
printf("a (-999 to 999): ");
if (scanf("%4d", &a) != 1 || a < -999 || a > 999) {
printf("aの入力を確認してください。\n");
return 1;
}
printf("b (-999 to 999): ");
if (scanf("%4d", &b) != 1 || b < -999 || b > 999) {
printf("bの入力を確認してください。\n");
return 1;
}
printf("合計は%dです。\n", a + b);
return 0;
}
解説
aに12、bに-5を入力した場合、12 + (-5)で7を表示します。
先に両方を0で初期化し、入力が1項目成功したかをそれぞれ確認しています。||は「または」なので、入力失敗と範囲外のどちらかなら終了します。
%4dは負号を含め最大4文字を読む指定です。この例でも行の末尾までの検査はしていません。余計な文字を断り、入力し直せるようにする段階は成績管理プログラムで学びましょう。
次の一歩
「名前の付いた値を、入力・計算・表示で受け渡す」という流れが見えれば、今回の土台はできています。次はifを使い、受け取った値によって処理を分けます。