const

const修飾子を変数宣言で型の前に付けると、値が変更できない変数(つまり定数)となる・・・。

const <型> <変数名>

例えば、

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */

/* main関数の定義 */
int main(void){

  /* 変数の初期化 */
  int a = 10; /* aを10に初期化. */
  const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */

  /* 値の出力 */
  printf("a = %d\n", a); /* aの値を出力. */
  printf("b = %d\n", b); /* bの値を出力. */

  /* プログラムの終了 */
  return 0;

}

aを10, bを100に初期化しておいてbをconstにする・・・。

$ gcc const.c -o const
$ ./const
a = 10
b = 100
$

当然、コンパイル、実行に成功し、そのまま出力される・・・。

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */

/* main関数の定義 */
int main(void){

  /* 変数の初期化 */
  int a = 10; /* aを10に初期化. */
  const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */

  /* 値の出力 */
  printf("a = %d\n", a); /* aの値を出力. */
  printf("b = %d\n", b); /* bの値を出力. */

  /* constに代入は不可. */
  a = 20; /* aに20を代入.(これは問題なし.) */
  b = 200; /* bに200を代入.(これはビルドエラー.) */

  /* プログラムの終了 */
  return 0;

}

このようにaに20, bに200を代入しようとすると、

$ gcc const.c -o const
const.c: 関数 ‘main’ 内:
const.c:17:3: エラー: 読み取り専用変数 ‘b’ への代入です
   b = 200; /* bに200を代入.(これはビルドエラー.) */
   ^
$

bへの代入はコンパイルエラーとなる・・・。constにより定数として扱われるので・・・。

このようにconstは変数の値を変更されたくない場合に使う・・・。

さて、ポインタの場合は、constの置く位置によって意味がかわる・・・。

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */

/* main関数の定義 */
int main(void){

  /* 変数の初期化 */
  int a = 10; /* aを10に初期化. */
  const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */
  /* 配列・ポインタの初期化 */
  char str1[] = "ABC"; /* str1に"ABC"という文字列をセット. */
  char str2[] = "DEF"; /* str2に"DEF"という文字列をセット. */
  const char * p = str1; /* ポインタでconstが型名の前の場合は, 参照先の値が変更不可になる. */
  char * const q = str2; /* ポインタでconstが変数名の前の場合は, ポインタの値が変更不可になる. */

  /* 値の出力 */
  printf("a = %d\n", a); /* aの値を出力. */
  printf("b = %d\n", b); /* bの値を出力. */

  /* constに代入は不可. */
  /*a = 20;*/ /* aに20を代入.(これは問題なし.) */
  /*b = 200;*/ /* bに200を代入.(これはビルドエラー.) */

  /* 値の出力 */
  printf("str1 = %s\n", p); /* p( == str1)を出力. */
  printf("str2 = %s\n", q); /* q( == str2)を出力. */

  /* 変更する. */
  *p = 'G'; /* これは変更不可なのでビルドエラー. */
  *q = 'H'; /* これは変更可能. */

  /* 値の出力 */
  printf("str1 = %s\n", p); /* p( == str1)を出力. */
  printf("str2 = %s\n", q); /* q( == str2)を出力. */

  /* プログラムの終了 */
  return 0;

}

char型配列str1の先頭アドレスをp, str2の先頭アドレスをqに渡す・・・。
pは型の前にconstを付けるのに対し、qは型の後(変数名の前)にconstを付けている・・・。
これをコンパイルすると、

$ gcc const.c -o const
const.c: 関数 ‘main’ 内:
const.c:29:3: エラー: 読み取り専用位置 ‘*p’ への代入です
   *p = 'G'; /* これは変更不可なのでビルドエラー. */
   ^
$

ポインタの場合は、型の前だとポインタの参照先の値を変更不可にする・・・。

const <型> * <ポインタ名> /* ポインタの参照先の値が変更不可 */

である・・・。

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */

/* main関数の定義 */
int main(void){

  /* 変数の初期化 */
  int a = 10; /* aを10に初期化. */
  const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */
  /* 配列・ポインタの初期化 */
  char str1[] = "ABC"; /* str1に"ABC"という文字列をセット. */
  char str2[] = "DEF"; /* str2に"DEF"という文字列をセット. */
  const char * p = str1; /* ポインタでconstが型名の前の場合は, 参照先の値が変更不可になる. */
  char * const q = str2; /* ポインタでconstが変数名の前の場合は, ポインタの値が変更不可になる. */

  /* 値の出力 */
  printf("a = %d\n", a); /* aの値を出力. */
  printf("b = %d\n", b); /* bの値を出力. */

  /* constに代入は不可. */
  /*a = 20;*/ /* aに20を代入.(これは問題なし.) */
  /*b = 200;*/ /* bに200を代入.(これはビルドエラー.) */

  /* 値の出力 */
  printf("str1 = %s\n", p); /* p( == str1)を出力. */
  printf("str2 = %s\n", q); /* q( == str2)を出力. */

  /* 変更する. */
  /**p = 'G';*/ /* これは変更不可なのでビルドエラー. */
  *q = 'H'; /* これは変更可能. */

  /* 変更する. */
  p = str2; /* これは変更可能. */
  q = str1; /* これは変更不可なのでビルドエラー. */

  /* 値の出力 */
  printf("str1 = %s\n", p); /* p( == str1)を出力. */
  printf("str2 = %s\n", q); /* q( == str2)を出力. */

  /* プログラムの終了 */
  return 0;

}

これだと、

$ gcc const.c -o const
const.c: 関数 ‘main’ 内:
const.c:34:3: エラー: 読み取り専用変数 ‘q’ への代入です
   q = str1; /* これは変更不可なのでビルドエラー. */
   ^
$

型の後ろだとポインタを変更不可にする・・・。

<型> * const <変数名> /* ポインタが変更不可 */

である・・・。

最終的にコンパイル成功したものは、

結果は、

$ ./const
a = 10こ
b = 100
a = 20
b = 100
str1 = ABC
str2 = DEF
p = HEF
q = HEF
$

qの参照先の先頭を'H'に変え、pはstr2を指すようにしたので、こうなる・・・。

Sample/const.c at master · bg1bgst333/Sample · GitHub