変数とprintf

値を一時保存する

プログラミングでは変数という機能が頻繁に使用されます。
変数とは、値を一時的に保存しておく「入れ物」のことです。


#include <stdio.h>

int main()
{
    int kazu;
    kazu = 10;
    printf("%d", kazu);
    getchar();
}
10

5行目のint kazu;で、変数の使用を宣言しています。
これは「kazu」という名前の「数値」を入れることができる変数を今から使えるようにします、という意味を持ちます。

次の6行目で、変数「kazu」に実際に数値を入れています。

7、8行目は前ページと同じ、値の画面への表示とプログラムの停止(キーボードの入力待ち)です。
printf関数の引数が変わっているのは後述します。

データ型

変数にはデータ型(型)という概念があります。
変数には値を入れて保存しておくことができますが、そこに入れることのできるデータには制限があります。

例えば、サンプルコードではint型を指定しています。
int型は整数を扱うことができるデータ型です。
整数の値を保存したい場合はint型を使用します。

データ型には例えば以下のようなものがあります。
(C言語で扱えるデータ型の一部です。)

char
整数型、文字を扱うので文字型とも呼ぶ
int
整数型
short
整数型、intより扱える最大値が小さい
long
整数型、intより扱える最大値が大きい
float
小数点型(実数型)
double
小数点型、floatより扱える最大値が大きい

小数点を含む値を使いたい場合はfloat型かdouble型のどちらかを使用せねばなりません。
int型に小数点を含む数値を入れようとすると、期待通りの値になりません。
プログラムの実行自体は可能ですが、バグの原因になります。

データ型についてはデータ型の項で改めて説明します。
とりあえずは「整数はint型が基本」「整数と小数では扱うデータ型が異なる」という二点は覚えておきましょう。

変数の使い方

変数を使用するには、まず目的のデータ型を書き、半角スペースを空け、次に変数名を書きます。


データ型 変数名;

int kazu;
kazu = 10;

変数名は自由に決めることができます。
使用できる文字列は、半角の英数字とアンダースコア(_)です。
ただし変数名の最初に数字は使えないという制限があります。
また、既に存在する変数名や関数名、C言語が使用する一部のキーワードは使用できません。
(使えない単語については予約語を参照)


//OK
int kazu;
int Number0;
int _abc;

//NG
int 0abc;	//先頭に数字はダメ
int a-b;	//「_」以外の記号は使えない
int do;		//「do」は予約語なので使えない

//予約語を含む単語はOK
int does;

変数を用意した後は、値を変数に入れます。
これを代入といいます。
サンプルコードでは、変数kazuに対して「10」という整数を代入しています。

代入は、変数名の後に「=」(イコール)記号を書き、その後に代入したい値を書きます。
変数kazuはint型の変数なので、整数である「10」を代入できます。
これで、変数kazuには10という整数値が保存された状態になります。

変数同士の代入

変数は他の変数からも値を代入することができます。


int a;
int b;

a = 10;
b = a;

変数aとbは両方とも「10」が保存された状態になります。
値はコピーされるので、変数aの中身が空になったりはしません。

変数同士の代入は、互いのデータ型が異なる場合は少しややこしくなります。
これについては別の項で改めて説明します。

変数の中身を書き換える

変数はデータの「入れ物」なので、別のデータを入れ直すこともできます。


#include <stdio.h>

int main()
{
    int kazu;
    kazu = 10;
    printf("%d", kazu);

    printf("\n");

    kazu = 20;
    printf("%d", kazu);
    getchar();
}
10
20

7行目までは最初のサンプルコードと同じです。

11行目では、先ほど「10」を代入した変数kazuに「20」を再度代入しています。
もう一度変数kazuの中身を確認すると、きちんと「20」に変更されていることがわかります。

変数の中身を別の値で置き換えると、最初に変数に保存されていた値は消滅してしまいます。
複数の値を同時に保存しておきたい場合は変数も複数必要となります。

ちなみに9行目では\nという文字列がprintf関数の引数に指定されています。
これは改行コードという特殊な文字列です。
文字列中に半角で「\」記号を書くと、それに続く一文字は特殊な意味を持ちます。
「n」の場合はそこで改行をする、という意味になります。
詳しくはエスケープシーケンス(特殊文字)の項で改めて説明します。

「\」記号は特殊な文字で、環境によっては日本円の円記号(¥)で表示されたり、バックスラッシュ記号(\)として表示されたりします。
(この説明ではどちらも全角文字で表示していますが、本来は半角文字です)

サンプルコードと説明文とで「¥n」「\n」と違う表記になることもありますが、どちらも同じ意味です。

変数の書き方あれこれ

使う前に初期化する

変数から値を取り出すには、その前に必ず何か値を代入しておく必要があります。
以下のコードはエラーとなります。


#include <stdio.h>

int main()
{
    int kazu;
    printf("%d", kazu);
    getchar();
}

5行目で変数kazuを定義していますが、値を代入しないまま6行目で変数の中身を表示しようとしています。
何も入っていない入れ物から値を取り出そうとしているため、このコードはエラーになります。
(内部的には「空」なのではなく、何が入っているか不明な状態。不定と言う)

変数に対して最初に値を代入することを変数の初期化と言います。
変数は初期化して初めて使用することができます。

変数の宣言と初期化

以下のようにすると、変数の宣言と初期化を同時に行うことができます。


#include <stdio.h>

int main()
{
    int kazu = 10;
    printf("%d", kazu);
    getchar();
}

5行目は変数kazuの宣言と値の代入を一度に行っています。
こう書くことで行数の節約になり、見た目にもスッキリします。

厳密には、変数の宣言と同時に「=」記号で値を入れることを初期化と言います。
変数を宣言した行以降で値を入れる処理はただの値の代入となります。

今は気にする必要はありませんが、「初期化時」ならばOKでも「代入時」ではNG、という書き方も存在します。

同じデータ型の変数を同時に複数宣言する

同じデータ型の変数が複数必要になる場合は、以下のように書くことができます。


#include <stdio.h>

int main()
{
    int kazu1 = 10, kazu2 = 20;
    int kazu3, kazu4;
    printf("%d", kazu1);
    getchar();
}

「,」で区切ることで、同じ行で同じデータ型の変数を同時に宣言できます。

上の例では、変数kazu1とkazu2はそれぞれ「10」「20」で初期化された状態になります。
変数kazu3とkazu4は変数の初期化がされていない状態です。

ちなみに複数の変数に一度に値を代入することもできます。


#include <stdio.h>

int main()
{
    int kazu1 = 10, kazu2 = 20;
    int kazu3, kazu4;
    kazu3 = kazu4 = 30;
    printf("%d", kazu3);
    getchar();
}

上の例では、変数kazu3とkazu4には「30」の値が代入されます。

printf関数で変数の中身を表示する

変数に代入した値は、その値を取り出すことができます。
以下のコードは7行目のprintf関数で変数の中身を実際に画面上に表示しています。


#include <stdio.h>

int main()
{
    int kazu;
    kazu = 10;
    printf("%d", kazu);
    getchar();
}
10

このprintf関数は何をしているのか直感的にわかりにくい書き方となっています。

関数の引数は、「,」(カンマ、コンマ)で区切ることで複数を同時に指定することができます。
このprintf関数には、「"%d"」と「kazu」の2つの引数が指定されていることになります。
ひとつ目の引数を第一引数、二つ目の引数を第二引数といいます。
(以降、第三引数、第四引数…となります)

書式指定文字列

このprintf関数の第一引数の文字列は「%d」となっていますが、このプログラムを実行してもコンソール画面には「%d」とは表示されません。
「%d」は、第二引数に指定している変数kazuの中身の整数を表示する、という意味を持っています。
この特殊な文字列を変換指定子といいます。

「printf」は「print(印刷、出版)」と「format(形式)のf」とを合わせた言葉です。
単純に文字を出力するだけでなく、値を指定した形式に沿って表示することができる関数です。

printf関数の第一引数には文字列を指定しなければならない、と決められています。
この文字列に、何をどのような形式で表示するかを記述します。
printf関数の第一引数に指定する文字列を書式指定文字列(書式化文字列)といいます。

書式指定文字列は、変換指定子を含む文字列です。
変換指定子が必要ないならば使用しなくても構いません。


//変換指定子を使わない
//引数はひとつ
printf("ABCDE");

//変換指定子を使う
//引数はふたつ以上
printf("%d", 10);

printf関数の第一引数を書き換えてみる

上のサンプルコードを以下のように書き換えてみます。


#include <stdio.h>

int main()
{
    int kazu;
    kazu = 10;
    printf("変数kazuの中身は[%d]です。", kazu);
    getchar();
}
変数kazuの中身は[10]です。

printf関数の第一引数を書き換えただけで、他はすべて同じです。
「%d」の部分だけが変数kazuの中身に置き換えられているのが分かると思います。

書式指定文字列に半角で「%」記号を書くと、それに続く一文字は変換指定子となり特殊な意味を持ちます。
「d」の場合は、第二引数で指定されている整数型の値に置き換えられる、という意味を持ちます。
(decimal=10進数、の意味)

変換指定子以外の箇所の文字列はそのままの文字列として表示されます。
「kazu」という変数名と同じ文字が書式指定文字列に含まれていますが、これもただの文字として扱われます。

「%d」のほかにも、「%f」で小数型、「%c」でchar型の変数の中身を表示できるなど、様々な変換指定子が用意されています。
(後述)

複数の変数の中身を表示する

変数はプログラム中で何個でも自由に使用できます。
(パソコンの性能限界はありますが)
printf関数は、複数の変数の中身を同時に表示することもできます。


#include <stdio.h>

int main()
{
    int kazu1;
    int kazu2;
    kazu1 = 10;
    kazu2 = 20;
    printf("変数kazu1: %d, 変数kazu2: %d", kazu1, kazu2);
    getchar();
}
変数kazu1: 10, 変数kazu2: 20

書式指定文字列に複数の変換指定子が含まれる場合、その箇所は第二引数の中身、第三引数の中身…と順番に置き換えられます。

変換指定子の簡易表

printf関数の書式指定文字列で使用できる変換指定子の一部を掲載します。
意味の分からない用語がいくつかあると思うので、とりあえず目を通すくらいで構いません。

%d、%i
10進符号付き整数
%u
10進符号なし整数
%o
8進符号なし整数
%x、%X
16進符号なし整数
(%Xはアルファベットを大文字で出力する)
%e、%E
指数形式小数点数
(%Eはアルファベットを大文字で出力する)
%f、%F
小数点数
(%Fはアルファベットを大文字で出力する)
%a、%A
16進小数点数
(%Aはアルファベットを大文字で出力する)
%c
文字
%s
文字列
%p
ポインタ
%%
「%」を出力する

printf関数の書式指定文字列はかなり複雑です。
ここではごく基本的な使用方法を解説しました。
(このページで説明していない機能はまだたくさんあります)

しっかりとしたコンソールアプリケーションを開発するならprintf関数の使い方はマスターすべきだと思いますが、ウィンドウアプリが全盛の今ではそこまで深く理解する必要はありません。


#include <stdio.h>

int main()
{
	int num = 123;
	double real = 45.6;

	printf("%d", num);
	printf("\n");
	printf("%f", real);
	getchar();
}
123
45.600000

「%」記号を表示する

printf関数で画面に「%」記号を表示するには「%%」と連続で%記号を書きます。
つまり、


printf("変数kazuの中身は[%%d]です。", kazu);

上のように書き換えてコードを実行すると、以下のように「%d」を画面に表示できます。

変数kazuの中身は[%d]です。

書式指定文字列に第二引数を表示するための指定が含まれていないので、変数kazuの中身は表示できなくなっています。

「\」記号を表示する

同じように、文字列中で「\」記号を表示したい場合は「\\」と連続して\記号を書きます。


printf("改行\nされます\n");
printf("改行\\nされません");
改行
されます
改行¥nされません

最初のprintf関数では途中と行末の二か所で改行されています。
次のprintf関数では\記号が二つ連続していますので、二つ目の\記号はただの文字と判断されます。

「%」記号は特殊な意味を持ちますが、これはprintfなどの一部の特殊な関数だけの話です。
一方で「\」記号は文字列全般で特殊な意味を持ちます。

このページのまとめ

  • 値を一時的に保存するには変数を使う
  • 変数に値を保存することを代入という
  • 変数には「データ型」がある
  • データ型には整数型や文字型などがあり、用途によって使い分ける
  • printf関数はいろいろな書き方があるが、全部を覚える必要はない
  • 文字列中で改行する場合は「\n」を使う