プログラミング(2)「変数」

変数と型

変数とは数値や文字などを入れる入れ物のようなものです。 変数は大きく分けて、整数を入れる変数と実数を入れる変数があります。 変数は全て「型」を持っていて、 整数を入れる変数はchar, int等の型を使用し、 実数を入れる変数はfloat,double等の型を使用します。 コンピュータは基本的に有限の数値しか扱えませんので、 それぞれの型で使用できる数値の範囲が決まります。

それぞれの型で使用できる範囲はコンピュータによって違いますが、 現在主流の32bitマシンでは以下のようになっています。

サイズ使用できる範囲
char 1バイト-127 〜 128
int 4バイト-2,147,483,648 〜 2,147,483,647
float 4バイト±1.2E-38 〜 ±3.4E+38 (有効桁数:約6桁の実数)
double8バイト±2.3E-308 〜 ±1.7E+308 (有効桁数:約15桁の実数)

コンピュータ内には有限桁の数値しか保存できませんので、 使用用途によって型を決めます。 通常、文字を入れる変数はchar、整数を入れる変数はint、 実数はfloatを使います。ただし、 科学技術計算など精度が求められる計算には実数にdoubleを使用します。

数値の範囲だけ考えるとintの範囲はfloatやdoubleの範囲に含まれるので、 intは不要とも言えます。 しかし、実際はintとfloat,doubleは性質が違い、用途によって使い分けるので、 どちらも必要になります。intは整数値しか表せませんが、その値を厳密に表すことができます。 それに対しfloatやdoubleは1を代入しても、実際に表すのは約1です。 doubleで1に一番近くて小さい数字と、大きい数字はそれぞれ
0.999999999999999888977697537484345957636833(=1-2-52)
1.000000000000000222044604925031308084726334(=1+2-52)
となるので、doubleの1は厳密には1ではなく、この二つ値の間の値が全て1と表されます。 これは、本来は連続な数字を有限桁で表しているため起こるもので、 floatやdoubleを使うとき注意が必要になることもあります。

まとめ

  • 整数(個数、回数などの小数点以下のない場合)はint
  • 実数(座標、質量などの小数点以下がある場合)はdouble


変数の宣言

プログラム中で変数を使用するためには変数を宣言する必要があります。宣言は 以下のように行います。

int i;
double x;

iやxは変数名で、プログラムを作る人が自由に決めることが出来ます。ただし、 C言語で予め使われるintやdouble等は変数名として使うことが出来ません。 変数名にはその変数に入れる値についてわかりやすい名前を付けたほうがプログラム が読みやすくなります。

int particle_number;
double position;

代入と計算

変数に値を入れるためには=(イコール)を使用します。 式には演算子を使用できるので、 計算の結果を変数に代入することも出来ます。

int i,j,k;
i = 1;
j = 2;
k = i + j;

ちなにみに、変数を宣言して代入を行わない場合はその変数の中身は不定です。 C言語では変数を宣言したときに変数の値の初期化は行わないので注意してください。 演算子の種類は以下の通りです。

演算子機能
*乗算
/除算
%余り
+加算
-減算

C言語には演算と代入を同時に行う複合代入演算子あります。 a = a + bのような演算は、複合代入演算子を使ってa += bと書きます。 その他の例は以下の通りです。

複合代入演算例等価演算
a += ba = a + b
a -= ba = a - b
a *= ba = a + b
a /= ba = a / b

また、a = a + 1を++aやa++と書け、これをインクリメント演算子といいます。 どちらもaに1を加えてaに代入しますが、++aはaを評価する前に1を加え、 a++はaを評価した後に1を加えます。 インクリメント演算子と代入を同時に行う場合はこれらの違いに注意する必要があります。 例えば以下のプログラムを実行すると、

#include <stdio.h>

main()
{
  int a,b,c;

  a = 1;
  b = ++a;

  a = 1;
  c = a++;

  printf("a=%d b=%d c=%d\n",a,b,c);
}
a=2 b=2 c=1

という結果になり、bにはaに1を加えた後に値が代入され、 cにはaに1を加える前の値が代入されていることが分かります。 a = a - 1は--aやa--と書け、これをデクリメント演算子といいます。 使い方はインクリメント演算子と同じです。


変数の表示

変数の中身を表示するためにはprintfを使用します。

#include <stdio.h>

main()
{
  int i,j,k;

  i = 1;
  j = 2;
  k = i + j;

  printf("i=%d j=%d k=%d\n",i,j,k);
}

上記ののプログラムをコンパイルして実行すると

i=1 j=2 k=3

と表示されます。printfで使用されている%dは整数を表示するための指定子です。 指定子には以下のようなものがあります。

指定子表示する変数
%d整数
%f実数
%e実数(指数表記)
%s文字列
演習
doubleの変数を2つ用意し、それぞれに50,20を代入し、それぞれの和、差、積、 商の結果を以下のように表示するプログラムを作成せよ。
wa   70.000000
sa   30.000000
seki 1000.000000
syou 2.500000

配列変数

変数を一度にたくさん使用するときは配列変数を使います。

int type[10];

上記のように配列変数を宣言した場合は、変数としてtype[0], type[1], tyep[2], ... , type[9]の10個のint型の変数が使用できます。 C言語では変数の[ ]の中の数字に0から9までの10個の数字を使用します。 宣言では[10]と書きますが、使用できるのは[9]までなので注意してください。

もし間違ってtype[10]を使用してもエラーは出ません。 変数の中身を表示させた場合の結果は不定になりますし、 代入を行った場合の動作も予想できず、 最悪の場合はコンピュータがハングアップします。

コンピュータは変数が宣言されたときに必要な分だけメモリを確保します。 宣言した配列の範囲以外の場所を使うということは、 コンピュータが確保したメモリ以外の場所にアクセスすることになります。 その場所には他の変数が使用しているかもしれませんし、 プログラム自体が書かれている場所かもしれません。 配列の外側の領域から値を読んだり書いたりした場合の動作は予測不能ですので、 十分注意しましょう。

大量の配列変数を宣言するときは、宣言の前にstaticを付けて

static int type[10000];

とします。 staticを付けない場合はスタック領域と呼ばれる場所からメモリを確保し、 staticを付けた場合は静的領域と呼ばれる場所からメモリを確保します。 スタック領域は通常は容量が少ないので、 大量のメモリを確保する場合は static を用いて静的領域からメモリを確保する必要があります。

staticを付けた場合は実行時に一度だけ値が自動的に初期化されます。 初期値を明示しない場合は値が0に初期化されるので、 上の例では配列の全てに0が入ります。また、staticを付けて宣言された変数は、 プログラム実行中は値が保持されるので、 関数内で変数の値を保持したい場合もstaticを用います。

まとめ

  • 変数をたくさん使うときは配列変数を使う
  • 100以上ぐらいの配列変数を使う場合は宣言の前にstaticを付ける


文字列

C言語では文字を格納する変数としてchar型の変数を使用します。 本来char型はサイズが1バイトの整数値を入れることの出来る型ですが、 コンピュータでは文字も数値として扱うので文字を入れる変数としては通常 char型を使用します。 文字と数値の対応はASCIIコードで決められていて、 例えばAは65、Bは66、Cは67となっています。

文字列の宣言は

char word[6] = {"Hello"};

のように行います。"Hello"は5文字ですが、 C言語では文字列の終端を'\0'で表しますので、 宣言をする場合は文字数+1のサイズで宣言を行います。 このように宣言をした場合は
word[0] = 'H',
word[1] = 'e',
word[2] = 'l',
word[3] = 'l',
word[4] = 'o',
word[5] = '\0'
と代入したことと同じ動作になります。

上記の例では" "(ダブルクウォート)と' '(シングルクウォート)を使用しましたが、 C言語では両者は明確に区別されます。 " "で囲ったものは文字列としてメモリ上に確保され、 ' 'で囲った場合はASCIIコードに従った数値に置き換えられます。 ' '内には一文字しか書けません。

char a = 'A';

char a = 65;

は同じ意味になります。

文字列の表示にもprintfを使用します。

#include <stdio.h>

main()
{
  char word[] = {"Hello, World!"};

  printf("%s\n",word);
}

この例では、配列の宣言でword[]としてサイズが省略されていますが、 この場合コンパイラが自動的に必要な配列のサイズを確保してくれます。 printfで使用されている%sは文字列を表示するための指定子です。 このプログラムをコンパイルして実行した場合は以下のように表示されます。

Hello, World!

まとめ

  • 文字列はchar型の配列変数に入れる
  • 文字の終端は'\0'で表す


構造体

変数をまとめて扱いたい場合は構造体を使います。

struct particle {
  double charge;
  double x,y,z;
};
struct particle pl[10];

structは構造体を作るためのキーワード、 particleはタグといってその構造体の名前です。 タグを使ってplという配列を定義できます。

typedefを使うと以下のように定義できます。

typedef struct {
  double charge;
  double x,y,z;
} PARTICLE;
PARTICLE pl[10];

構造体の中の変数には'.'(ピリオド)を使用して値を参照します。

  pl[0].charge = -1.0;
  pl[0].x = 1.2;
  pl[0].y = 3.4;
  pl[0].z = 5.6;

もちろんpl[1].charge等にも同様に値を参照することができます。


列挙型

整数の定数を入れる変数として使用します。 用途としては数字に意味をつけるために使うことが多いです。

#include <stdio.h>
main()
{
  enum {
    LJ,
    COULOMB,
    BOND,
    ANGLE,
    TORSION,
    NUM
  };
  double potential[NUM];

  potential[LJ] = 0;
}

上記の例ではenum内の変数の値は

LJ      = 0
COULOMB = 1
BOND    = 2
ANGLE   = 3
TORSION = 4
NUM     = 5

と自動的に割り当てられます。これらの値を使うと、 potenital[0]ではなくpotential[LJ]と書けるので、 プログラムが読みやすくなります。

以下の例のように、変数の値を与えることも出来ます。 主にプログラム中で使用する定数として使います。

enum {
  PARTICLE_NUM = 256,
  TOTAL_STEP = 10000
};