C言語の基礎
ここでは、C言語の基礎について説明します。
目次
- C言語の雛形
- 変数と配列
- 制御文について
- 関数について
- メイン関数とサブルーチンについて
- ヘッダーファイルについて
- 関数printfについて
- ポインタについて
- 構造体について
- typedefを用いた構造体について
- 構造体の参照について
- 参考文献
C言語の雛形
C言語は、大枠として以下のように記述します。
#include <stdio.h>
int main(void)
{
/* ここに処理内容を記述する */
return 0;
}
この雛形を元にして、C言語の基本的な仕組みについて説明します。
変数と配列
変数について
変数とは、いわゆる値を入れるための箱のようなものです。
変数を使う場合、その変数がどのようなデータを扱うのかを示す型を宣言する必要があります。
ここでは、まず以下の2つを覚えれば十分です。
| 型 | 意味 | 例 |
|---|---|---|
int型 |
整数型 |
1, 2, 3
|
char型 |
文字型 |
'A', 'B', 'C'
|
例えば、以下のように宣言します。
int a;
char b;
C言語では、基本的に文の最後に**セミコロン(;)**を付けます。
変数に値を代入するときは、=を使います。
int x = 1;
char y = 'y';
char z = 'K';
ここで注意したいのが、char型に1文字を代入するときは、文字を**シングルクォーテーション(')**で囲むことです。
char c = 'A';
一方、複数の文字からなる文字列は、ダブルクォーテーション(")で囲みます。
char name[] = "yuto";
配列について
変数をいくつかまとめて扱うための仕組みが配列です。
配列に入っている一つ一つのデータを要素といい、配列に入れられる要素の数を要素数といいます。
例えば、5個の整数を格納する配列は以下のように定義できます。
int x[5] = {1, 2, 3, 4, 5};
配列にはインデックス番号が割り振られています。
重要なのは、C言語の配列は0番目から始まるということです。
x[0] = 1
x[1] = 2
x[2] = 3
x[3] = 4
x[4] = 5
つまり、5個の要素を持つ配列の場合、インデックス番号は0~4になります。
配列の要素を参照するときは、
配列名[インデックス番号]
と記述します。
例えば、
printf("%d\n", x[0]);
とすると、1が表示されます。
制御文について
制御文とは、プログラムの動きを制御するための命令です。
制御文を使うことで、
- 条件による処理の分岐
- 処理の繰り返し
などができるようになります。
ここでは、代表的な制御文であるif文とfor文について説明します。
if文について
if文は、条件分岐を行うための構文です。
条件に応じて、実行する処理を変更できます。
基本的な書き方は以下の通りです。
if (条件式)
{
/* 条件式が真のときの処理 */
}
else
{
/* 条件式が偽のときの処理 */
}
例えば、以下のように記述できます。
#include <stdio.h>
int main(void)
{
int a = 3;
if (a > 0)
{
printf("これは自然数です\n");
}
else
{
printf("これは自然数ではありません\n");
}
return 0;
}
このプログラムでは、aが0より大きい場合、
これは自然数です
と表示されます。
一方、aが0以下の場合は、
これは自然数ではありません
と表示されます。
for文について
for文は、繰り返し処理を行うための構文です。
基本的な書き方は以下の通りです。
for (初期値; 繰り返し処理をする条件; 処理した後の処理)
{
/* 繰り返し処理をする内容 */
}
例えば、
for (i = 1; i <= 10; i++)
{
/* 処理 */
}
とした場合、以下のような流れで処理されます。
初期値
↓
条件を確認
↓
条件を満たす?
↓ YES
繰り返し処理
↓
iを増やす
↓
条件を確認
↓
...
↓ NO
終了
つまり、
初期値
↓
繰り返し条件
↓
繰り返し処理
↓
処理後の処理
↓
繰り返し条件
↓
繰り返し処理
↓
処理後の処理
↓
……
という流れでループします。
例えば、1から10までの整数を合計するプログラムは以下のようになります。
#include <stdio.h>
int main(void)
{
int i;
int sum = 0;
for (i = 1; i <= 10; i++)
{
sum = sum + i;
}
printf("1から10までの合計は%dです\n", sum);
return 0;
}
実行すると、
1から10までの合計は55です
と表示されます。
関数について
関数とは、ある処理をひとまとめにしたものです。
例えば、
入力 → 関数 → 出力
という形で処理を行うことができます。
C言語における関数の基本的な形は以下の通りです。
戻り値の型 関数名(引数1, 引数2, ...)
{
/* 変数の定義 */
/* 処理内容 */
return 戻り値;
}
例えば、2つの整数を足し算する関数は以下のように書けます。
int sum(int x, int y)
{
int z;
z = x + y;
return z;
}
この場合、
x
+
y
↓
sum関数
↓
z
という処理を行い、最後にzを戻り値として返します。
メイン関数とサブルーチンについて
C言語では、main関数がプログラムの実行開始地点になります。
基本的には以下のように記述します。
int main(void)
{
/* 変数の定義 */
/* 処理内容 */
return 0;
}
return 0;は、main関数から0を返してプログラムを終了することを表します。
main関数とは別に関数を作ることもできます。
例えば、先ほどのsum関数を利用する場合、以下のように書けます。
#include <stdio.h>
int sum(int x, int y);
int main(void)
{
int a = 1;
int b = 2;
int c;
c = sum(a, b);
printf("値は%dになります\n", c);
return 0;
}
int sum(int x, int y)
{
int z;
z = x + y;
return z;
}
このプログラムでは、
int sum(int x, int y);
という関数プロトタイプ宣言をmain関数より前に記述しています。
その後、
c = sum(a, b);
とすることで、aとbの値をsum関数に渡しています。
今回の場合、
a = 1
b = 2
↓
sum(1, 2)
↓
1 + 2
↓
3
↓
c = 3
という流れになります。
引数と戻り値
関数に渡す値を引数といい、関数から返ってくる値を戻り値といいます。
int sum(int x, int y)
の場合、xとyが引数です。
そして、
return z;
によってzを戻り値として返しています。
なお、昔のC言語では、main関数をメインルーチン、それ以外の関数をサブルーチンと呼ぶことがあります。
現在では、一般的には「関数」と呼ぶほうが分かりやすいでしょう。
ヘッダーファイルについて
C言語では、以下のような記述をよく見かけます。
#include <stdio.h>
stdio.hは、C言語の**標準入出力(Standard Input/Output)**に関する宣言がまとめられているヘッダーファイルです。
stdioは、
standard input/output
の略です。
stdio.hには、例えば、
printfscanf
などの標準入出力に関係する機能を利用するための宣言が含まれています。
#includeを使うことで、必要なヘッダーファイルを読み込むことができます。
基本的な書き方は、
#include <ファイル名>
です。
例えば、
#include <stdio.h>
と記述すると、stdio.hにある宣言を利用できるようになります。
つまり、ヘッダーファイルには、関数などを利用するために必要な宣言がまとめられていると考えると分かりやすいでしょう。
関数printfについて
printfは、画面に文字や数値を表示するための関数です。
基本的な書き方は以下の通りです。
printf("書式文字列", 変数);
例えば、
int a = 10;
printf("この値は%dです\n", a);
とすると、
この値は10です
と表示されます。
ここで、
%d
は、整数を10進数として表示するための変換指定子です。
代表的なものには以下があります。
| 指定子 | 意味 |
|---|---|
%d |
10進数の整数 |
%f |
浮動小数点数 |
%c |
1文字 |
%s |
文字列 |
%p |
ポインタ(アドレス) |
例えば、
int a = 10;
double b = 3.14;
char c = 'A';
printf("%d\n", a);
printf("%f\n", b);
printf("%c\n", c);
のように使用できます。
ポインタについて
ポインタは、C言語を理解するうえで非常に重要な仕組みです。
簡単に言えば、ポインタとは他の変数が存在するメモリ上の場所(アドレス)を扱う仕組みです。
ポインタ変数について
ポインタ変数は以下のように宣言します。
変数の型 *変数名;
例えば、
int *p;
とすると、int型のデータを指すポインタ変数pを宣言できます。
ここで使われている*は、文脈によって意味が変わります。
int *p;
では、pがポインタであることを示します。
一方、
*p
と書いた場合は、ポインタpが指している先の値を参照します。
アドレスの参照
変数には、メモリ上のアドレスが割り当てられます。
変数のアドレスを取得するときには、&演算子を使用します。
&変数名
例えば、
int x = 10;
printf("%p\n", (void *)&x);
とすると、変数xのアドレスを表示できます。
ポインタを使った例
#include <stdio.h>
int main(void)
{
double x = 2.71;
double *y;
y = &x;
printf("変数xのアドレスは%pです\n", (void *)y);
printf("変数xの中身は%fです\n", *y);
return 0;
}
このプログラムでは、
double x = 2.71;
によってxという変数を作っています。
次に、
double *y;
によって、double型を指すポインタyを作ります。
そして、
y = &x;
によって、xのアドレスをyに代入しています。
そのため、
x
┌─────────┐
│ 2.71 │
└─────────┘
↑
│
│ アドレス
│
┌─────────┐
│ y │
└─────────┘
という関係になります。
*yとすると、yが指している先の値、つまりxの値である2.71を取得できます。
ポインタと配列
配列とポインタには密接な関係があります。
例えば、
int a[5] = {10, 20, 30, 40, 50};
という配列があるとします。
配列名aは、多くの式の中で先頭要素へのポインタのように扱われます。
つまり、
a
は、先頭要素a[0]を指す値として扱うことができます。
例えば、
int *p = a + 1;
とすると、pは2番目の要素a[1]を指します。
そして、
printf("%d\n", *p);
とすると、
20
と表示されます。
また、
a[1]
は、
*(a + 1)
と同じ意味になります。
つまり、
a[1] = *(a + 1);
という関係があります。
構造体について
構造体とは何か
**構造体(struct)**とは、複数の異なる型のデータを一つにまとめて扱うための仕組みです。
構造体を構成する一つ一つのデータをメンバといいます。
基本的な書式は以下の通りです。
struct 構造体タグ
{
型 メンバ名;
型 メンバ名;
...
};
例えば、学生の成績を表す構造体を作るとします。
struct seiseki
{
int number; /* 学籍番号 */
char name[20]; /* 氏名 */
char subject[20]; /* 科目名 */
int score; /* 点数 */
};
ここでは、
seiseki
が構造体タグです。
また、
number
name
subject
score
がメンバです。
この構造体を利用する変数を作る場合は、
struct seiseki yuto;
と記述します。
これによって、yutoという構造体変数を作ることができます。
typedefを用いた構造体について
typedefを使用すると、構造体に別名を付けることができます。
基本的な書式は以下の通りです。
typedef struct 構造体タグ
{
型 メンバ名;
型 メンバ名;
...
} 別名;
例えば、
typedef struct
{
int number;
char name[20];
char subject[20];
int score;
} NEMber;
とすると、NEMberという名前でこの構造体を利用できます。
例えば、
NEMber yuto;
と書くことができます。
typedefを使わない場合、
struct seiseki yuto;
と書く必要があります。
一方、typedefを使えば、
NEMber yuto;
と書けるため、構造体を利用するときの記述を簡潔にできます。
構造体の参照について
構造体のメンバを参照するときは、**ドット演算子(.)**を使います。
基本的な書き方は、
構造体の変数名.メンバ名
です。
例えば、
yuto.number
とすれば、yutoのnumberメンバを参照できます。
構造体を使ったプログラム
以下は、学生の成績を構造体で管理する例です。
#include <stdio.h>
typedef struct
{
int no; /* 学生番号 */
char name[20]; /* 氏名 */
double average; /* 平均値 */
} SEISEKI;
int main(void)
{
int i;
SEISEKI student1 = {5, "mikun", 83.5};
SEISEKI student2[20] =
{
{1, "radio", 78.6},
{2, "mameshiba", 57.3},
{3, "MATSUNOKI", 66.4}
};
printf("%d %s %5.1f\n\n",
student1.no,
student1.name,
student1.average);
for (i = 0; i < 3; i++)
{
printf("%d %s %5.1f\n",
student2[i].no,
student2[i].name,
student2[i].average);
}
return 0;
}
このプログラムでは、
SEISEKI student1;
によって一人分の成績データを管理しています。
また、
SEISEKI student2[20];
とすることで、同じ構造を持ったデータを配列として管理しています。
例えば、
student2[0].no
とすれば、student2の0番目の要素にある学生番号を参照できます。
このように、構造体と配列を組み合わせることで、複数のデータを整理して管理できます。
まとめ
ここまで、C言語の基本的な仕組みについて説明しました。
今回扱った内容をまとめると、以下のようになります。
| 項目 | 内容 |
|---|---|
| 変数 | 値を保存するためのもの |
| 配列 | 複数の同じ型のデータをまとめるもの |
if文 |
条件によって処理を分岐する |
for文 |
処理を繰り返す |
| 関数 | 処理をひとまとめにする |
#include |
ヘッダーファイルを読み込む |
printf |
文字や数値を表示する |
| ポインタ | メモリ上のアドレスを扱う |
| 構造体 | 複数の型のデータをまとめる |
C言語は、これらの基本的な仕組みを組み合わせることで、より複雑なプログラムを作ることができます。
特にポインタ・配列・構造体は、C言語を理解するうえで重要な要素です。
参考文献
- 『やさしく学べるC言語入門[第2版]』皆本晃也、サイエンス社
- 『Cの絵本』株式会社アンク、翔泳社
- C言語入門
http://www9.plala.or.jp/sgwr-t/c/sec16.html