#C言語とは
- 1972年にAT&Tベル研究所のデニス・リッチーが主体となって開発した汎用プログラミング言語
- 高水準言語と低水準言語の両方の性質を併せ持つ
- コンパイラ言語のため実行速度が速い
- 後継の様々な言語に影響を与えた
- コンパクトでメモリに占める容量が少ないため小さなコンピュータに利用される
#C言語を実行する流れ
- ソースファイルの作成
- .cという拡張子のソースファイルを作成する
- コンパイル※1をする
- コンパイルコマンド(環境によって異なる)を入力しコンパイルをする
- プログラムの実行
※1 コンパイルとはC言語でかかれたファイルを機械が理解できる機械語に翻訳することである
ソースコードを書く前に
- 関数: プログラムで何かを行うために使用するもの。関数への入力を引数という
- 変数: データを格納しておく箱のようなものであり、好きな名前をつけることができる
- 予約語: C言語にあらかじめ決められている言葉で、この予約語を関数名、変数名にすることはできない
- ライブラリ: すでに作成されているコードの集合。入出力に関わるコードが書かれているstdioをよく利用する
- 代入: 変数に値を格納すること。代入演算子である=を用いる
ソースコードを書こう
- ライブラリを読み込む
- メイン関数を書く
#include <stdio.h> // stdioというライブラリを読み込んでいる
int main(void) // メイン関数を記述している
{
// ここにコードを記述する
}
//はコメント文といい、実行に影響しないため説明などを記述することが一般的
データ型とは
- C言語にはコンピュータにどの種類の文字を扱うかを示す型というものがある
- この型によって格納できる文字の種類が決まっており、コンピュータも型の種類によって扱う方法が違うこともあるため用途にあった型を宣言することが大切である
- 後述するprintf関数などに利用する表記を書式指定子という
型名 | 格納される文字種 | 書式指定子 |
---|---|---|
int | 整数 | %d, %i |
long | 整数 | %ld |
double | 小数 | %f |
float | 小数 | %f |
char | 文字 | %c |
char[] | 文字列 | %s |
bool | 真偽 |
同じ整数・小数と書かれているものでも格納できる値の上限が異なる
boolはstdboolという標準ライブラリをインクルードすることで利用できる
演算子とは
- C言語には数学のように数値を計算する算出演算子や比較する比較演算子、論理演算子というものなどがある
- 数学の記号とは異なるものも多いため間違えないようにしたい
### 算術演算子
- 値の計算を行う演算子。考え方は学校の数学で習うものと同じだが記号が違うものもある
演算子 | 説明 | 使用例 |
---|---|---|
+ | 加算 | a = 1 + 2, a -> 3 |
- | 減算 | a = 2 - 1, a -> 1 |
* | 乗算 | a = 1 * 2, a -> 2 |
/ | 除算 | a = 4 / 2, a -> 2 |
% | 剰余 | a = 3 % 2, a -> 1 |
### 比較演算子
- 2つの値を比較する演算子。後述する条件分岐でよく利用する
- ==は=とは違う(=は代入演算子の一種)
比較演算子 | 説明 | 使用例 |
---|---|---|
> | 左の要素は右の要素より大きい | a > b |
< | 右の要素は左の要素より大きい | a < b |
>= | 左の要素は右の要素以上 | a >= b |
<= | 右の要素は左の要素以上 | a <= b |
== | aとbは同じ | a == b |
!= | aとbは異なる | a != b |
論理演算子
- 数Aで習うand(かつ)やor(または)、否定(not)と同じようなもの
- 条件分岐などで利用する
論理演算子 | 説明 | 使用例 |
---|---|---|
&& | 両方の要素が真の場合に真となる | a && b |
|| | どちらかの要素少なくとも1つがが真の場合真となる | a || b |
! | 要素が真の場合は偽に、偽の場合は真になる | !a |
関数を知ろう
- 関数には様々な種類があり、それらを利用することも、自分で作成することもできる
- 文末には;(セミコロンをつける)
#include <stdio.h>
int main(void)
{
printf("Hello Qiita\n");
// printf関数(文字を出力する関数)でHello Qiitaと出力するようにしている
// \nは改行を表すエスケープシーケンスと呼ばれる記号
}
Hello Qiita
文字列は""で囲む
#include <stdio.h>
void hello(void);
// main関数より後にhello関数があるとエラーが発生するためプロトタイプと呼ばれるものを作ってエラーを回避する
int main(void)
{
hello();
}
void hello(void) // 戻り値(最初のvoid)と引数(2つ目のvoid)がないhelloという名前の関数
{
printf("Hello Qiita\n"); // Hello Qiitaと出力する
}
Hello Qiita
よく利用する関数をまとめたのでぜひご覧ください
頻出関数まとめ
変数を使ってみよう
- 動的に変化するプログラムを作成するために変数は不可欠である
#include <stdio.h>
int main(void)
{
char *qiita = "Hello Qiita"; // qiitaという変数に"Hello Qiita"という文字列のアドレスを代入
printf("%s\n", qiita);
// %sという書式コードがqiitaという変数に置き換わりqiitaに格納されているHello Qiitaが出力される
}
Hello Qiita
条件分岐をしよう
- 条件分岐とはもし〇〇ならこういう処理を行うという条件を定めるもの
- いくつもの分岐をすることができる
#include <stdio.h>
int main(void)
{
int a = 1;
if (a == 1) // aが1の場合「aは1です」と出力する
{
printf("aは1です\n");
}
else if (a == 2) // aが2の場合「aは2です」と出力する
{
printf("aは2です\n");
}
else // それ以外の場合「aは1でも2でもありません」と出力する
{
printf("aは1でも2でもありません\n");
}
}
aは1です
繰り返し処理をしよう
- 同じ処理も何度も書くのは面倒なため繰り返し処理を使って少ない行で済むようにする
- 繰り返しの中で変数を変更することができる
- for, while ,do whileがある
#include <stdio.h>
int main(void)
{
int a = 1;
while (a < 4) // aが4未満の時、aを出力してaの値を1増やす
{
printf("a\n");
a++;
}
}
a
a
a
a++は糖衣構文といい、aを1増加させるという意味(使用する状況により異なるが、一般的に a += 1, a = a + 1と同意)
ちなみにa++は変数に代入した後にaを1増加させる。++aは変数に代入する前にaを1増加させる。
-> 状況に応じた使い分けを
#include <stdio.h>
int main(void)
{
int a = 1;
do // aが1以外の時aを出力する
{
printf("a\n");
}
while (a != 1);
}
a
do while文は一度は処理をしたいときに利用する構文であり、上の例ではaが1以外であるにも関わらずaが出力されている
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 6; i++) // 最初にiを0に初期化し、iが6未満の場合その時のiの値を出力し、iの値を1増加させる
{
printf("%d\n", i);
}
}
0
1
2
3
4
5
構造体を作ってみよう
- 1つの変数の中に異なる型のデータを複数格納できるデータ型の一種
#include <stdio.h>
int main(void)
{
typedef struct // int型ageとchar*(string)型のnameという変数を持ったpersonという型を新しく作る
{
int age;
char *name;
} person;
person man; // person型のmanという変数を作成
man.age = 20; // 構造体の中の変数にアクセスするときは . を用いる
man.name = "sayyyyyy";
printf("年齢は%d、名前は%sです。\n", man.age, man.name);
}
年齢は20、名前はsayyyyyyです。
配列を使ってみよう
- 同じ種類の複数のデータを格納するデータ構造を配列という
- 配列に格納されるひとつひとつの値を配列の要素といい、要素にアクセスするために利用される番号をインデックスという
- インデックスは0から始まることに注意
#include <stdio.h>
int main(void)
{
int a[3]; // 配列を宣言(int型の変数を3つ持った配列)
a[0] = 1; // インデックス0に1を代入
a[1] = 2;
a[2] = 3;
for (int i = 0; i < 3; i++) // for文で配列の要素を全て出力
{
printf("%d\n", a[i]);
}
}
ユーザから入力を受け付けよう
- ユーザから入力を受け付けるために利用する関数はscanf関数
- 第2引数に指定する&は後述するアドレスを示すものとなっている
#include <stdio.h>
int main(void)
{
int age;
printf("年齢を入力してください");
scanf("%d", &age); // scanf関数でageに、入力された値を代入している
printf("%d\n", age);
}
ポインタ操作をしてみよう
- 値が格納してある場所を確認できるアドレスというものがある
- &をつけることでアドレスを取得することができる
- アドレスにアクセスするときは*を用いる
- 違う関数間で同じ変数を扱うことができる
#include <stdio.h>
int main(void)
{
char *name = "sayyyyyy"; // name変数が格納されているポインタの一番最初のアドレスをname変数に格納している
printf("%s\n", name);
printf("%p\n", &name); // nameのアドレスを出力
}
sayyyyyy
0x7fffbfcc1ba8
%pはポインタを表示するプレースホルダ
メモリはプログラムを実行するたびにランダムに位置を振り分けるためアドレスは毎回異なる