C言語

C言語は実行速度が速い汎用プログラミング言語です。

auto

自動変数はスタック領域に変数の領域が確保される。自動変数を宣言するには、記憶クラスに auto を指定する。

記憶クラスとは、宣言する変数をどこに記憶するかを指定します。

auto int n;

変数を宣言する際、記憶クラスの指定を省略した場合は自動変数となる。

int n;

自動変数を宣言する際、明示的に初期化を行わなければ、初期値は不定となる。

static

静的変数は、プログラム実行中に常に同じ場所に配置され、値を保持します。

静的変数を宣言するには、記憶クラスに static を指定します。静的変数を宣言する例を次に示します。

static int n;

静的変数を宣言する際、明示的に初期化を行わなければ、初期値は0になります。

記憶クラス 初期値
自動変数 不定
静的変数 0

register

変数の領域が確保される物理的な記憶装置は主記憶装置である。主記憶装置よりもCPU内のレジスタの方が高速にアクセスできるため、変数の領域を確保する物理的な記憶装置をレジスタに指定した変数がレジスタ変数である。ただし、可能な限りレジスタに確保するよう要求するだけで、必ずしもレジスタに確保される保障はない。

レジスタ変数を宣言するには、記憶クラスに register を指定する。

register int n;

typedef

typdefは、既存の型に対して新しい名前を付けるときに使用します。

typedef 型名 新しい型名;

新しい型名を付けると、既存の型名のように使用することができます。

typedef unsigned int BYTE;
BYTE data;

この例は、次のように変数を宣言するのと同じです。

unsigned int data;

型名の代りに、構造体や共用体の宣言を指定することもできます。

typedef struct {
  変数宣言のリスト
} 新しい型名;
typedef union {
  変数宣言のリスト
} 新しい型名;

これらは次のように記述することもできる。

struct tag_name {
  変数宣言のリスト
};

typedef struct tag_name 新しい型名;
union tag_name {
  変数宣言のリスト
};

typedef union tag_name 新しい型名;

const

const は定数を表す修飾子である。

例としてstrcpy関数のプロトタイプ宣言を見てみよう。

char *strcpy( char *string1, const char *string2 );

strcpy 関数は文字列 string2string1 へコピーする関数である。

string1 はコピー先の領域であり、コピー後は内容が変化する。strcpy 関数にとっては出力パラメーターであり、変数であるため const 修飾子が付いていない。

一方、string2 はコピー元の領域であり、コピー後も内容は変化しない。strcpy関数にとっては入力パラメーターであり、定数であるため const 修飾子が付いている。

たとえば、次のようなソースコードはコンパイル時にエラーとなる。

void example(const char *dest, char *src) {
  strcpy(dest, src);
}

この場合、char *の引数にconst char *を渡しているためエラーとなる。

なお、const char *の引数にchar *を渡しても問題ない。

volatile

volatile修飾子は最適化を抑制するオブジェクトを宣言します。

volatile int comm = 1;
while (1) if (comm == 0) break;

もし volatile 修飾子が無ければ、Cコンパイラーにより最適化が行われます。 ソースプログラムではループの中で変数が0に等しいかどうか比較していますが、変数が0になることは無いのでCコンパイラーの最適化機能で無駄な比較が削除されることがあります。 このため無条件で無限ループとなります。 volatile 修飾子があればコンパイラーによる最適化が行われないため、(他のプロセスから値を変更するなどして)変数 comm の値が0になるとループを脱出します。 これは、タスク間の同期制御に利用できます。

union

union (共用体)は、同一のデータ領域を複数の異なるデータ型が共用するようにしたものです。

union タグ名 {
  変数宣言のリスト
};

以下の場合には、タグ名を省略することが可能です。

変数宣言のリストの中に共用体を入れて、入れ子構造にすることも可能です。

共用体内の最初のメンバの初期化が可能です。

union x {
  char a[4];
  int  b;
};

union x ux = { 'U', 'N', 'I', 'X' };

strtok()

#include <string.h>

char *strtok(char *s1, const char *s2);

引数s1で指定した文字列の中に引数s2で指定した区切り文字(文字列形式で複数種類の文字を指定可能)が存在すれば、全てNUL文字('\0')に置き換えます。

つまり、1つの文字列を区切り文字によって複数の文字列に分割します。この分割されたそれぞれの文字列をトークンといいます。

例えば、以下のような文字列 s1 があったとします。

A B , C D , E F \0

strtok(s1, ",") を実行すると、文字列 s1 は次のようになります。

A B \0 C D \0 E F \0

また、strtokは最初のトークン ("AB") の先頭の文字 ('A') のポインタを返します。

次に、strtok(NULL, ",") を実行すると、strtokは次のトークン ("CD") の先頭文字 ('C') のポインタを返します。

次にstrtok(NULL, ",") を実行すると、strtokは次のトークン ("EF") の先頭文字 ('E') のポインタを返します。

最後のトークンの先頭文字のポインタを返した後にstrtok(NULL, ",") を実行すると、strtokは戻り値として NULL を返します。

rand()

C言語で乱数を生成するには、次の関数を使用します。

#include <stdlib.h>

int rand(void);

rand() 関数は 0 から RAND_MAX までの乱数を返します(RAND_MAX はヘッダファイル stdlib.h の中で定義されています)。

0 から 99 までの乱数を発生させたいときは、100 で割った余りを使います。

srand()

rand() ライブラリ関数は、あらかじめ決められた乱数表から順番に値を返しているので、完全にランダムな数を生成しているわけではありません。これは、rand() 関数の戻り値を printf() 関数で出力するプログラムを作成すれば確認できます。実行するたびに毎回同じ数値が出力されるはずです。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int i, r;
  for (i = 0; i < 10; i++) {
    r = rand();
    printf("%i\n", r);
  }
}

上記のプログラムを何度実行しても、常に同じ乱数が出力されます。そこで乱数の初期化が必要です。乱数の初期化とは、乱数表を先頭からではなく別のところから読み出すようにすることでです。乱数の初期化は srand() 関数で行います。

#include <stdlib.h>

void srand(unsigned int seed);

引数 seed には初期値を指定します。通常は time() 関数の戻り値を指定します。プログラムを実行するたびにそのときの時刻は変わるので、プログラムを実行するたびに異なる乱数が発生するようになります。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[]) {
  int i, r;
  srand(time(NULL));
  for (i = 0; i < 10; i++) {
    r = rand();
    printf("%i\n", r);
  }
}