授業/C言語基礎/変数の高度な使い方 のバックアップ差分(No.7)


  • 追加された行はこの色です。
  • 削除された行はこの色です。
これまで、int型、double型、そしてchar型という3つのデータ型を使ってきました。

ここでは、

*変数名 [#yaa70780]

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

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

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




*基本データ型 [#ma1cbc41]

**char型 [#pa5cba25]

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



**符号付き整数型 [#w1744804]

これまで使ってきた''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型のサイズが同じという環境もあります。


**符号なし整数型 [#b23138d6]

符号なし整数型は、符号付きであることを表す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)



**浮動小数点型 [#d9962971]

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

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

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

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

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



*符号付き整数型と符号なし整数型の違い [#w797be54]

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

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

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

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

これを実行すると、次のようになります。
#geshi(sh){{
luna% a.out
>> -1
>> 255
}}
255は、2進数で表すと 11111111 ですが、符号付き整数では負の数を''2の補数''として表現するので、これを2の補数として解釈し、-1 と出力されています。
2の補数については、計算機アーキテクチャーの授業できちんと勉強してください。

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


**演習1 [#he198ca3]
プログラム1を作成し、実行結果を確認せよ。




*定数 [#jd785038]

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

**整定数 [#lc2a5f96]

整定数には、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'' です。

定数が符号なし整数や(上位が 0 の)長いビット列を表すこともあるので、定数の後ろに''接尾語''をつけて定数の型を明確にすることができます。
接尾語をつけないとint型とみなされます。

接尾語 ''u'' は、unsigned int型であることを表します。
接尾語 ''l'' は、long型(long int型)であることを表します。
接尾語 ''ll'' は、long long型(long long int型)であることを表します。
#geshi(c){{
  printf(">> %d\n", 10);
  printf(">> %d\n", 010);
  printf(">> %d\n", 0x10);
  printf(">> %04x\n", 16);
}}
#geshi(sh){{
luna% a.out
>> 10
>> 8
>> 16
>> 0010
}}



**浮動小数点定数 [#ha10de47]

浮動小数点定数には、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進浮動小数点数の形を出力するときの変換指定子は ''

浮動小数点定数にも接尾語があります。
接尾語をつけないとdoube型であるとみなされます。

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



**文字定数 [#h316433f]

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

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



**値を変更できない変数 [#bf179f25]

変数を宣言するときに、型名の前に ''const'' を付けて宣言すると、その変数には初期化のときにしか値を代入できなくなり、プログラムの実行中に値を変更できなくなります。
変数を宣言するときに、型名の前に ''const'' を付けて宣言すると、その変数には初期化のときにしか値を代入できなくなり、定数となります。
#geshi(c){{
  const 型 定数名 = { 初期化子 };
}}
型が配列でないときは、初期化子を囲む波括弧 { } は省略できます。

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






*変数の有効範囲(スコープ) [#ld62e59b]

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

**ブロック有効範囲 [#z411c33f]

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

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

次のプログラムは、同じ名前で有効範囲の異なるローカル変数を二つ宣言しています(プログラム2)。
#geshi(c){{
int main(void) {
  int i = 0;
  printf(">> %d\n", i);

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

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

  return 0;
}
}}

このプログラムに登場する変数のスコープを図で表すと、次のようになります。
#ref(./scope.png,40%)
#ref(./block_scope.png,40%)

同じブロック内ですでに宣言されている変数の名前と同じ名前の変数を宣言することはできませんが、ブロックを作ることで同じ名前の変数を宣言できるようになります。
このとき、変数にアクセスすると、より内側のブロックでの宣言が優先されます。

このプログラムを実行すると、次のようになります。
#geshi(sh){{
luna% a.out
>> 0
## 1
>> 0
}}

C99では、for文の丸括弧 ( ) の中でも変数を宣言できるようになりました(プログラム3)。
#geshi(c){{
  for (int i = 0; i < 3; i++) {
    printf("Hello World!\n");
    printf(">> %d\n", i);
  }
}}

ただし、gccでこのプログラムをコンパルするときには、stdオプションにc99を指定する必要があります。
#geshi(sh){{
luna% gcc -std=c99 hello.c
luna% a.out
Hello World!
Hello World!
Hello World!
>> 0
>> 1
>> 2
}}



**演習2 [#q8585d42]
プログラム2とプログラム3を作成し、実行結果を確認せよ。




**ファイル有効範囲 [#v583ef90]

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

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

次のプログラムは、同じ名前のグローバル変数とローカル変数を宣言しています(プログラム4)。
#geshi(c){{
#include <stdio.h>

int i = 0;

int print(void) {
  printf(">> %d\n", i);
  return 0;
void prt(void) {
  printf("## %d\n", i);
}


void inc(void) {
  i++;
}


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

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

  return 0;
}
}}

このプログラムに登場する変数のスコープを図で表すと、次のようになります。
#ref(./file_scope.png,40%)
有効範囲が赤色で示されているものがファイル有効範囲の変数、青色で示されているものがブロック有効範囲の変数です。

変数にアクセスすると、より内側の宣言が優先されます。


このプログラムを実行すると、次のようになります。
#geshi(sh){{
luna% a.out
>> -1
## 0
## 1
>> -1
}}


**演習3 [#ob503147]
プログラム4を作成し、実行結果を確認せよ。



*変数の有効期限 [#u1ae71fa]

**静的記憶域期間 [#pf7ad444]
**自動記憶域期間 [#t4e53d48]



*C言語の規格(おまけ) [#c701d64c]

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

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

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

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

gccでは、stdオプションを指定すると、指定した規格の文法に従ってコンパイルができます。
#geshi(sh){{
luna% gcc -std=c99 filename.c
}}





*列挙型(おまけ) [#p3e9cc57]

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

列挙型は、次のように宣言します。
#geshi(c){{
  enum 列挙型名 { 列挙子の並び };
}}
列挙子には、先頭から順に 0, 1, 2 と値が割り当てられますが、代入演算子 ''='' をつけて値を指定することもできます。
また、同じ値を複数の列挙子に割り当てることもできます。


次のプログラムは、enum deptという名前の列挙型を宣言し、変数 d をenum dept型として宣言しています。
こうすることによって、変数 d にはenum dept型の列挙子の並びに宣言された値しか代入できなくなります。
#geshi(c){{
  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);
}}

これを実行すると、次のようになります。
#geshi(sh){{
luna% a.out
>> 07
>> 55
}}


*定数の接尾語(おまけ) [#q1059ae6]

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

**整定数 [#te70157b]

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

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



**浮動小数点定数 [#w69a5729]

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

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

次のプログラムは、2進数にすると循環小数になるため必ず誤差が生じてしまう10進数の定数 0.1 を表示するプログラムです。
#geshi(c){{
  printf(">> %.30f\n", 0.1);
  printf(">> %.30f\n", 0.1f);
}}

これを実行すると、次のようになります。
#geshi(sh){{
luna% a.out
>> 0.100000000000000005551115123126
>> 0.100000001490116119384765625000
}}

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS