View on GitHub

SSR C11 Textbook

変数と型

Back to the ToC


プログラムは,変数(へんすう/variable)と呼ばれるものに値を紐付けることで,簡単にデータを扱えるようにしています. しかしC言語は,気ままに変数を使うことを許してはくれません. 変数を使うためには,必ず宣言 (declaration)と呼ばれる操作をしなければなりません. 本章では,この宣言と呼ばれる操作と,宣言を行うために必要な (かた/type)という概念について学びます.

変数宣言

C言語では, 変数は宣言をしなければ使うことができません. 変数は宣言によって初めて存在することが許されるのです.

宣言には,どのようなデータを格納するのかを示す「型」と「変数の名前」という2つの情報が必要になります. それでは実際に,変数を宣言してみましょう.

int x;  // 宣言:intという型,xという名前

なんと,宣言はこれだけです. ここでは,intという名前の型で,xという名前の変数を使うことを宣言しています. 文末のセミコロン(;)を忘れないようにしてください. 話し言葉では,「int(イント)型のx」と呼びます.

一度宣言をしてしまえば,その変数は,以降のプログラムで使うことが可能になります. 例えば今回の場合,変数xに整数を代入することができるようになります.

#include <stdio.h>
    
int main(void) {
    int x;  // 変数xの宣言
    x = 2;  // 変数xに数値2を代入
    printf("x = %d\n", x);  // xの値を出力
    return 0;
}

このプログラムを実行すると,次のような結果が得られます.

x = 2

それでは次に,悪戯として, 宣言する前の変数へ値を代入をしてみましょう.

#include <stdio.h>

int main(void) {
    x = 0;  // まだ宣言されていない変数xへの代入
    int x;  // 変数xの宣言
    printf("x = %d\n", x);  // xの値を出力
    return 0;
}

このプログラムが実行されることはありません. 「4行目の時点では,xなんて変数はないよ!」という内容のコンパイルエラーが発生することでしょう.

In function ‘main’:
test.c:4:5: error: ‘x’ undeclared (first use in this function)
     x = 0;  // まだ宣言されていない変数xへの代入
     ^
test.c:4:5: note: each undeclared identifier is reported only once for each function it appears in

ここで,プログラムは上から順に実行されるということを覚えておいてください. 今回の例では,「宣言」してから「代入する,という順番を守らなければいけませんでした. プログラムは,内容の順番を入れ替えると,正しく動かなくなることがあるのです.

複数の変数の同時宣言

C11では,使いたい変数が複数あって,それらが同じ型であれば,同時に宣言することができます. 方法は簡単で,変数名をカンマ (,)で区切り,並べるだけです. 実例を見てみましょう.

#include <stdio.h>
    
int main(void) {
    int x, y;  // 変数xと変数yを同時に宣言
    x = 2;     // 変数xに数値2を代入
    y = 3;     // 変数yに数値3を代入
    printf("x = %d, y = %d\n", x, y);  // 値を出力
    return 0;
}

4行目で,int型のxという変数と,同じくint型のyという変数を同時に宣言しています. これは次のような,それぞれを個別に宣言した場合と全く同じです.

#include <stdio.h>
    
int main(void) {
    int x;  // 変数xの宣言
    int y;  // 変数yの宣言
    x = 2;  // 変数xに数値2を代入
    y = 3;  // 変数yに数値3を代入
    printf("x = %d, y = %d\n", x, y);  // 値を出力
    return 0;
}

変数名

変数の名前は,基本的に自由に命名することができます. 変数名には,数字とアルファベット,そしてアンダースコア (_) が利用可能です. (※アンダーバーという呼び方が多く用いられていますが,正式な記号名はアンダースコアと言います.)

ただし,注意点がいくつかあります. 変数名を決めるときは,次のルールを守らなければいけません.

また,次のルールを守ることは,義務ではありませんが,強く推奨されています.

例示すると,以下のような感じです.

int rogiken;    // 可
float a, b_c;   // 可
char _sasori;   // 非推奨
int 2020tokyo;  // 不可
double int;     // 不可

ここで予約語とは,プログラミング言語の機能に関わる文字列で,そもそも利用ができない名前(識別子)となっているものです.

予約語一覧

C11の予約語は計44単語あります:auto , break , case , char , const , continue , default , do , double , else , enum , extern , float , for , goto , if , inline , int , long , register , restrict return , short , signed , sizeof , static , struct , switch , typedef , union , unsigned , void , volatile , while , _Alignas , _Alignof , _Atomic , _Bool , _Complex , _Generic , _Imaginary , _Noreturn , _Static_assert , _Thread_local (アルファベット順).

宣言においては,「型」と呼ばれるものが必要でした. この「型」が,その変数が取り扱うことのできる値の種類を指定します. 「データ型」と呼ばれることもあります. C言語は,静的型付け(せいてきかたづけ/static typing)と呼ばれる型付けを採用しており,変数は宣言時に,予めどのような種類の値を取り扱うのかということが決まっている必要があるのです.

型には実に多くの種類があり,また自ら作ることもできます. ここでは,基本データ型,あるいはプリミティブ型 (primitive data type) と呼ばれる代表的な4つの型を紹介します.

データ型 値の例 最低bit数 必ず取れる値の範囲
char 整数・文字 8bit (1B) -127 ~ 127
int 整数 16bit (2B) -32,767 ~ 32,767
float 実数(単精度) 32bit (4B) ± 1.0 × 10の-37乗 ~ 1.0 × 10の38乗
double 実数(倍精度) 64bit (8B) ± 1.0 × 10の-307乗 ~ 1.0 × 10の308乗

それぞれの型には,どのような情報を,どの範囲で扱うことができるか,という情報が詰められています. char型はこの4つの中では少し特殊で,文字,つまりアルファベットや記号,(文字としての)数字を扱うことができます. しかし難しいことはありません. char型も\texttt{int}型と同様,本質的に扱っているのはただの整数です. 例えば,66という整数に大文字アルファベットのAが対応している,というだけのことです.

ここでの要点は,「変数には型というものがあり,その型に従って値が格納される」ということです.

型の由来と読み方

floatは浮動小数点数の浮動を意味するfloat(ing)に由来し「フロート」と読みます.また,doubleは倍精度を意味するdoubleで,そのまま「ダブル」と読みます. intは整数を意味する英単語のintegerの略で「イント」と読むことがほとんどでしょう. charは文字を意味する英単語characterの略です. 読み方は「チャー」が主流だと思われますが,単語を意識して「キャラ」と読む人も一定数いるようです. どちらの読み方も覚えておくと良いでしょう.

代入

変数を宣言しても,その変数の値は未定義です. 値が未定義というのは,どのような値が入っているかわからない,ということです. 宣言をした変数には必ず,明示的に値を入れてあげる必要があります. この操作を代入 (assignment) と言います.

代入にはイコール (=) を1つだけ使います. 数学での用法と異なり,左辺と右辺の値が等しいことを示すわけではありませんので,注意してください. 例えばx = 3;という文は,「変数xに3という数値を代入する」という操作を意味します. 実際に試してみましょう.

#include <stdio.h>

int main(void) {
    int x;  // ここではxの値は未定義
    printf("1: x = %d\n", x);
    x = 3;  // 値が3に確定
    printf("2: x = %d\n", x);
    x = 5;  // 値を5に上書き
    pritnf("3: x = %d\n", x);
    return 0;
}

代入するまでは値が確定しませんので,1行目の出力にはどのような値が出るかわかりません. 実行毎に違う値が出力されることもあり得ますし,毎回同じ値が出るかもしれません. 要は実行してみないとどうなるかわからないのです. このような動作は未定義動作 (undefined behavior)と呼ばれます. コンパイルエラーにはならない一方で,意図しない不具合(バグ)が生じることがありますから,プログラムを書く上では必ず避けなければいけません.

一部のオンラインコンパイル環境ではサービスの安全のため,必ず0になる場合があります.一般に,PC上で実際に動かす場合はそのようにはなりません.

一度値が代入された変数は,次の代入か,変数の寿命が尽きるまで,変わることはありません. また,後から実行された代入は,過去の代入に関わらず,変数の値を上書きします. よって,先程のプログラムの出力は,次のようになります.

1: x = ?
2: x = 3
3: x = 5

代入するときは,オーバーフローにも気を付けましょう.

初期化

C99以降のC言語では,変数の宣言と代入を同時に行う,初期化 (initialization) と呼ばれる操作が可能になっています. 宣言の際の変数名に,直接代入を行うことで初期化を行えます. 例を見てみましょう.

#include <stdio.h>

int main(void) {
    int x = 1;
    printf("x = %d\n", x);
    return 0;
}

このプログラムは問題なくx = 1を出力します. また,

int a = 1, b = 2;

のように,複数の変数をまとめて初期化することも可能です.

初期化には,宣言をしてから代入をするのと比べて,行数が減るだけでなく,代入忘れをしにくいという,バグを防ぐ上で大切な利点があります. 積極的に使っていきましょう.


Back to the ToC

Previous: プログラムの実行 / Next: 四則演算


(c) 2017-2021 Yuki Onishi