プログラミング実習II情報 教科書の正誤表†
『C言語によるプログラミング 基礎編 第3版』(1刷)の明らかな誤植だけでなく、初学者には混乱の元になる無駄な記述を以下に指摘します。
- p.61 上から2行目
- 『最初の31文字までが有効』→『少なくとも最初の31文字までが有効』
環境依存で、もっと長い変数名を区別することもあります。
- p.61 上から8--9行目
- 『同じ変数として扱われる』→『同じ変数として扱われる可能性のある』
環境によっては区別されます。
- p.64 表3.3
- long doubleの使用ビット数(最低保証)は、言語仕様上はdouble以上であることのみが決められていて、具体的な値は指定されてないはずです。少なくとも80ではなく、VisualStudioのあるバージョンでは64(つまりdoubleと同一)です。
- p.64 表3.4
- signedで表せる値の最小値が、-32768のように -2^n になるのは、マイナスを「2の補数」で実現した場合に限ります。C99では他に「1の補数」と「符号と絶対値」の2通りの実現方法が想定されており、この場合は最小値が -(2^n-1)(つまり最大値の符号違い)になります。
- p.65 図3.3の4行上
- 『(この表現方法はコンピュータによって異なります)』→『(この表現方法もコンピュータによって異なります)』
あたかも整数型と浮動小数点で状況が異なるかのような言い回しですが、整数値のマイナス表現にも3通りのバリエーションがあります。(p.68 の Coffe Break 3.4 で、「2の補数」であることが決まっているかのような説明も間違いです。)
- p.65 図3.3
- 浮動小数点の内部表現には、「符号部」を含める必要がありますが、この図では抜けています。
- p.65 表3.5
- double の正の小さな値の 2.2251e-308 は正規化数に限った場合で、精度が落ちてよければ4.9e-324まで表せます。負の値や、float, long double でも同様に、より0に近い値まで表せます。
- p.66 3行目
- 『精度がよい』→『精度が同じかよい』
- p.66--67 coffee break 3.2 内
- 「最小値」という単語が、文脈によって2通りの意味で用いられています。「doubleの最小値」には0より大きい正規化数という前提がついているのに対して、「intの最小値」にはその前提がありません。なお、前提なしの「doubleの最小値」は -DBL_MAX です。
- P.67 coffee break 3.3
- intのビット数は、「アーキテクチャで提供される自然の大きさ」(K&R第2版日本語版)として選ばれます。演算が高速であることは、(考慮すべきですが)絶対的な条件ではありません。
- p.78 上から4行目
- 『%lf』→『%Lf』printf() の %f と %lf の動作は同じです。long double には %Lf を使います。
- p.78 下から1行目
- 『全体で15桁、小数点以下3桁』→『全体で少なくとも15桁、小数点以下がちょうど3桁』
- p.79 上から2行目
- 『全体で15桁』→『全体で少なくとも15桁』
- p.150 リスト4.11
- 7行目の変数定義は不要です。13行目と14行目でも変数定義されています。
- p.184 リスト5.6の直前の段落からリスト5.7まで
- 『また、関数の定義では、その多くを省略することができます...』→関数の定義では、C言語の旧規格との互換性のために、省略できるキーワードがいくつかありましたが、省略するメリットはありませんのできちんと記述するようにしましょう。
- p.184 脚注13
- 『引数を省略すると、void型の引数となります。』→『引数を省略すると、引数の型チェックがされなくなり、どんな引数で呼び出してもエラーになりません。』
voidの省略が「引数なし」の意味になるのは、C++やJavaなど、他の言語の場合です。
- p.195 リスト5.12 と p.196 2段落目
- プロトタイプ宣言は、「関数定義」と「関数呼び出し」の整合性を調べるためのものです。7行目のように、関数の中でプロトタイプ宣言を行っても、16行目の関数定義との整合性は調べられません。プロトタイプ宣言は関数の外(例えば2行目)に移動すべきです。ローカル変数と一緒に宣言するメリットは、まったくありません。
- p.196 5.2.3節 1行目
- 『maz(24,12)』→『max(24,12)』
- p.199 下から3行目
- 『総省選択』→『総称選択』
- p.200 リスト5.16の6行目
- 『_Generic((X, Y), ...』→『_Generic((Y), ...』_Generic() の総称選択に使える値は1個だけです。(X, Y) としても、カンマ演算子(逐次評価)によって X が無視されて Y のみが使われるので、コンパイラによっては警告されます。X,Y のペアで判定されてるかのような表記 (X,Y) はやめておくべきでしょう。
- p.236 下から7行目
- 『オプション(-lm)をつけてコンパイルする必要があります。』→『オプション(-lm)の必要な場合があります。』
Cygwin のように、gcc でも -lm の不要な環境があります。
- p.238 中央の数式
- 分散の式の最後の項が違います。カッコの位置を次のようにします。(あるいは、カッコは不要です。)
- p.263 上から(ソースコードを含めて)10行目
- 『/* Case2 */ int a[3][2] = {1,2,3,4,5,6}; と定義することもできます。』→『int a[3][2] = {1,2,3,4,5,6}; という記述はエラーにはなりませんが、「初期化子の周りに中括弧がありません」といった警告が出ることがあります。』
- p.283 Coffe Break 7.2
- strcpy_s() や strcat_s() は C11 で導入された関数ですが、オプショナル機能と位置づけられているため、例えば gcc では使えません。
- p.295~297 リスト8.3, 8.4, 8.5
- sizeof(int) を printf() で表示するためには "%zd" の書式指定子を使うか、値を(int)でキャストする必要があります。
- p.298 リスト8.6の11行目から13行目
- 『%d』→『%td』ポインタどうしの減算の結果は ptrdiff_t 型になり、この値を表示するためには "%td" の書式指定子を使うか、あるいは値を(int)でキャストする必要があります。
- p.301 リスト8.9の6行目
- 『int i;』は不要です。
- p.309 リスト8.14の7行目
- 『 %s\n" 』→『 "%s\n" 』最初のダブルコーテーション(")が抜けています。
- p.317 2段落目からp.318 2行目
- 『また、構造体タグの省略について...警告を出すコンパイラも存在します。』→構造体タグを省略する手法は、その構造体を他の場面で利用できなくなるので、通常は用いられません。後述の9.5.1節(p.339)のように、typedef と組合せて型名を名付ける場合には、構造体タグを省略する手法がよく用いられます。
- p.320 リスト9.1
- 構造体がmain関数内で宣言されていますが(しかも変数定義を同時に行なっていますが)、こうするとこの構造体は通用範囲がmain関数に限定されてしまい、他の関数で用いることができませんので、このような使い方はしません。通常は複数の関数で扱えるように、構造体の宣言は関数の外側(特にプロトタイプ宣言の直前)に記述します。そして変数定義は分離することになります。
- p.335 リスト9.5の41行目
- 初期化されない可能性があるため、コンパイラによっては警告されます。8行目の構造体変数max_dis_seat[]を、定義と同時に(0で)初期化するのが標準的な作法です。
- p.338 ソースコード内の下から3行め(print_address()関数内)
- printf(" zip:%l\n", addr.zip);→printf(" zip:%d\n", addr.zip);
- p.340--345
- 論理型の変数名には、is_selected のように is + 形容詞(過去分詞)にする習慣があり、さらに is を省略する場合もあります。しかし、ここでは selected が laguage_t 型になっていて、紛らわしいです。この用例では受け身にする必要性は見出だせないので select のほうがよいでしょう。
10章†
- p.371 リスト10.7
- プログラムの中程で「if( (fp=fopen()) == NULL)」とNULLとの比較が記述してあるのに、もう少し下では『while(fgets(string, STRING_SIZE, fp))』とNULLとの比較が省略されていて、一貫性に欠けます。このページの2行目には「fgets関数はNULLを返します」との記述があるので、『while(fgets(string, STRING_SIZE, fp) != NULL)』と明示するのがよいでしょう。
- p.373~374 リスト10.8と10.9
- 『if (fp... 』→『if ((fp... 』どちらのリストも、3ヶ所のカッコ始まりが抜けています。
11章†
変数名や関数名の命名規則に、C言語では「すべて小文字、単語は_をはさんで連結する」というスネークケースが用いられるのが一般的ですが、「単語の先頭を大文字にして隙間なくつなげる」というキャメルケースや、大文字小文字の使い分けルールの読み取れない部分が残っています。(第2版よりは減りました。)スネークケースで統一されるよう、変数名は以下のように読み替えるのがよいでしょう。
- 383ページ
- 『MonthlyRecord_t』→『monthly_record_t』
『DailyRecord_t』→『daily_record_t』
また、このように typedef と組み合わせる場合、構造体にタグ名(MonthlyRecord_T や DailyRecord_T)をつける必要はありません。
- 387ページ
- 『MonthlyRecord_t』→『monthly_record_t』
『dayCount』→『day_count』
『dataFile』→『data_file』
他にも多数あります。