閉じる

【C言語】データ型の種類と選び方とは?役割とメリットをやさしく解説

C言語では、変数にどのような種類の値を入れるかを事前に決める必要があります。

そのとき鍵になるのがデータ型です。

本記事では、C言語の代表的なデータ型の種類と役割を整理しながら、初心者でも迷わず選べるように、考え方や注意点をやさしく解説します。

実際に動くサンプルコードも交えて、型選びのコツを身につけていきましょう。

目次 [ close ]

C言語のデータ型とは

データ型とは何か

C言語におけるデータ型とは、「その変数にどんな種類の値を入れるか」「どれくらいの大きさ(ビット数)でメモリに保存するか」を決める情報のことです。

たとえば、次のような宣言があります。

C言語
int    age;     // 整数(年齢など)
double height;  // 小数を含む数値(身長など)
char   initial; // 1文字(イニシャルなど)

ここでintdoublecharがデータ型です。

変数ageが整数であること、heightが小数を扱うことなどをコンパイラに伝えています。

データ型が決まると、次のようなことが決まります。

  • メモリ上で何バイト確保するか
  • 表現できる値の範囲
  • その変数に対してどんな演算ができるか
  • 入出力(printf/scanf)でどの書式指定子を使うか

なぜC言語にデータ型が必要なのか

C言語はコンパイル時に型をチェックする言語です。

これは、プログラムを実行する前に、コンパイラが型の矛盾や明らかなバグを見つけてくれるという意味です。

データ型が必要な理由は主に3つあります。

  1. メモリの使い方を明確にするため
    メモリはビットの並びですが、4バイトを整数として解釈するのか、小数として解釈するのかは型によって決まります。型がないと、どのように値を解釈すればよいか分かりません。
  2. 誤った操作を防ぐため
    たとえばポインタを整数として足し算したり、文字列と整数をそのまま比較したりするのは危険です。型が違えばコンパイラが警告やエラーを出してくれます。
  3. 処理速度と効率を高めるため
    型が分かっていれば、コンパイラは最適な機械語命令を選んでくれます。特に整数演算と浮動小数点演算ではCPU上の扱いが大きく異なるため、型指定は性能にも直結します。

データ型を正しく選ぶメリット

データ型を適切に選ぶことには、次のようなメリットがあります。

  • バグを減らせる
    想定外の桁あふれや、負の数が入り得ないのに負の値が混入する、といった問題を抑えられます。
  • メモリを無駄にしない
    小さくて済む値に安易にlong longなどを使うと、必要以上にメモリを消費します。組み込みや大量データ処理では差が大きくなります。
  • プログラムの意図が分かりやすくなる
    たとえばunsigned int index;と書けば、「負の値を取らないインデックス」であることが一目で分かります。
  • 処理速度の最適化につながる
    CPUが扱いやすいサイズの型を選ぶことで、無駄な変換や拡張を減らすことができます。

C言語の基本的なデータ型の種類

ここではC言語の代表的なデータ型と、その役割・使いどころを整理します。

整数型(intなど)の役割と使いどころ

整数を表す代表的な型は次の通りです。

  • short
  • int
  • long
  • long long

これらは小数部分を持たない数値を扱うときに使います。

たとえば、個数、回数、インデックス(配列の添え字)、年齢、ID番号などです。

代表的な使いどころとしては次のような場面があります。

  • ループ回数を数えるfor (int i = 0; i < 10; i++)
  • 配列の位置を表すindex
  • メニュー選択の番号choice
  • 点数や個数などのカウント

簡単な例を見てみます。

C言語
#include <stdio.h>

int main(void) {
    int count = 0;      // カウンタ用の整数
    int score = 85;     // テストの点数(0~100想定)

    count = count + 1;  // 1回処理したのでカウントアップ

    printf("count = %d\n", count);
    printf("score = %d\n", score);

    return 0;
}
実行結果
count = 1
score = 85

整数型は最もよく使う型なので、C言語を学ぶうえで最初にしっかり押さえておきたいところです。

小数型(float,double)の役割と使いどころ

小数を扱う型としては次の2つが基本です。

  • float … 単精度浮動小数点数
  • double … 倍精度浮動小数点数

これらは浮動小数点数と呼ばれ、誤差を完全には避けられないが、非常に広い範囲の値を扱える方式です。

使いどころとしては次のような場面があります。

  • 身長、体重、温度、距離などの実数
  • 測定値や統計データ
  • 物理シミュレーションやゲーム内の座標

サンプルコードで確認します。

C言語
#include <stdio.h>

int main(void) {
    float  temperature = 23.5f;  // fをつけてfloat型のリテラルにする
    double pi          = 3.141592653589793; // double型(末尾に何も付けない)

    printf("temperature = %f\n", temperature);
    printf("pi          = %.15f\n", pi); // 小数点以下15桁表示

    return 0;
}
実行結果
temperature = 23.500000
pi          = 3.141592653589793

精度が重要な場合は原則としてdoubleを使うのがおすすめです。

floatは主に、メモリ節約や速度重視の場面(組み込み、GPUなど)で選ばれることが多いです。

文字型(char)と文字コードの基本

char型は1文字を扱うための型です。

実体は1バイトの整数であり、その値を文字コードとして解釈します。

代表的な文字コードとしてASCIIコードがあります。

たとえば、

  • ‘A’ → 65
  • ‘a’ → 97
  • ‘0’ → 48

という対応があります。

C言語
#include <stdio.h>

int main(void) {
    char c1 = 'A'; // 1文字は' 'で囲む
    char c2 = 'a';
    char c3 = '0';

    printf("c1 = %c, ASCII = %d\n", c1, c1);
    printf("c2 = %c, ASCII = %d\n", c2, c2);
    printf("c3 = %c, ASCII = %d\n", c3, c3);

    return 0;
}
実行結果
c1 = A, ASCII = 65
c2 = a, ASCII = 97
c3 = 0, ASCII = 48

ポイントはcharが数値としても扱えることです。

アルファベットが連続したコードになっていることを利用して、簡易的な変換などにも使えます。

ただし、日本語のようなマルチバイト文字はchar1つでは収まらないことが多いため、その扱いは別のトピックになります。

真偽値としてのintと_Bool

C言語の古い仕様にはbool型がなく、整数型intで真偽値を表現するのが慣習でした。

  • 0 → 偽(false)
  • 0以外 → 真(true)
C言語
#include <stdio.h>

int main(void) {
    int flag1 = 0;  // 偽
    int flag2 = 1;  // 真(0以外なら何でも真)

    if (flag1) {
        printf("flag1 is true\n");
    } else {
        printf("flag1 is false\n");
    }

    if (flag2) {
        printf("flag2 is true\n");
    } else {
        printf("flag2 is false\n");
    }

    return 0;
}
実行結果
flag1 is false
flag2 is true

C99以降では_Boolが導入され、<stdbool.h>をインクルードすることでboolという名前で使えるようになりました。

C言語
#include <stdio.h>
#include <stdbool.h> // bool, true, falseを使うため

int main(void) {
    bool is_valid = true;
    bool is_done  = false;

    printf("is_valid = %d\n", is_valid); // trueは1, falseは0として表示される
    printf("is_done  = %d\n", is_done);

    return 0;
}
実行結果
is_valid = 1
is_done  = 0

条件を表す変数にはboolを使うと意図が明確になるため、新しいコードではboolの使用をおすすめします。

符号付きと符号なし(signed,unsigned)の違い

整数型には符号付き(signed)符号なし(unsigned)があります。

  • signed int … 正と負の両方を表現可能
  • unsigned int … 0以上の値のみを表現(その代わり上限が2倍近く広がる)

例として、32ビットのintの場合の典型的な範囲を示します。

およその値の範囲
signed int-2,147,483,648 ~ 2,147,483,647
unsigned int0 ~ 4,294,967,295

符号なしにすると最大値が広がる反面、負の値が扱えないため、用途に応じて選ぶ必要があります。

short,int,long,long longの違いとサイズの目安

整数型はビット数や表現範囲に差があります。

ただし、正確なサイズは環境依存ですが、多くのPC環境(32ビット/64ビット)では次のような目安です。

典型的なサイズ備考
short2バイト小さめの整数
int4バイト「標準的な」整数
long4または8バイトOSやコンパイラ依存
long long8バイト非常に大きな整数

正確なサイズはsizeof演算子で調べられます。

C言語
#include <stdio.h>

int main(void) {
    printf("sizeof(short)     = %zu\n", sizeof(short));
    printf("sizeof(int)       = %zu\n", sizeof(int));
    printf("sizeof(long)      = %zu\n", sizeof(long));
    printf("sizeof(long long) = %zu\n", sizeof(long long));

    return 0;
}
実行結果
sizeof(short)     = 2
sizeof(int)       = 4
sizeof(long)      = 8
sizeof(long long) = 8

初心者はまずintを基準に考え、特殊な場面でshortlong longを選ぶ、という方針が分かりやすいです。

ポインタ型(型名* )の基本イメージと役割

ポインタ型は、「値そのもの」ではなく「値が入っているメモリアドレス」を扱う型です。

書き方は型名 のように、型の後ろにを付けます。

例としてintのポインタを見てみます。

C言語
#include <stdio.h>

int main(void) {
    int  value  = 10;   // 普通のint型変数
    int *p      = &value; // valueのアドレスを格納するポインタ

    printf("value = %d\n", value);
    printf("p     = %p\n", (void *)p);   // アドレスを表示
    printf("*p    = %d\n", *p);          // ポインタが指す先の値を参照

    return 0;
}
実行結果
value = 10
p     = 0x7ffd12345678   (環境によって異なる)
*p    = 10

ポインタは「別の変数を指す変数」とイメージすると理解しやすくなります。

配列や文字列、動的メモリ確保など、C言語の多くの機能でポインタが関わってきます。

配列と文字列(char配列)の位置づけと注意点

配列は「同じ型の要素が連続して並んだもの」です。

たとえばint a[5];int型の要素が5個分並んだ領域です。

C言語
#include <stdio.h>

int main(void) {
    int a[3] = {1, 2, 3}; // int型の配列(要素数3)

    printf("a[0] = %d\n", a[0]);
    printf("a[1] = %d\n", a[1]);
    printf("a[2] = %d\n", a[2]);

    return 0;
}
実行結果
a[0] = 1
a[1] = 2
a[2] = 3

文字列char型の配列で表現されます。

ただし最後に'\0'(ヌル文字)を置いて終端を示すというルールがあります。

C言語
#include <stdio.h>

int main(void) {
    char str1[] = "Hello";       // "Hello
#include <stdio.h>
int main(void) {
char str1[] = "Hello";       // "Hello\0" が自動的に入る
char str2[6] = "World";      // 要素数6(最後は'\0')
printf("str1 = %s\n", str1);
printf("str2 = %s\n", str2);
return 0;
}
" が自動的に入る char str2[6] = "World"; // 要素数6(最後は'
#include <stdio.h>
int main(void) {
char str1[] = "Hello";       // "Hello\0" が自動的に入る
char str2[6] = "World";      // 要素数6(最後は'\0')
printf("str1 = %s\n", str1);
printf("str2 = %s\n", str2);
return 0;
}
') printf("str1 = %s\n", str1); printf("str2 = %s\n", str2); return 0; }
実行結果
str1 = Hello
str2 = World

配列名は多くの場面で「先頭要素へのポインタ」として扱われるため、ポインタとの関係がやや紛らわしく感じるかもしれません。

初心者のうちは「配列は同じ型が並んだ箱」「文字列はchar配列で、最後に’\0’が入っている」とイメージできれば十分です。

C言語のデータ型の選び方ガイド

ここからは、実際に変数を宣言するときにどのように型を選べばよいかの考え方を整理します。

まず「値の種類」を決める

型選びの第一歩は扱いたい値の「種類」をはっきりさせることです。

次のように分類して考えます。

  • 個数、回数、インデックス → 整数型
  • 身長、温度、割合など小数が必要 → 浮動小数点型
  • 1文字(アルファベット、記号など) → char
  • 真偽(はい/いいえ、フラグ) → boolまたはint
  • 複数の同じ型の集まり → 配列
  • 文字列 → char配列(またはポインタ)

まずは「整数か」「小数か」「文字か」「真偽か」「配列か(文字列か)」を決めると、その後の選択がぐっと楽になります。

次に「値の範囲」を考える

次にどれくらい大きな値まで扱う必要があるかを考えます。

  • 年齢: 0~150程度 → intで十分
  • ファイルサイズ(バイト数): 数十GBまで → long longsize_tなど大きめの型
  • 配列の要素数: 数千~数百万 → 環境によるがintsize_t

範囲が分からないときは想定される最大値をざっくり見積もるとよいです。

もし後で足りないと分かった場合は、より広い型に変更します。

メモリ使用量と速度を意識した型選び

一般的に型が大きいほどメモリを消費し、場合によっては速度にも影響します。

ただし、現代のPCではintshortの差が体感できない場面も多いです。

初心者向けの考え方としては次のようにしておくと安全です。

  • 基本はintdoubleを使う
  • 特別な理由があるときだけshortlong longを検討する
  • 大量データや組み込みなどメモリ制約が厳しいときはサイズも考慮する

小数計算ではfloatとdoubleをどう選ぶか

浮動小数点数を使うとき、最初に悩むのがfloatdoubleかです。

初心者向けの指針としては次の通りです。

  • 特に理由がなければdoubleを使う
    精度が高く、誤差の影響が出にくいです。
  • メモリ節約や速度が重要な場合のみfloatを検討
    ただし、誤差が増えることには注意が必要です。
C言語
#include <stdio.h>

int main(void) {
    float  x = 1.0f / 3.0f;
    double y = 1.0  / 3.0;

    printf("float  x = %.10f\n", x);
    printf("double y = %.15f\n", y);

    return 0;
}
実行結果
float  x = 0.3333333433
double y = 0.333333333333333

同じ1/3でも表現できる桁数が違うことが分かります。

金融計算など誤差にシビアな処理では特に注意が必要です。

文字処理でcharと文字列(char配列)をどう使い分けるか

文字を扱う場面ではcharchar配列(文字列)を使い分けます。

  • 1文字だけ扱う
    例: 性別のコード’M’、’F’など →char gender;
  • 複数文字の名前やメッセージ
    例: “Hello”、”Yamada”など →char name[100];
C言語
#include <stdio.h>

int main(void) {
    char grade = 'A';          // 1文字
    char name[16] = "Yamada";  // 文字列(最後に'
#include <stdio.h>
int main(void) {
char grade = 'A';          // 1文字
char name[16] = "Yamada";  // 文字列(最後に'\0'が入る)
printf("grade = %c\n", grade);
printf("name  = %s\n", name);
return 0;
}
'が入る) printf("grade = %c\n", grade); printf("name = %s\n", name); return 0; }
実行結果
grade = A
name  = Yamada

1文字は’ ‘で囲み、文字列は” “で囲むという区別は非常に重要です。

これを混同するとコンパイルエラーや意図しない挙動を招きます。

signedかunsignedかを決めるときの判断基準

整数型を選ぶとき、signedにするかunsignedにするかも重要です。

判断基準は次のようになります。

  • 負の値があり得るならsigned
    例: 温度(-10℃など)、残高の増減、差分値
  • 負の値が「絶対に」出ないならunsignedも検討
    例: 個数、インデックス、サイズ(バイト数)

ただしsignedとunsignedを混ぜた計算はややこしいため、初心者のうちは<zst-strong>まずsigned(何も付けなければsigned)</zst-strong>を使う方が安全です。

どうしても範囲が足りない場合にunsignedを検討するとよいです。

初心者におすすめの基本パターン

C言語初心者が迷わないために、基本パターンを決めておくと便利です。

  • 一般的な整数 → int
  • 大きな整数が必要 → long long
  • 小数 → double
  • 1文字 → char
  • 真偽値 → bool(#include <stdbool.h>)
  • 文字列 → char name[長さ];
C言語
#include <stdio.h>
#include <stdbool.h>

int main(void) {
    int    age       = 20;
    long long money = 10000000000LL; // リテラル末尾にLL
    double height   = 170.5;
    char   initial  = 'T';
    bool   is_adult = true;
    char   name[16] = "Tanaka";

    printf("age      = %d\n", age);
    printf("money    = %lld\n", money);
    printf("height   = %.1f\n", height);
    printf("initial  = %c\n", initial);
    printf("is_adult = %d\n", is_adult);
    printf("name     = %s\n", name);

    return 0;
}
実行結果
age      = 20
money    = 10000000000
height   = 170.5
initial  = T
is_adult = 1
name     = Tanaka

まずはこのパターンを使いこなせるようになると、多くのプログラムを書けるようになります。

型変換(キャスト)が必要な場面と注意点

異なる型同士を計算するとき、C言語では自動的に型変換(暗黙の型変換)が行われます。

それでも、次のような場面では明示的な型変換(キャスト)が必要です。

  • 整数同士の割り算で小数の結果が欲しいとき
  • より広い型から狭い型へ変換するとき(情報が失われるかもしれない)
  • ポインタの型を変えるとき
C言語
#include <stdio.h>

int main(void) {
    int a = 5;
    int b = 2;

    int   c1 = a / b;              // 整数同士 → 2
    double c2 = (double)a / b;     // aをdoubleにキャスト → 2.5

    printf("c1 = %d\n", c1);
    printf("c2 = %f\n", c2);

    return 0;
}
実行結果
c1 = 2
c2 = 2.500000

キャストを使えば何でも変換できるわけではなく、情報が失われる場合もあるので、どんな値が入るかをよく考えてから使うことが大切です。

C言語のデータ型の書き方とよくあるミス

ここでは、初心者がつまずきやすいデータ型まわりの典型的なミスをまとめて紹介します。

変数宣言の書き方

C言語では「型名 変数名;」という形で変数を宣言します。

複数まとめて宣言することもできます。

C言語
#include <stdio.h>

int main(void) {
    int a;        // int型の変数aを宣言
    int b, c;     // 同じ型ならカンマでまとめて宣言できる
    double x = 1.5, y = 2.5; // 宣言と同時に初期化も可能

    a = 10;
    b = 20;
    c = a + b;

    printf("c = %d\n", c);
    printf("x = %f, y = %f\n", x, y);

    return 0;
}
実行結果
c = 30
x = 1.500000, y = 2.500000

宣言より前に変数を使うことはできない点にも注意が必要です。

初期化の書き方と未初期化変数の危険性

C言語ではローカル変数(関数内の変数)は自動的には0で初期化されません

初期化しないで使うと、中身が不定(ゴミ値)となり、非常に危険です。

C言語
#include <stdio.h>

int main(void) {
    int x;    // 初期化していないローカル変数
    printf("x = %d\n", x); // 何が表示されるか分からない(未定義動作)

    return 0;
}
実行結果
x = 32767   (環境によっては別の値になる)

初心者にとって未初期化変数は大きなバグの原因になるため、宣言と同時に初期値を入れる習慣をつけると良いです。

C言語
int x = 0;  // 必ず初期化しておく

桁あふれ(オーバーフロー)と型の範囲の確認方法

整数型には表現できる値の範囲があります。

それを超えるとオーバーフロー(桁あふれ)が起き、結果が正しくなくなります。

C言語
#include <stdio.h>
#include <limits.h> // INT_MAXなどの定数が定義されている

int main(void) {
    int x = INT_MAX; // int型の最大値
    printf("INT_MAX = %d\n", x);

    x = x + 1;       // 1を足してみる(オーバーフロー)
    printf("x = %d (オーバーフロー後)\n", x);

    return 0;
}
実行結果
INT_MAX = 2147483647
x = -2147483648 (オーバーフロー後)

<limits.h><float.h>には各型の最小値・最大値が定義されています

大きな値を扱うときは、それらを参照して範囲が足りているか確認すると安心です。

整数と小数を混ぜた計算(暗黙の型変換)での落とし穴

整数と浮動小数点を混ぜて計算するとき、Cは自動で型を揃えようとします

このとき、意図せず整数同士の割り算になってしまうなどの落とし穴があります。

C言語
#include <stdio.h>

int main(void) {
    int n = 5;
    int m = 2;

    double a = n / m;       // 整数同士の割り算 → 2
    double b = (double)n / m; // nがdoubleに変換される → 2.5

    printf("a = %f\n", a);
    printf("b = %f\n", b);

    return 0;
}
実行結果
a = 2.000000
b = 2.500000

どこか一方を明示的にdoubleにキャストすることで、小数としての計算になります。

特に割り算ではこのミスがよく起こるため、意識しておくと良いです。

charと文字列リテラルの勘違い

1文字文字列の区別は非常に重要です。

  • 1文字 → 'A'(シングルクォート)
  • 文字列 → "A"(ダブルクォート)
C言語
#include <stdio.h>

int main(void) {
    char c = 'A';      // 正しい: 1文字
    // char s = "A";   // 誤り: "A" は文字列(配列)なので代入できない

    char str[] = "A";  // 文字列(実際には 'A' と '
#include <stdio.h>
int main(void) {
char c = 'A';      // 正しい: 1文字
// char s = "A";   // 誤り: "A" は文字列(配列)なので代入できない
char str[] = "A";  // 文字列(実際には 'A' と '\0' の2文字)
printf("c   = %c\n", c);
printf("str = %s\n", str);
return 0;
}
' の2文字) printf("c = %c\n", c); printf("str = %s\n", str); return 0; }
実行結果
c   = A
str = A

コンパイルエラーの例として、char c = "A";のような書き方をしてしまうと「互換性のないポインタ型から整数型への代入」などのエラーや警告になります。

ポインタと配列の型ミスマッチで起きるエラー

配列とポインタは密接に関係していますが、完全に同じではありません

型が合っていないポインタに代入しようとするとエラーや警告になります。

C言語
#include <stdio.h>

int main(void) {
    int  a[3] = {1, 2, 3};
    int *p    = a;      // OK: int配列の先頭 → int * に代入

    double d[3] = {1.0, 2.0, 3.0};
    // int *q = d;     // NG: double配列の先頭は double * 型

    printf("a[0] = %d, *p = %d\n", a[0], *p);

    return 0;
}
実行結果
a[0] = 1, *p = 1

ポインタは「何型へのポインタなのか」が非常に重要です。

型が違うと、1つ進めたときに何バイト先へ進むかが変わってしまいます。

コンパイラ警告をよく確認して、型を合わせるようにしましょう。

コンパイラ警告を活用したデータ型エラーの発見方法

C言語では、コンパイラが警告としてデータ型の問題を教えてくれることがあります。

たとえば次のような状況です。

  • 型の不一致(例: doubleintへ代入)
  • 戻り値の型と関数宣言の不一致
  • printf/scanfの書式指定子と変数型の不一致

コンパイル時に-Wallオプションを付けて警告を有効にすると、多くの問題を早期に発見できます。

Shell
gcc -Wall main.c -o main

警告が出たら必ず内容を読み、原因を理解して修正することが、C言語上達への近道です。

データ型のミスはバグにつながりやすいため、警告を味方にして開発を進めていくことが大切です。

まとめ

本記事では、C言語におけるデータ型の基本と選び方について、初心者向けに整理して解説しました。

データ型は単なる「型の名前」ではなく、メモリ上での表現方法・扱える値の範囲・演算の意味を決める重要な要素です。

特に次のポイントを押さえておくと、型選びで迷いにくくなります。

  • まず「整数か」「小数か」「文字か」「真偽か」「配列や文字列か」という値の種類を決めること
  • 整数は基本int、小数は基本doubleから始めること
  • 1文字はchar、文字列はchar配列で表現し、' '" "を混同しないこと
  • 負の値が必要かどうかでsignedunsignedかを判断すること
  • 未初期化変数、オーバーフロー、整数と小数の混在計算、ポインタの型不一致といった典型的な落とし穴に気をつけること
  • コンパイラの警告を必ず確認し、0件になるように修正すること

データ型の理解は、C言語のあらゆる機能(配列、ポインタ、構造体、標準ライブラリなど)の土台になります。

この記事の内容を実際にサンプルコードで確かめながら、自分の手で変数を宣言し、値を入れ、出力してみることで、少しずつ「型の感覚」が身についていきます。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!