勉強会資料のレビュー

今年は勉強会の講師ではなく、お目付役となったので、ちょっと気楽だ。入社からずっと教えてきた4年目のメンバーが講師をすることになったので、お手並み拝見である。

と思っていたら、C言語勉強会の資料を見つけたので、お節介ながらレビューしてみる。

Windows より Mac より Linux がいい

第2回
http://www.brown-note.net/dist/toaru/ch02.pdf

  • 7ページ目

「ポインタ変数の値=変数の値」というのは説明としては乱暴かな。とりあえず「メモリ上のアドレス*1を表している」ぐらいの説明がよいと思う。

  • 9ページ目
p = (0x60000000) + 1

まぁこれはセミコロンがついていないので、厳密にはコードでは無いのかもしれないが、このままではwarningが出るはずだ。これは型があっていないからで、コンパイラを黙らせるにはキャストする必要がある。

printf("%c\n", *p);
p = (char *)0x60000000 + 1
  • 13ページ

「*p を実行するとみんなの友達♪セグメンテ〜ションエラ〜♪」
となるかは運次第。何事もなく実行されることも珍しくない。

  • 14ページ

– intだと4バイト以上の領域を持っています。
– ただアドレスを +1 しただけでは、うまくいきません
+1したとき、int分だけ移動させなくてはいけません。え?

これはポインタ演算の説明だと思うが、ちょっと意味がわからないかな。
型TYPEに対してポインタ変数pを以下のように宣言する。

TYPE *p;

このときp + 1はsizeof(TYPE)だけ増加する。
具体的には

int *p;

printf("sizeof(int) = %d: p(%p), p + 1(%p)\n", sizeof(int), p, p + 1);
  • 20ページ

文字列コピー関数のバリエーションになるけどその前に[]演算子の説明をしておいた方がよい。特に

ポインタ変数pと整数型変数iに対して *(p + i) を p[i]と定義する。

ついでに関数に配列は渡せないことも合わせて説明する方がよいと思う。

  • my_strcpy

個人的に my_strcpyのバリエーションの中ではループの外で終端文字を設定するのは、どうもスマートじゃない気がする。私のお薦めは下記だがいかが?

void  my_strcpy(char *pDst, char *pSrc)
{
    int i;
    
    for (i = 0; ;i++) {
        pDst[i] = pSrc[i];
        if (pDst[i] == '\0') {
            break;
        }
    }
  • 25ページ

配列の全要素をもれなく舐めるにはおきまりのfor(i = 0; i < n; i++)を使いましょう。
個人的には以下のように書きたい。

int sum(int *pAry,  int n)
{
    int s = 0;
    int i;
     
    for (i = 0; i < n; i++) {
        s += pAry[i];
    }

    return  s;
}

リストは色々ありそうだが、コードをみれないので、略。できれば後日みます。

  • 32ページ

まとめページだが色々ある。
「ポインタ変数は、数字×ポインタ先のバイト数– ポインタ変数を使えば、短いコードで書ける
– ポインタ変数を使えば、読みにくいコードで書ける」
→「ポインタ変数はアドレスとその型情報」
「すべて、コンパイラが自動でやってくれる」
→「ポインタ演算は、指している型に合わせて、コンパイラが指しているアドレスを進めてくれる」

「ポインタ変数を使えば、短いコードで書ける」
「 ポインタ変数を使えば、読みにくいコードで書ける」
→書き方次第じゃない?私が書くと、ポインタ使うからと言って短くはならない。構造体が入れ子になっている場合、ポインタを使った方が、読みやすくなることも珍しくない。

「ポインタ変数を使えば、高速なコードが書ける」
コンパイラの最適化を考えれば、ポインタを使っても高速になるとは限らない。

*1:C言語の規格上はアドレスと限定していないので、もしかしたらアドレスではないかもしれない。しかし通常の環境ならアドレスと考えてよいし、アドレスじゃない場合を考えられるのは、本当にポインタを理解してからになるだろう。