これまで、int型、double型、char型という3種類の変数を使ってきました。

ここでは、変数について、改めてきちんと説明します。

変数名

変数の名前は、下線 _、英大文字 A-Z、英小文字 a-z、数字 0-9 で構成され、先頭は数字以外の文字でなければなりません。大文字と小文字は区別されます。

int, double, char, void, return, if, else, while, for, switch, case, default など、あらかじめ決められているキーワード予約語)と同じ名前を使うことはできません。

習慣的に、C言語では変数名を小文字にします。

基本データ型

char型

char型は、文字を表します。 整数として扱うことができます。

符号付き整数型

これまで使ってきたint型は、符号付きの整数を表します。 符号付きであることは省略できるので、これまでは省略していました。 省略せずに書くと、signed int型です。

int型の記憶容量(サイズ)を基本として、int型より小さいサイズにしたり、大きいサイズにすることができます。

符号付き整数型をサイズの小さい順に並べると、次のようになります。

  • signed char
  • short (signed short)
  • int (signed int)
  • long (long int, signed long int)
  • long long (long long int, signed long long int)

ただし、実際のサイズは実行環境に依存します。 long型とlong long型のサイズが同じという環境もあります。

符号なし整数型

符号なし整数型は、符号付きであることを表すsignedの代わりに、unsignedと書いて表します。

また、C99から、0または1で論理値を表す_Bool型が追加されました。

符号なし整数型をサイズの小さい順に並べると、次のようになります。

  • _Bool
  • unsigned char
  • unsigned short int (unsigned short)
  • unsigned int
  • unsigned long (unsigned long int)
  • unsigned long long (unsigned long long int)

浮動小数点型

double型は、倍精度の浮動小数点数を表します。 浮動小数点数については、計算機アーキテクチャーや数値解析Iの授業できちんと勉強してください。

浮動小数点数型には、double型の半分のサイズのfloat型と、double型よりも大きなサイズのlong double型があります。

(実数を表す)浮動小数点数型をサイズの小さい順に並べると、次のようになります。

  • float
  • double
  • long double

符号付き整数型と符号なし整数型の違い

符号付き整数型では、先頭ビットが符号を表します。 符号なし整数型には、符号を表すビットは存在しません。

このため、符号なし整数型は、符号付き整数型の約2倍の範囲の数を表すことができます。

次のプログラムは、8ビットの大きさの符号付きchar型と符号なしchar型に、8ビット符号なし整数の最大値である255を代入して表示します(プログラム1)。

    signed char sc = 255;
  unsigned char uc = 255;

  printf(">> %d\n", sc);
  printf(">> %d\n", uc);

これを実行すると、次のようになります。

luna% a.out
>> -1
>> 255

255は、2進数で表すと 11111111 ですが、符号付き整数では負の数を2の補数として表現するので、これを2の補数として解釈し、-1 と出力されています。 2の補数については、計算機アーキテクチャーの授業できちんと勉強してください。

また、符号付き整数と符号なし整数では、あとで勉強するシフト演算の振る舞いが異なります。

演習1

プログラム1を作成し、実行結果を確認せよ。

定数

変数がプログラム実行中に変化する可能性がある数であるのに対し、定数はプログラム実行中に変化することがありません。プログラムの中に直接書かれている値も、定数です。

整定数

整定数には、10進数、8進数、16進数があります。

10進数は、0 以外の数字で始まり0 から 9 までの数字だけで表します。 たとえば、10 は、10進数の 10 を表します。 整数をprintf関数を用いて10進数表記で出力するときの変換指定子は %d です。

8進数は、0 で始まり0 から 7 までの数字だけで表します。 たとえば、010 は、8進数の 10 を表し、10進数にすると 8 です。 符号なし整数をprintf関数を用いて8進数表記で出力するときの変換指定子は %o です。

16進数は、0x で始まり0 から 9 までの数字と a から f までの英字だけで表します。 たとえば、0x10は、16進数の 10 を表し、10進数にすると 16 です。 符号なし整数をprintf関数を用いて16進数表記で出力するときの変換指定子は %x です。

  printf("%d\n", 10);
  printf("%d\n", 010);
  printf("%d\n", 0x10);
  printf("%04x\n", 16);
luna% a.out
10
8
16
0010

浮動小数点定数

浮動小数点定数には、10進浮動小数点数、指数表現10進浮動小数点数、指数表現16進浮動小数点数があります。

10進浮動小数点数は、0 以外の数字で始まり、0 から 9 までの数字と小数点だけで表します。 たとえば、1.01 は、10進数の 1.01 を表します。

指数表現10進浮動小数点数は、10進浮動小数点数の後に e と指数部を表す10進数をつけて表します。 たとえば、1.01e2 は、[math]1.01 \times 10^2[/math]で 101、1.01e−2 は、[math]1.01 \times 2^{-2}[/math]で 0.0101 を表します。

指数表現16進浮動小数点数は、0x で始まり、0 から 9 までの数字と a から f までの英字と小数点、その後に p と指数部を表す10進数をつけて表します。 基数は2なので、指数部は2の何乗倍であるかを表します。 たとえば、0x1.01p12 は、16進数 1.01 の2の12乗倍を表し、2進数 0001.0000 0001 を左に12ビットだけシフトしたものなので2進数 0001 0000 0001 0000、10進数にすると 4,102 です。 printf関数で指数表現16進浮動小数点数の形を出力するときの変換指定子は ''

文字定数

文字定数は、シングル・クォーテーションで囲まれた文字です。

英大文字 A-Z、英小文字 a-z、数字 0-9、記号 ! " # % & ( ) * + , - . / : ; < = > ? [ ] ^ { | } ~、または \ で始まるエスケープ・シーケンスのいずれかです。

値を変更できない変数

変数を宣言するときに、型名の前に const を付けて宣言すると、その変数には初期化のときにしか値を代入できなくなり、定数となります。

  printf("%f\n", 1.01);
  printf("%f\n", 1.01e2);
  printf("%f\n", 1.01e-2);
  printf("%f\n", 0x1.01p12);

型が配列でないときは、初期化子を囲む波括弧 { } は省略できます。

習慣的に、C言語では定数名を大文字にします。

変数の有効範囲(スコープ)

変数は、宣言する場所によってその有効範囲が異なります。 変数の有効範囲をスコープといいます。

同じスコープを持つ同じ名前の変数を宣言することはできませんが、 スコープが異なれば同じ名前の変数を宣言することができます。

スコープが異なる同じ名前の変数が宣言されているとき、その変数にアクセスすると、より内側の有効範囲の宣言が優先されます。

ブロック有効範囲

波括弧 { } で囲まれたブロック内で宣言された変数は、ブロック有効範囲の変数となり、宣言したところからそのブロックの終わりまでだけで有効です。

このような変数を、局所変数、’’ローカル変数''といいます。

次のプログラムは、同じ名前で有効範囲の異なるローカル変数を二つ宣言しています(プログラム2)。

1.010000
101.000000
0.010100
4112.000000

このプログラムに登場する変数のスコープを図で表すと、次のようになります。

block_scope.png

このプログラムを実行すると、次のようになります。

  const 型 定数名 = { 初期化子 };

C99では、for文の丸括弧 ( ) の中でも変数を宣言できるようになりました(プログラム3)。

int main(void) {
  int i = 0;
  printf(">> %d\n", i);

  {
    int i = 1;
    printf("## %d\n", i);
  }

  printf(">> %d\n", i);

  return 0;
}

ただし、gccでこのプログラムをコンパルするときには、stdオプションにc99を指定する必要があります。

luna% a.out
>> 0
## 1
>> 0

演習2

プログラム2とプログラム3を作成し、実行結果を確認せよ。

ファイル有効範囲

関数の外で変数を宣言すると、ファイル有効範囲の変数となり、宣言されたところからそのファイルの最後まで全体で有効となります。

このような変数を、大域変数グローバル変数といいます。

次のプログラムは、同じ名前のグローバル変数とローカル変数を宣言しています(プログラム4)。

  for (int i = 0; i < 3; i++) {
    printf(">> %d\n", i);
  }

このプログラムに登場する変数のスコープを図で表すと、次のようになります。

file_scope.png

有効範囲が赤色で示されているものがファイル有効範囲の変数、青色で示されているものがブロック有効範囲の変数です。

このプログラムを実行すると、次のようになります。

luna% gcc -std=c99 hello.c
luna% a.out
>> 0
>> 1
>> 2

演習3

プログラム4を作成し、実行結果を確認せよ。

変数の有効期間(記憶域クラス)

宣言された変数をコンピューター内のどこに記憶するか(記憶域クラス)を、指定することができます。

#include <stdio.h>

int i = 0;

void prt(void) {
  printf("## %d\n", i);
}


void inc(void) {
  i++;
}


int main(void) {
  int i = -1;
  printf(">> %d\n", i);

  prt();
  inc();
  prt();

  printf(">> %d\n", i);

  return 0;
}

変数が記憶される場所としては、メモリー内の静的領域スタック領域ヒープ領域、CPU内のレジスターがあります。 これらの違いについては、計算機アーキテクチャーの授業できちんと勉強してください。

静的記憶域期間

ブロック有効範囲の変数に記憶域クラス指定子として static を指定すると、プログラムの実行開始時に静的領域に記憶域が割り当てられ、プログラム終了時まで保持されます。 初期化は、プログラムの実行開始時に一度しか行われません。 初期化を省略すると、0 に初期化されます。

このような変数を、静的変数といいます。

次のプログラムは、int型の変数 i を静的変数として宣言しています(プログラム5)。

luna% a.out
>> -1
## 0
## 1
>> -1

変数 i は、プログラムの実行開始時にメモリー内の静的領域に記憶され、プログラムの実行終了まで保持されます。 初期化は一度しか行われません。 したがって、このプログラムを実行すると、次のようになります。

  記憶域クラス指定子 型 変数名;

ファイル有効範囲の変数は、静的領域に割り当てられ、静的記憶域期間の変数になります。

演習4

プログラム5を作成し、実行結果を確認せよ。

自動記憶域期間

ブロック有効範囲の変数に記憶域クラス指定子を指定しないか、記憶域クラス指定子として auto を指定すると、ブロックの実行開始時にスタック領域(またはレジスター)に記憶域が割り当てられ、そのブロックの実行終了時まで保持されます。

次のプログラムは、プログラム5の static を auto に変えただけのものです(プログラム6)。

void cnt(void) {
  static int i = 0;
  i++;
  printf(">> %d\n", i);
}

int main(void) {
  cnt();
  cnt();
  cnt();

  return 0;
}

変数 i は、cnt関数の実行開始時にメモリー内のスタック領域(またはCPU内のレジスター)に記憶され、cnt関数の実行が終了すると解放されます。 初期化は記憶域が割り当てられるごとに毎回行われます。 したがって、このプログラムを実行すると、次のようになります。

luna%
>> 1
>> 2
>> 3

演習5

プログラム5をプログラム6に変更し、実行結果を確認せよ。

C言語の規格(おまけ)

C言語は、1989年にアメリカで最初の標準規格が作られました。 この規格は、ANSI-CC89と呼ばれています。

これを基にして、1990年にC90と呼ばれる標準規格が世界標準機構 (ISO) で標準規格が作られました。

その後、1999年と2011年に規格が改定され、それぞれ、C99C11と呼ばれています。 (現在のgccには、C99とC11のほとんどの機能が実装されています。)

C言語の教科書、参考書を読むときには、どの規格に基づいて書かれているのか、確認しておきましょう。

gccでは、stdオプションを指定すると、指定した規格の文法に従ってコンパイルができます。

void cnt(void) {
  auto int i = 0;
  i++;
  printf(">> %d\n", i);
}

int main(void) {
  cnt();
  cnt();
  cnt();

  return 0;
}

列挙型(おまけ)

int型の値で、かつ、取りうる値が決まっているとき、列挙型とすることによって、変数の値を制限することができます。

列挙型は、次のように宣言します。

luna% a.out
>> 1
>> 1
>> 1

列挙子には、先頭から順に 0, 1, 2 と値が割り当てられますが、代入演算子 = をつけて値を指定することもできます。 また、同じ値を複数の列挙子に割り当てることもできます。

次のプログラムは、enum deptという名前の列挙型を宣言し、変数 d をenum dept型として宣言しています。 こうすることによって、変数 d にはenum dept型の列挙子の並びに宣言された値しか代入できなくなります。

luna% gcc -std=c99 filename.c

これを実行すると、次のようになります。

  enum 列挙型名 { 列挙子の並び };

定数の接尾語(おまけ)

定数の後ろに接尾語をつけて定数の型を明確にすることができます。

整定数

接尾語をつけないとint型とみなされます。

接尾語 u は、unsigned int型であることを表します。 接尾語 l は、long型(long int型)であることを表します。 接尾語 ll は、long long型(long long int型)であることを表します。

浮動小数点定数

接尾語をつけないとdouble型とみなされます。

接尾語 f は、float型であることを表します。 接尾語 l は、long double型であることを表します。

次のプログラムは、2進数にすると循環小数になるため必ず誤差が生じてしまう10進数の定数 0.1 を表示するプログラムです。

  enum dept {
    EM = 1, EE, ED, EC, EA, EK, EP, ER,
    LB = 51, LK, LP, LS, LC, LE
  };
  enum dept d;

  d = EP;  // 情報工学科
  printf(">> %02d\n", d);

  d = LC;  // 臨床工学科
  printf(">> %02d\n", d);

これを実行すると、次のようになります。

luna% a.out
>> 07
>> 55

複素数型(おまけ)

C99から、複素数を表す型(型名の後ろに_Complexが付く)が追加されました。

複素数を表す浮動小数点数型をサイズの小さい順に並べると、次のようになります。

  • float _Complex
  • double _Complex
  • long double _Complex
トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS