目次
はじめに
はじめに
Visual C++ 2010 Expressのインストール
プログラムの作成
hello.c
コンパイルと実行
C言語プログラミングの学習環境
終了ステータスって?
整数値を3桁区切りで表示するプログラム
課題1 「整数値を3桁区切りで表示する」
ソースコードの雛形
h20a6.c
ソースコードの解説
配列の要素を反転する
課題2 「整数型の最大値と最小値を表示する」
h20a6_min.c
ソースコードの解説
課題3 「64ビットの整数値を表示する」
h20a6_x64.c
ソースコードの解説
他の言語のlong型
課題4 「整数値を4桁区切りの16進数で表示する」
h20a6_hex.c
ソースコードの解説
多倍長整数の加算を行うプログラム
課題1 「多倍長整数型を作る」
ソースコードの雛形
h21a9_set.c
ソースコードの解説
課題2 「多倍長整数の比較を行う」
h21a9_cmp.c
ソースコードの解説
課題3 「多倍長整数の加算を行う」
h21a9_add.c
ソースコードの解説
条件演算子を使用する
課題4 「多倍長整数の減算を行う」
h21a9_sub.c
ソースコードの解説
課題5 「多倍長整数型に符号を追加する」
h21a9_ssub.c
ソースコードの解説
課題6 「符号付き多倍長整数の加減算を行う」
h21a9_sign.c
h21a9_sign.c - part2
ソースコードの解説
数当てゲームを行うプログラム
課題1 「重複のない4桁の乱数を生成する」
ソースコードの雛形
h18a6_prev.c
ソースコードの解説
擬似乱数って?
課題2 「マスターマインドを作成する」
ソースコードの雛形
h18a6.c
ソースコードの解説
課題3 「平均推測回数を表示する」
h18a6_average.c
ソースコードの解説
課題4 「組合せを用いてマスターマインドを解くAIを作成する」
h18a6_ai.h
h18a6_ai.c
h18a6_ai_comb.c
ソースコードの解説
課題5 「順列を用いてマスターマインドを解くAIを作成する」
h18a6_ai_perm.c
ソースコードの解説
課題6 「順列のみを用いてマスターマインドを解くAIを作成する」
h18a6_ai_perm10.c
ソースコードの解説
ソースコードの分割
文字列のURLエンコードを行うプログラム
課題1 「URLエンコードを行う」
ソースコードの雛形
h16a6.c
ソースコードの解説
ポインタを扱うときの注意
課題2 「空白文字を+記号に置換する」
h16a6_space.c
ソースコードの解説
課題3 「URLデコードを行う」
h16a6_decode.c
ソースコードの解説
相対パスを絶対パスに変換するプログラム
課題1 「UNIX形式のパスを変換する」
ソースコードの雛形
h21h9.c
ソースコードの解説
課題2 「Windows形式のパスを変換する」
h21h9_win.c
ソースコードの解説
課題3 「両方の形式を変換する」
h21h9_both.c
ソースコードの解説
WindowsでもUNIXでもコンパイルできるソースコード
課題4 「ファイルの有無を確認する」
h21h9_exists.c
ソースコードの解説
標準ライブラリ関数の調べ方
単語幅でワードラップを行うプログラム
課題1 「単語幅でワードラップする」
ソースコードの雛形
h17h6.c
ソースコードの解説
課題2 「文字列をトークン分割する」
h17h6_token.c
ソースコードの解説
課題3 「改行文字に対応する」
h17h6_newline.c
ソースコードの解説
Windowsのフォントから文字幅を取得してみる
文字数でワードラップを行うプログラム
課題1 「文字数でワードラップする」
ソースコードの雛形
h22h9.c
ソースコードの解説
ファイル記述子って?
課題2 「タブ文字に対応する」
h22h9_tab.c
ソースコードの解説
課題3 「定義済みのキーワードを参照する」
ソースコードの雛形
h22h9_keyword1.c
ソースコードの解説
課題4 「キーワードを定義する」
h22h9_keyword2.c
ソースコードの解説
奥付
奥付

閉じる


<<最初から読む

11 / 120ページ

試し読みできます

ソースコードの解説

convert()

 関数convert()の中心は与えられた整数値numを一の位から順に取り出していくループ処理です。 その中で数字への変換、桁数のカウント、コンマの挿入を行います。 10進数の一の位を取り出すのに10で割った余り(num % 10)を計算するのは数学的な基礎知識なので覚えてしまいましょう。
 負の整数への対応として変数minusにフラグを立てておき、後で符号を書き足しています。 桁を区切るループ処理は正の整数の場合と共通です。
 なお以上の処理で出来上がる文字列は逆向きになってしまっているため、最後に配列str[]の要素を並べ直して辻褄を合わせています。

整数値を3桁区切り形式の文字列に変換する処理

試し読みできます

配列の要素を反転する

Tips : 配列の要素を反転する

 配列の要素を並べ替える処理はC言語演習課題の定番で、反転処理もその1つです。 配列の先頭要素と末尾要素から入れ替えを開始し、内側に向かって処理を進めて行きます。 配列の真ん中まで来たときに反転が完了します。

  1. /**
  2. * @brief 配列の要素を反転する。
  3. *
  4. * @param [in,out] array 反転させる配列
  5. * @param [in] length 反転させる配列の要素数
  6. * @return なし
  7. */
  8. void reverse(int array[], int length)
  9. {
  10. int i, j;
  11. int temp;
  12. for( i = 0, j = length - 1; i < j; i++, j-- )
  13. {
  14. temp = array[i];
  15. array[i] = array[j];
  16. array[j] = temp;
  17. }
  18. }

 基本情報技術者試験の穴埋め問題にもなっていますが、for文の条件が「i != j」でなく「i < j」となっている理由は、配列の要素数lengthが偶数の場合に添字ijがすれ違いを起こして処理が止まらなくなってしまうためです。
試し読みできます

課題2 「整数型の最大値と最小値を表示する」

課題2 「整数型の最大値と最小値を表示する」

 long型の最大値と最小値は、LONG_MAXLONG_MINという名前でヘッダファイルlimits.hに定義されています。これらの値を3桁区切り形式の文字列に変換してみてください。
 実は基本情報技術者試験で出題された課題1の関数convert()にはバグがあるため、LONG_MINを正しく変換できません。 そのバグの原因を特定し、関数convert()を修正してください。

  1. #include <stdio.h>
  2. #include <limits.h>


  3. int main(int argc, char *argv[])
  4. {
  5. char buffer[BUFSIZE];
  6. /* テストデータでconvert()を実行する。 */
  7. convert(LONG_MAX, buffer);
  8. printf("%ld => %s\n", LONG_MAX, buffer);
  9. convert(LONG_MIN, buffer);
  10. printf("%ld => %s\n", LONG_MIN, buffer);
  11. return 0;
  12. }

試し読みできます

h20a6_min.c

  1. /** @file h20a6_min.c
  2. * @brief 整数値を3桁区切りで表示するプログラム
  3. *
  4. * - 負数の場合、先頭にマイナス符号を付ける。
  5. * - 数値の下位から3桁ごとにコンマを挿入する。
  6. * - LONG_MIN(-2147483648)の表示に対応する。
  7. *
  8. * @see 平成20年度秋期 午後試験 問6
  9. */
  10. #include <stdio.h>
  11. #include <limits.h>


  12. /** 数字列バッファサイズ */
  13. #define BUFSIZE 15


  14. void convert(long num, char str[]);


  15. /**
  16. * @brief 整数値から3桁区切りの数字列を生成する。
  17. *
  18. * @param [in] num 桁区切りしたい整数値
  19. * @param [out] str 桁区切りされた数字列
  20. * @return なし
  21. */
  22. void convert(long num, char str[])
  23. {
  24. const char table[] = "0123456789";
  25. int minus = 1; /* フラグの使い方を変更 */
  26. int i = 0, j = 0;
  27. char tmp;
  28. /* 負数の場合、フラグを立てておく。 */
  29. if( num < 0 )
  30. {
  31. minus = -1;
  32. }
  33. do
  34. {
  35. /* 最下位桁を取り出し、1桁右シフトする。 */
  36. str[j++] = table[(num % 10) * minus]; /* 負数の対策 */
  37. num /= 10;
  38. /* 3桁ごとにコンマを挿入する。 */
  39. i++;
  40. if( i % 3 == 0 && num != 0 )
  41. {
  42. str[j++] = ',';
  43. }
  44. } while( num != 0 );
  45. /* 負数の場合、マイナス符号を付ける。 */
  46. if( minus != 1 )
  47. {
  48. str[j++] = '-';
  49. }
  50. str[j--] = '\0';
  51. /* 逆向きに出来上がった数字列を並べ直す。 */
  52. for( i = 0; i < j; i++, j-- )
  53. {
  54. tmp = str[i];
  55. str[i] = str[j];
  56. str[j] = tmp;
  57. }
  58. }


  59. /**
  60. * @brief エントリポイント
  61. *
  62. * @param [in] argc コマンドライン引数の数
  63. * @param [in] argv コマンドライン引数
  64. * @return 終了ステータス
  65. *
  66. * @par 実行方法:
  67. * cmd> h20a6_min.exe
  68. */
  69. int main(int argc, char *argv[])
  70. {
  71. char buffer[BUFSIZE];
  72. long test_data[] = {
  73. 1234567L,
  74. -57482L,
  75. 63L,
  76. -999999L,
  77. 0L,
  78. LONG_MAX,
  79. LONG_MIN
  80. };
  81. int t, tests = sizeof(test_data) / sizeof(*test_data);
  82. /* テストデータでconvert()を実行する。 */
  83. for( t = 0; t < tests; t++ )
  84. {
  85. convert(test_data[t], buffer);
  86. printf("%ld => %s\n", test_data[t], buffer);
  87. }
  88. return 0;
  89. }

試し読みできます

ソースコードの解説

バグの原因

 関数convert()がlong型の最小値LONG_MINを変換できない原因は、整数値numが負数の場合に行っている「num = -num;」の処理にあります。 この処理は負の整数を正の整数と同じコードで変換できるようにする目的で記述していました。
 Windows用のCコンパイラではlong型が32ビットなので、LONG_MINの値は-2147483648(= -2^31)、LONG_MAXの値は2147483647(= 2^31 - 1)です。 このことからLONG_MINの符号を反転した値は2147483648となり、LONG_MAXより大きな値(オバーフロー)となってしまっていたことが判明します。 この状態で「num % 10」や「num /= 10;」を計算しても期待する結果は得られません。

LONG_MAX < -LONG_MIN

バグの修正

 LONG_MINの変換に対応するためには「num = -num;」の処理を削除しなければなりませんので、代わりの処理を考えましょう。 仮に変数numに負数を格納したまま処理を進めた場合、1桁の数値を数字に変換する「str[j++] = table[num % 10];」の処理で配列table[]の添字となる「num % 10」の計算結果が負数になってしまうという不都合が生じます。
 この不都合を回避するには「(num % 10) * -1」の計算が必要です。 そこで変数minusの使い方を変更し、件の処理を「str[j++] = table[(num % 10) * minus];」と改めました。 変数minusの値は変換する整数値が正数の場合に「1」、負数の場合に「-1」と設定します。
 以上の修正により、関数convert()でlong型の最小値LONG_MINを正しく変換できるようになりました。

読者登録

nakano.hさんの更新情報・新作情報をメールで受取りますか?(読者登録について