C

🔳変数

コンピュータ内部でのメモリの識別:数値による番地(=住所)。メモリのどの番地に値が保持されているか、数値による番地を指定することは大変。メモリを変数として扱うとき、固有の名前を付けて区別する。C言語では、「 データ型 変数; 」で宣言することによりメモリのある領域が変数として扱うことができる。




🔳スタック

スタックはメモリ上に確保されていて、データの位置をスタックポインタという特殊なレジスタ(CPU内部の値を格納するエリア)を利用して実現している。スタック上に確保された変数は、その関数の処理を終えると、変数自体も消えてしまう(ローカル変数:関数の中で宣言する)。

#include <stdio.h>

char *func(void){
  char one_string[14] = "hello, world\n";
  printf("from func: %s", one_string);

  return one_string;
}

int main(int argc, char const *argv[])
{
  printf("from main: %s", func());
  return 0;
}

main()関数と、func()関数の2カ所で画面に文字を表示するprintf()関数が呼び出しているが.....

$ ./auto-var
from func: hello, world
from main: I��

func()関数の中で宣言した、配列one_stringはスタック上に確保されるものなので、func()関数の処理を終了した時点で、他の処理に使われて内容が破壊されてしまう。

func()関数、main()関数両方のprintf()が綺麗に表示できるようにするためには、スタックとは別の場所に変数を確保するような宣言を行う必要がある。「静的変数」として変数を宣言すると、スタックとは別の場所に確保される「 staticデータ型変数名; 」。

#include <stdio.h>

char *func(void){
  static char one_string[14] = "hello, world\n";
  printf("from func: %s", one_string);

  return one_string;
}

int main(int argc, char const *argv[])
{
  printf("from main: %s", func());
  return 0;
}
$ ./auto-var
from func: hello, world
from main: hello, world

「static int count」

#include <stdio.h>

void func(void){
  int count = 0;
  count += 1;

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

  return;
}

int main(int argc, char const *argv[])
{
  func();
  func();
  func();

  return 0;
}
$ ./auto-var_2
count = 1
count = 1
count = 1
#include <stdio.h>

void func(void){
  static int count = 0;
  count += 1;

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

  return;
}

int main(int argc, char const *argv[])
{
  func();
  func();
  func();

  return 0;
}
$ ./auto-var_2
count = 1
count = 2
count = 3

🔳大域変数:プログラムのどこからでも読み書きができる変数

大域変数は関数ではない場所で宣言する。

#include <stdio.h>

int global_number;

void func_1(void){
  printf("from func_1: %d\n", global_number);
  return;
}

void func_2(void){
  printf("from func_2: %d\n", global_number);
  return;
}

void func_3(void){
  printf("from func_3: %d\n", global_number);
  return;
}

int main(int argc, char const *argv[])
{
  global_number = 1;
  func_1();

  global_number = 10;
  func_2();

  global_number = 100;
  func_3();
  
  return 0;
}
$ ./global 
from func_1: 1
from func_2: 10
from func_3: 100

別ファイルからの大域変数の参照:extern指定子

extern指定子は、別のファイルに宣言してある変数や関数を利用したいときに、「あとでリンクするときに、実体がありますよ」と指定するためのキーワード。

extern_sub.c

int global_number = 99;

extern_main.c

#include <stdio.h>

extern int global_number;

int main(int argc, char const *argv[])
{
  printf("global_number = %d\n", global_number);
  return 0;
}
PROGRAM = extern
OBJS =  extern_sub.o extern_main.o
SRCS =  $(OBJS:%.o=%.c)
CC =  gcc
CFLAGS =  -g -Wall
LDFLAGS =

$(PROGRAM):$(OBJS)
    $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LDLIBS)
$ make -f Makefile.extern 
gcc -g -Wall   -c -o extern_sub.o extern_sub.c
gcc -g -Wall   -c -o extern_main.o extern_main.c
gcc -g -Wall  -o extern extern_sub.o extern_main.o 
$ ./extern 
global_number = 99

🔳const:記憶クラス指定子

constは、初期化した値から一切変更できなくなる指定子で、あらかじめ決められた値を、プログラム中で変更したくない場合に利用する。constが指定された変数を、初期値以外から変更しようとするとコンパイルエラーになる。

#include <stdio.h>

int main(int argc, char const *argv[])
{
  const char character = 'A';
  const int number = 1;

  printf("character is = %c\n", character);
  printf("number is %d\n", number);

  character = 'B';
  number = 2;

  return 0;
}
$ make -f Makefile.const 
gcc -g -Wall   -c -o const.o const.c
const.c:11:13: error: cannot assign to variable 'character' with const-qualified type
      'const char'
  character = 'B';
  ~~~~~~~~~ ^
const.c:5:14: note: variable 'character' declared const here
  const char character = 'A';
  ~~~~~~~~~~~^~~~~~~~~~~~~~~
const.c:12:10: error: cannot assign to variable 'number' with const-qualified type
      'const int'
  number = 2;
  ~~~~~~ ^
const.c:6:13: note: variable 'number' declared const here
  const int number = 1;
  ~~~~~~~~~~^~~~~~~~~~
2 errors generated.
make: *** [const.o] Error 1