the ド田舎エンジニア

東京とは名ばかり 八王子市は尾崎 幸一朗(通称:サチロー)による気まぐれブログです

久しぶりのC言語 その3

こんばんは。
サチローこと幸一朗です。

久しぶりのC言語といいつつ、最近はちょくちょく触っているためか久しぶり感がなくなってきました(笑)

それにしても難しい。
教えるのは難しい。
多分向いてない。

今回は配列、文字列、ポインタ。
C言語における難所の一つ。

配列とは、同じ型を持つ複数のデータを管理するものです。

#include <stdio.h>

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

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

  return 0;
}

表示結果は『12345』。

array[x]のxは、x番目の要素を参照するもの。

厳密には、arrayという変数が確保しているメモリの先頭アドレスからsizeof(array[0]) * xした値を加算したアドレスを参照する(で合ってるかな?)もの。

先頭を参照する場合は「0」。
以降「1」、「2」・・・と指定します。
要素の数以上の値を指定するとエラーが起きます。
arrayという変数が確保していない(範囲外)のアドレスを参照することになるためです。


そして、この形式で表現されるのが、文字列。
C言語には文字列が存在しません。

#include <stdio.h>

int main(void)
{
  char str[] = "hoge";

  printf("%c\n", str[0]);

  return 0;
}

表示結果は『h』となる。
"hoge"は文字の配列なのです。

ちなみにstrの中身はこう。
str[0]:'h'
str[1]:'o'
str[2]:'g'
str[3]:'e'
str[4]:'\0'

'\0'は終端を示す。
こいつが無いとC言語は文字の終わりを理解できない。


そして配列を学び始めると「アドレス」という単語がボコボコ出てくる。
そこで、いよいよ「ポインタ」の登場です。

ポインタとは、変数のアドレスを格納する。
変数のアドレス?何のこっちゃ?

変数を使用するには領域が必要です。
ハードディスクにいろんなデータを突っ込んでいくと容量を消費するように、変数も値を記憶しておくためにメモリを使用します。

int a = 0;

printf("%p\n", &a);

みたいなことをすると、aという変数がどこのアドレスに割り当てられているかを確認することができます。

ポインタ変数を使うとこんな感じ。

int a = 0;
int *p;

p = &a;

printf("%p\n", p);

 // ポインタ変数に「*」を付けると、アドレスに格納されている値を得る
printf("%d\n", *p);


ポインタ変数のアドレスもポインタ変数に格納できる。

int a = 10;
int *p;
int **pp;

p = &a;
pp = &p;

printf("%p\n", &pp); // 変数「pp」のアドレス
printf("%p\n", pp);  // 変数「p」のアドレス
printf("%p\n", *pp);  // 変数「a」のアドレス
printf("%d\n", **pp);  // 10


これの使いやすさを理解するには実際にコードを組む経験を積んだ方が早いです。


これらを踏まえて、こんな課題を出してみました。

①配列を用いて以下を標準出力してください。
「1 5 103 65 33」

②標準入力から文字列を得てください。その文字列において、文字「a」を検出した場合は「hit」、全く検出しなかった場合は「no hit」を1度だけ標準出力してください。

③標準入力から得た文字列を反転して標準出力してください。

④変数「i」を宣言し、そのアドレスを標準出力してください。

⑤変数「i」のアドレスをポインタ変数「p」に格納し、ポインタ変数を用いて変数「i」のアドレスを標準出力してください。

⑥「⑤」で使用したポインタ変数「p」のアドレスをポインタ変数「pp」に格納し、ポインタ変数「p」のアドレスを標準出力してください。


概ねこんな感じの出題となりました。
未だに手探りです(笑)