C言語 入門 part1 基本編

June 25th, 2021

目次

関連リンク

C言語入門リスト

プログラミング完全初学者向けというより、 他のプログラミング言語を何かしら習得している事を前提に進めていきます。m(._.)m

C言語について

  • C言語は様々な目的で利用するために作られた、1972年に開発されたプログラミング言語。
  • 様々な言語のコンパイラとしてC言語が利用されていたりする。
  • IoTなどの普及によりC言語やC++言語が再び注目を浴びている。
  • 家電製品や自動車にも利用されている。

ほうほう、これは学んでおきたい 🦉

開発環境

以下の環境で開発を進めてみました。

とりあえずコードを実行

// printf関数を利用するために最初に呼び出しておく header ファイル。
// 他にも色々なライブラリが標準で備わっている。
#include <stdio.h>

// main関数はプログラムのエントリポイント
// この中に処理を書いていく。
int main()
{
  printf("こんにちは。私の名前は%sです。 \n年齢は%d歳", "Cゲンガー", 23);
  return 0; // プログラム正常終了の合図
}
こんにちは。私の名前はCゲンガーです。
年齢は23歳です。

printf

  • 第一引数が出力される文字列
  • 第二引数以降は何かしらの値

第一引数に記載されたformat specifier(フォーマット指定子)を元に第二引数以降の値が挿入される。

上記のコードでは

  • 文字列型(string)である %sCゲンガー が割り当てられ、
  • 10進数の実数型(decimal)である %d23 が割り当てられるっと。

return 0; について

これは、プログラムが正常に終了したことを表すものです。

以下のような2つのコードがあるとして、コンパイル後にターミナルでコマンドを打ってみました。

#include <stdio.h>
int main() {
  printf("Hello World ! ")
  return 0;
}
% ls
hello.c hello

% ./hello && echo "Hi !"

出力結果

Hello World ! Hi!

return 1; にすると?

#include <stdio.h>
int main() {
  printf("Hello World ! ")
  return 1;
}
% ls
hello.c hello

% ./hello && echo "Hi !"

出力結果

Hello World !

&& は コマンド1 && コマンド2 のような時、 コマンド1が成功した時に、コマンド2を実行する。

  • return 0; は正常終了を意味する。
  • reutrn 0以外で異常終了となる。

なので、プログラムが正常に終了したことを表すためには基本的には return 0; を最後に書く必要があります。

が、C99という1999年に策定されたC言語の規格以降では return 0; の記述が無くても動作します。


フォーマット指定子 (一例)

書式説明
%d整数値10進数
%f実数値10進数(単精度実数)
%lf実数値10進数 (倍精度実数)
%c文字。ASCII(アスキー)コードで表示された文字を表示する。シングルクォートで囲う。
%s文字列を表示する。ダブルクォートで囲う。
  • %f, %lf について それぞれ32bit, 64bitでデータを扱う。

詳しくは以下を参照

printfのオプションまとめ WIP 準備中...

データ型 (一例)

データ型意味説明サイズ
char整数型(文字列)1byteの符号付整数。ASCIIコードという文字コードに使用8bit
int整数型2または4byteの整数(コンパイラに依存する)16bit
float浮動小数点型4byteの単精度浮動小数点実数32bit
double浮動小数点型8byteの倍精度浮動小数点実数64bit

補足

  • 符号付整数型

    0と正負の数を表現できる整数型。 先頭が値の正負を表す符号ビットがある。(0が正/1が負)

  • 単精度浮動小数点実数

    有効桁数の少ない小数点を格納できる型

  • 倍精度不動小数点実数

    有効桁数の多い小数点を格納できる型

特殊文字 エスケープシーケンス

通常の文字列では表せない文字や機能を表現したもの

一例

特殊文字意味
\a警告音
\bバックスペース
\n改行
\tタブ
\\文字としての\
\?文字としての?
\"ダブルクォーテーション
\'シングルクォーテーション
\0null文字

変数

変数宣言する際には型を指定して変数は最初に全て定義しておかないといけない。 と言われていますがC99からブロックの途中でも変数宣言ができるようになってます。

#include <stdio.h>

int main()
{
  int a = 10;
  int b;
  b = 5; // 初期化は後からでもOK

  add = a + b;
  sub = a - b;
  printf("%d + %d = %d\n", a, b, add);
  printf("%d - %d = %d\n", a, b, sub);
}
10 + 5 = 15
10 - 5 = 5

配列(数値編)

#include <stdio.h>

int main() {
  int d[5]; // size5の配列変数の宣言 ( 配列の5番目という意味ではない! )
  int i;

  // 配列の番号を指定し、値を格納している。
  // このように後から初期化することが可能です。
  d[0] = 1;
  d[1] = 2;
  d[2] = 3;

  for (i = 0; i < 3; i++) {
    printf("%d ", d[i]);
  }
  printf("\n");
}
1 2 3

配列のsize宣言なしで初期化することも可能です。

その場合は、自動的にsizeが決まります。

#include <stdio.h>

int main() {
  int n[] = { 1, 2, 3, 4, 5 };
  int i;

  for(i = 0; i < 5; i++) {
    printf("n[%d] は %d\n", i, n[i]);
  }
}
n[0] は 1
n[1] は 2
n[2] は 3
n[3] は 4
n[4] は 5

配列(文字編)

文字の配列の場合は数値と扱い方が少し異なります。

文字の配列の場合は配列の最後の要素に '\0' が格納されます。

そしてこの文字の配列こそが、文字列になります。

とりあえず、見ていきすしょう。🤔

#include <stdio.h>

int main() {
  // 文字の配列では、どこで終わりにするかを '\0' で表す必要がある。
  char string1[4] = { 'a', 'b', 'c', '\0' };

  // 0 ~ 11には右辺の各文字が格納されており、
  // 12個目の文字には要素の終わりを表す '\0' が格納されている.
  char string2[] = "Hello World!";

  // 最大6文字まで入る文字列(= 最後に'\0'が入るので5文字指定できる)
  char string3[6];

  printf("string1 は %s\n", string1);
  printf("string2 は %s\n", string2);
}
string1 は abc
string2 は Hello World!

出力結果の abc と Hello World! から分かるように文字の配列が文字列として標準出力されました。

C言語において文字列というのは文字の配列のことだったのです。。。🤔

文字の配列の最後を確認してみた

変数が初期化された後の行でbreak pointを指定。(赤丸のやつ)

VScodeのコマンドパレットから Task: Run build task を実行して確認してみました。

実際にあった。

配列の確認

文字列は文字の配列であり、その最後には \0 というものが格納されているというのがポイントでした ! 🤯

scanf

scanfはキーボードからの入力を受け取り、変数にその入力を格納する関数。

scanf は引数に以下の2つの値を指定する必要があります。

  • 標準入力で受け取る値に一致する変換指定子
  • メモリのアドレス

メモリのアドレスを取得するにはアンパサンド & を利用します。(Cでは配列名自体がポインタとなるので、配列の場合は&は不要になる。)

#include <stdio.h>

int main() {
  // 変数定義
  // この時、ageのメモリアドレスが決まる。
  int age;

  printf("君おいくつ?");
  scanf("%d", &age);
  printf("%d 歳っ!🤓\n", age);
}

しかし注意が必要なのは、値の格納先が配列の場合は & は不要なケースがあります。

それが配列です。

#include <stdio.h>

int main() {
  char input[100];
  printf("あなたの名前は?\n");

  // 配列名は先頭要素を示す様に暗黙的に型変換されています。
  scanf("%s", input);
  printf("%sです!\n", input);
}
Cゲンガー // 入力した値
Cゲンガーです!

各要素の値を設定する場合は明示的にアドレスを指定する必要があるので、アンパサンド & が必要となります。

#include <stdio.h>

int main() {
  char input[2];
  printf("一文字入力雨してください\n");

  // 配列の1番目の要素に文字を格納する。
  scanf("%c", &input[0]);
  printf("入力した文字は。。。%cです!\n", input[0]);
}
C // ← 入力した値
入力した文字は。。。Cです!

算術演算

算術演算子

  • addition
  • subtraction
  • multiplication
  • division
  • modulus division
#include <stdio.h>

int main() {
  int a = 11;
  int b = 5;
  int c;

  c = a + b;
  printf("addtion: %d \n", c);

  c = a - b;
  printf("subtraction: %d \n", c);

  c = a * b;
  printf("multiplication: %d \n", c);

  c = a / b;
  printf("division: %d \n", c);

  c = a % b;
  printf("modulus division: %d \n", c);

  return 0;
}
addtion: 16
subtraction: 6
multiplication: 55
division: 2
modulus division: 1

優先順位

演算子の優先順位に基づいて数値式を評価していきます。 +と-は、*、/、%と同様に、同じ優先順位です。 式の左から右の順に *, /, % が実行され、次に + と - が同じく左から右の順に評価されていきます。 演算の順序を変えるには、どの演算を先に実行するかを括弧( )で囲みます。 たとえば、「2 + 3 * 2」の結果は 8、「(2 + 3) * 2」の結果は「10」です。 この辺は説明しなくても算数と一緒ですし、他のプログラミング言語触ってたら知ってるはずですね〜。

ただ実際に以下の様な場合は結合法則が不規則になる可能性があります。(計算結果は同じ)

a * b * c

// 以下のどちらで評価されるか分かりませんが、計算結果は同じです。
// (a * b) * c
// a * (b * c)

型変換

int型とfloat型で計算した時には、計算結果はfloat型に変換されます。

#include <stdio.h>

int main() {
  float tax_rate = 1.1;
  int price = 100;
  float billing_price;

  billing_price = tax_rate * price;

  printf("Billing Price: %f", billing_price);

  return 0;
}
Billing Price: 110.000000

強制的に型変換するには type cast します。

(変換したい型) 対象(値、変数、式など)

以下は、int型をfloat型に型変換した例です。

#include <stdio.h>

int main() {
  int a = 10;
  int b = 3;
  float average;

  average = (float) 10 / 3;
  printf("%f", average);
  // 3.333333

  return 0;
}

自己代入演算子

int型の変数xに対しての各処理です。

int x = 3;
x += 1;     // x の値は 4
x -= 1;     // x の値は 2
x *= 2;     // x の値は 6
x /= 2;     // x の値は 1
x %= 2;     // x の値は 1
x += 3 * 2; // x の値は 9

インクリメントとデクリメント演算子

int x = 3;
- ++x(またはx++); // x の値は 4
- --x(またはx--); // x の値は 2

先頭と末尾のインクリメントとデクリメント演算子の違い

increment, decrementを先頭に付けるか、末尾に付けるかで実は意味が変わってきます。

  • ++x

xに1プラスして、xの値を返す。

  • x++

xの値を返して、xに1プラスする。

  • --x

xに1マイナスして、xの値を返す。

  • x--

xの値を返して、xに1マイナスする。

例)

#include <stdio.h>
int main() {
   int a = 1, b = 3;

   // 5が表示されて、
   // その後に、aが2になる。
   printf("%d\n", a++);

   // bが4になって、
   // その後、bが表示される。
   printf("%d\n", ++b);

   return 0;
}

左から右に実行されているのに注意しなきゃいけないですね!🤯

ちなみに、increment, decrementの演算子がある他の言語でもこの様な挙動をします。(JavaとかJavaScriptとか) そもそも、increment, decrementがないプログラミング言語もあります。(Rubyとか)

printfのオプション(一部抜粋)

『printf 書式 値』で出力することができました。

printf("%d", 100)

printf関数にはオプションがあります。

数値の出力幅を指定 width

数値の出力幅を5に指定しています。 数値の桁数が指定した幅数より小さい時には左に空欄が挿入されます。

例)

#include <stdio.h>

int main() {
  printf("%5d\n", 1);
  //    1
  // ↑ 4つ分spaceが入っている。

  printf("%5d\n", 55555);
  //55555
  // ↑ スペース無し。(指定幅以上の数値の場合はspaceは無視される。)
  printf("%2d\n", 7);
  // 7
  // ↑ 1つ分spaceが入っている。
}

精度の指定 precesion

浮動小数点数の小数点以下の桁数を設定します。(省略時は小数点以下6桁)

桁数を表すには .10進数整数 を指定します。

例)

// %.2 は小数点以下の桁数は 2 なので 1.11
// 1.11 で 4つ分の長さ
// widthが10なので、6つ分spaceが足されます。
printf("%10.2f\n", 1.1111111111);
//      1.11
// ↑ 6つ分spaceが入っている。

// %.2 は小数点以下の桁数は 2 なので 1.11
// 1.11 で 4つ分の幅
// 既に指定幅 3 以上あるのでspaceは無視。
printf("%3.2f\n", 1.1111111111);
//1.11

printf関数のオプションは他にもいくつかありますので興味があれば調べてみましょう〜

ということで一応まとめてみました。

printfのオプションまとめ WIP 準備中...