変数についてより詳しく

C言語勉強会 第九回

kumar8600
June 2, 2013

今回の内容

型変換

明示的型変換(キャスト)

強制的に別の型に変換 したいときに用いる。

文法

(型)式

int変数 i をdouble型に変換する例

(double)i

暗黙の型変換

代入時の変換

左辺の型と右辺の型が異なっている場合は、 左辺の型に変換 される。

次の例では、 a は小数部の1415が切り捨てられて「3」になる。

int a;
double x = 3.1415;
a = x;

式の中で行われる変換

式の中で異なる型の定数や変数が現れたときは、 精度の高い型に統一 される。

3 ÷ 2 は 1 ??????

下の式では x は 1 になってしまう。

int a = 3;
int b = 2;

float x = a / b;

こうすれば右辺はfloat型の精度で計算され、 x は 1.5 になる。

float x = (float)a / b;

データ型をもっと知ろう

符号の有無

以下のキーワードを整数型の前後に付加することで符号の有無を指定する。

キーワード 意味
signed 符号あり
unsigned 符号なし

符号無しのint型変数を宣言するには以下のように書く。

unsigned int x;

なぜわざわざ符号なしの変数なんか宣言するのか?

それは、符号なしの時のほうが、扱える値の範囲が正の方向に長いので、そのほうが便利な場面があるからだ。

整数型の最大値・最小値

変数の型によって、扱える値の範囲は変わる。

符号 容量 値の範囲
signed char 1 -128 ~ 127
unsinged 0 ~ 255
signed short 2 -32,768 ~ 32,767
unsigned 0 ~ 65,535
signed int 4 -2,147,483,648 ~ 2,147,483,647(±約21億)
unsigned 0~4,294,967,295(約42億)
符号 容量 値の範囲
signed long 4 -2,147,483,648 ~ 2,147,483,647(±約21億)
unsigned 0~4,294,967,295(約42億)
signed long long 8 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807(±約922京)
unsigned 0~18,446,744,073,709,551,615(約1844京)

浮動小数点型

精度が低い順に、

がある。

sizeof 演算子

sizeofに渡された型や変数のメモリサイズを返す。

文法

sizeof 変数名
または
sizeof (型名or変数名)

型のメモリサイズを得る例

int integerSize = sizeof (int);

変数のメモリサイズを得る例

int i = 10;
int integerSize = sizeof (i);

配列のメモリサイズを得る例

int arr[10];
int arrSize = sizeof(arr);

配列の要素数を算出

配列の要素数 = sizeof(配列名) / sizeof(配列の要素の型)
すなわち
配列の要素数 = sizeof(配列名) / sizeof(配列名[0])

接尾語

式に直接、定数を書き込むとき、接尾語を付けることでその型を指定出来る。

float x = 3.0f / 2.0f;  // 3.0と2.0がfloat型であることを示している。

整数定数の接尾語

接尾語
なし int 以上の符号あり整数型
u または U unsigned int 以上の符号なし整数型
l または L long int 以上の符号あり整数型
ll または LL long long int

浮動小数点定数の接尾語

接尾語
なし double
f または F float
l または L long double

423     : int
423L    : long

423.0f  : float
423.0   : double

スコープ

ブロック

{}に囲まれた領域をブロックと呼ぶ。

ローカル変数

プログラムの一部分でしかアクセスできない変数のこと(グローバル変数の逆)

#include <stdio.h>

void print_a() {
    int o = a;
    printf("%d\n", o);
}

int main(void) {
    int a = 10;  /* ここから変数 a にアクセスできる */

    print_a();

    return 0;
} /* ここで変数 a は開放され、消滅する */

スコープ

先程の例では a にアクセスできるのはmain関数の終わりまでである。

グローバル変数

全てのスコープからアクセスできる変数。どこの関数の中でもない、プログラムの最も外側の部分に書く。

#include <stdio.h>

int a = 3;

int main(void) {

    printf("%d\n", a);

    return 0;
}

変数の優先度

ブロックの外側で宣言された変数よりも、内側で宣言された変数が優先される。

#include <stdio.h>

int a = 3;

int main(void) {
    int a = 10;

    printf("%d\n", a);

    return 0;
}

理解の再確認

今までの内容を理解しているなら、下のプログラムを実行するとどう出力されるかわかるはずだ。

#include <stdio.h>

int main(void) {
    int a = 10;

  if(1) {
    int a = 20;
    printf("%d\n", a);
  }

    printf("%d\n", a);

  return 0;
}

main関数ではじめに a を宣言し、10で初期化した。その後、if文の中でもう一度 a という名前の変数を宣言したが、これらが全く別の変数であることを意識出来れば、なんの迷いもない問題だ。

記憶クラス指定子

記憶クラス指定子

変数の保存方法を更に細かく指定する

文法

通常の変数の宣言の前につける。

記憶クラス指定子 型名 変数名;
または
型名 記憶クラス指定子 変数名;

static int a;
または
int static a;

以下の五つが存在する

auto | 自動変数

プログラム中の宣言されたブロック内でのみ使用できる変数。
つまり、 今まで使ってきた普通の変数

文法

auto 型名 変数名;
または
型名 変数名;

補足

自動変数のココが自動

特定の区域内に到達すると自動的に変数領域を確保しその区域を脱すると自動的にその領域を開放して消滅する 点が自動

void print_a() {
    int o;
    o = 10;
    printf("%d\n", o);
}

static | 静的変数

どこに宣言していようとも関係なく、プログラムの実行開始時にメモリ上に作られ、初期値も与えられる変数

文法

static 型名 変数名;

#include <stdio.h>

void printCalledNum() {
    static int n = 0;
    n++;
    printf("%d回目の呼び出し\n", n);
}

int main(void) {

    printCalledNum();
    printCalledNum();
    printCalledNum();

    return 0;
}

静的変数は必ず初期化される

静的変数は、具体的な初期値を与えなかった場合、必ず 0 で初期化されることが保証されている。

また、グローバル変数も、具体的な初期値を与えなかった場合、必ず 0 で初期化される。

グローバル変数でのstatic

グローバル変数にstaticをつけると、今まで説明した意味と全く違う意味になる。

extern

変数の実体が、別のところに存在していることを表現する

extern int a;

register | レジスター変数(時代遅れらしい)

コンピューターには主記憶装置である「メモリ」の他に、CPUに内蔵されていて、メモリと比べるととてつもなく速く、低容量な「 レジスタ 」がある。実はCPUによる計算は、メモリに入っている値を一度レジスタにコピーしてから行われている。(なんか最近は違うらしい)

そんな高速なレジスタに変数を格納したいとき、この指定子を使う。

register int a;

typedef

データ型に新しい名前(別名)をつける。

構造体を宣言する際にも何気なく使ってきたと思う。

例えば、int に自分の好きな別名をつけるには、

typedef int Seisu;

このように書く。この例では int に Seisu という別名をつけた。なので以降、

Seisu n;

と書くことでも int 型変数 n を宣言できる。

typedef | よくある使用例

unsigned int に uint という別名をつける

typedef unsigned int uint;

ある構造体を名前をつけ宣言する。

typedef struct {
    char name[20];
    double height;
    double weight;
} HUMAN;

型修飾子

型修飾子

データ型を用途に応じてきめ細かく指定する。

文法

変数を宣言する際、型の前後に付加して使う。

型修飾子 型名 変数名;
または
型名 型修飾子 変数名;

const int a;
int const a;

補足

関数の仮引数で型修飾子を使うことも出来る。

void func(const int a) {
    ...
}

以下の二つについて紹介する。

定数(const)

指定した変数が定数であることを指定する。

文法

const 型名 変数名;
または
型名 const 変数名;

#include <stdio.h>

int main(void) {

    const int a = 10;
    a += 2;

    printf("%d\n", a);

    return 0;
}

補足

volatile変数

コンパイラによる最適化を行わない変数。

今のコンパイラは頭がいいので、私たちの書いたなプログラムをできるだけ素晴らしい効率で動くように最適化する。

だが、マルチスレッドなプログラム等、コンパイラの設計の想定を超えるプログラムを書いた場合、逆にその最適化のせいでプログラムが正常に作動しなくなることがある。

次回