『C言語によるプログラミングの基礎』の疑問点†
授業の教科書『C言語によるプログラミングの基礎』(田中敏幸著、コロナ社)の非公式で勝手な正誤表です。第1版第2刷(2004年1月15日発行)の記述に基づいています。
このページの内容については、まったく保証しません。
2.3†
- p.11 「#include <stdio.h> これはプリプロセッサといいプログラムの中で使う関数を指定する部分である。 … プリプロセッサとしてどのようなものを用いるかは」
- プリプロセッサは前処理を行うソフトウェアのことなので、この部分は「#include <stdio.h> これはプリプロセッサ指令といい … ヘッダファイルとしてどのようなものを用いるかは」が正しいのではないか。
- 同 「どのような場合でもstdio.hは必ず宣言しておかなければならない」
- 初心者向けの記述とは思うが、そのソースファイルでprintfなどの標準入出力関数を用いないときはstdio.hは不要である。
- p.12 「関数の最後には必ず戻り値を返す関数が必要となる。この戻り値を返す関数がreturnである」
2.4†
- p.16 「C++が開発されたときに、改行までを一つの単位としてコメント文にする方法も付け加えられた」
- 誤りとはいえないが、「//」型のコメントはC言語の先祖にあたるBCPLから復活したものである。
3.8†
4.2†
- p.42 「Visual C++ではプログラム中に実数値を書くとすべて倍精度とみなされる」
- Visual C++だけでなく、倍精度(double)になるのが標準規格である。
4.3†
- p.56 「インクリメント演算子(++)とデクリメント演算子(--)は、浮動小数点(実数)の変数に対して用いることはできない」
4.4†
- p.68 「最近では、プログラミングの際に、特殊な場合を除いてgoto文は使わないというのが一般的になっている」
5.2†
- p.82 「これはPascalなどのプログラミング言語で用いられた書法だが、最近では、C言語でもこのようにmain関数を最後に置くプログラムがよく書かれるようになった」
- Pascalについては言語仕様で定められている。CについてはANSI Cの制定(1989年)以来、増えたのではないかと思われるが、これも「最近」や「よく」という表現がどの程度のことを言っているのかひっかかる…。
- p.86 「階乗など一部のアルゴリズムに使われているだけのようである」
- 一部かもしれないが、重要なアルゴリズムに再帰を使うものは多い。ほとんどループを使わず、代わりに再帰を使うプログラミング言語もある。
5.3†
- p.89 「5.3.2 外部変数(extern)」の説明
- 以前このページで教科書のexternの使い方は間違いだと書いたが、『プログラミング言語C』(K&R)の第1章(1.10)にも同じような使用例があり、これは私の解釈のほうの間違い。教科書の記述の通り、Cで「外部変数」はグローバル変数と同義であり、externはその使用宣言である。
- ただし、K&Rではこのような場合には「普通のやり方は、… extern宣言をすべて省く」とも書いてあり、教科書の「各関数の中でもexternを用いた使用宣言をするのが正式の使用方法である」という説明は、ちょっと「正式」の根拠が怪しい。
- K&Rでは、外部宣言とexternキーワードには直接の関係はない(K&R付録A10.2)とも書いてある。これは、externは外部変数(や関数)の使用宣言であって、外部変数のことをexternというのではない、という意味ではないだろうか。ちなみに、この教科書にはstaticな外部変数についての説明はない。
5.4†
- p.95 「stdio.hはプログラムの最初に必ずインクルードしなければならない」
- そのソースファイルのなかで、printfなどの標準入出力関数を用いないときはstdio.hは不要である。
- p.96 「#define PISQR PI*PI」
5.5†
- p.104 「理由についてははっきりしないが、2次元以上の配列で(1)の方法を用いると、プログラムが正常に実行されない場合がある」
- 本当だろうか? たとえば、Visual C++のどれかのバージョンでは、これが正常に実行されないのだろうか?
6.1†
7.2†
- p.151 「コンピュータの処理能力が低く、… プログラムの高速化のために*(a+i)のようなポインタ演算が好まれていた。初期のCプログラミングの本では、できるだけポインタ表現を使うよう心がけていたものが多く見られる。現在では、配列a[i]という書式を用いても …」
- *(a+i)とa[i]についていえば、今のコンパイラでも昔のコンパイラでも翻訳結果に違いはないだろう(アドレスレジスタ+インデックスレジスタ)。*p++とa[i++]のことならばそういうこともあるかもしれないが、Cを使い慣れていればポインタ表記が分かりにくいということはないだろう。
- p.165 リスト7-13
- 「#include <stdlib.h>」がない。
- 関数keisanで、スタック上のアドレスを呼び出し元の関数にreturnしている。keisanの中のbの宣言にstaticをつけるか、bはmallocによってヒープに確保しないといけない。
7.3†
- p.172 「この場合にはポインタと配列はまったく同じことを意味する」
- 配列名はその先頭要素へのポインタに適宜変換されるのであって、ポインタとまったく同じではない。具体的には、sizeof演算子での扱いが違う。sizeof(array)は配列全体のサイズであるが、sizeof(ptr)はポインタ変数のサイズである。