1 C言語入門 第10週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) 2 再帰呼び出し 関数 3 教科書 pp.190-197. 再帰関数 • 自分で自分を呼ぶ関数 𝑛の階乗(factorial) 𝑛! = 𝑛 × 𝑛 − 1 × ⋯ × 2 × 1 factoriali_with_recursion.c factoriali_with_loop.c int factoriali(int n) 再帰呼び出し { if (n <= 1) { return 1; } else { return n * factoriali(n - 1); } } int factoriali(int n) { int f = 1, i; for (i = 1; i <= n; i++) { f *= i; } return f; } 再帰による実装 factoriali_test.c ループによる実装 int f, i, n; fprintf(stderr, "n = ? "); scanf("%d", &n); printf("n! = %d\n", factoriali(n)); 4 教科書 pp.190-197. 階乗 (factorial)関数 • 考え方 • 再帰の場合 𝑛! = 𝑛 ⋅ 𝑛 − 1 ! 𝑛−1 != 𝑛−1 ⋅ 𝑛−2 ! ⋮ 1! = 1 ⋅ 0! 0! = 1 • ループの場合 再帰の場合は 1つ小さな値を 引数にして 自分で自身を呼ぶ だけ それ以上小さく 出来なくなったら ルールに沿って 適当な値を返す 𝑛! = 1 ⋅ 1 ⋅ 2 ⋯ 𝑛 − 1 ⋅ 𝑛 𝑛 ループの場合はこの数列を作り𝑛個積算していく 教科書 pp.190-197. 例題: factoriali_with_recursion.c • int型の整数𝑛について階乗(factorial) 𝑛!を求め る関数factoriali(n)を再帰を用いて実装せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに作成 せよ • n<0の場合は標準エラー出力にエラーメッセージを表 示してexit関数で終了せよ • 引数 • int n : 整数 • 戻り値 • 𝑛! をint型で返せ 5 教科書 pp.190-197. 例題: factoriali_with_loop.c • int型の整数𝑛について階乗(factorial) 𝑛!を求め る関数factoriali(n)をループを用いて実装せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに作成 せよ • n<0の場合は標準エラー出力にエラーメッセージを表 示してexit関数で終了せよ • 引数 • int n : 整数 • 戻り値 • 𝑛! をint型で返せ 6 7 例題: factoriali_with_*.c • factoriali_test.c による動作テスト mintty + bash + GNU C $ gcc factoriali_test.c factoriali_with_recursion.c && ./a c = ? 5 120 mintty + bash + GNU C $ gcc factoriali_test.c factoriali_with_loop.c && ./a c = ? 5 120 8 [1] p.199,318. exit 関数 • void exit(int status); • プロセスを正常に終了させ終了コードを親プロセ スに返す • 引数: • staus: 終了コード • 正常終了時には 0、以上終了時には 0 以外を与え る。マクロ定義されているEXIT_SUCCESS, EXIT_FAILURE の値を用いても良い。 • 要 stdlib.h JM: exit (3) 9 エラー処理 • 例: n<0の場合は標準エラー出力にエラー メッセージを表示してexit関数で終了せよ factoriali_with_recursion.c if (n < 0) { fprintf(stderr, "Error: in file %s line %d: invalid value: n = %d\n", __FILE__, __LINE__, n); exit(EXIT_FAILURE); } mintty + bash + GNU C $ gcc factoriali_test.c factoriali_with_recursion.c && ./a c = ? -1 Error: in file factoriali_with_loop.c line 9: invalid value: n = -1 ただ、漠然とエラーと表示するのではなく 何処で、どういう理由でエラーになったのか、分かり易く表示するべき 10 警告の表示 • 深刻なエラーではない場合は警告を表示して そのまま処理を続ける方法もある 警告の表示 if (警告を表示する条件) { fprintf(stderr, "Warning: in file %s line %d: 警告を表示する理由等\n", __FILE__, __LINE__); } 11 第4週資料 pp.45-47. 警告の表示(デバッグ用) • デバッグ時のみ有効にしたい処理は、プリプ ロセッサディレクティブを用いて条件付きコン パイルを行う debug_test.c printf("always\n") #ifdef DEBUG printf("only for debug\n"); #endif DEBUG マクロが 定義されている場合のみ コンパイルされる mintty + bash + GNU C $ gcc debug_test.c && ./a always $ gcc debug_test.c -DDEGUB && ./a always only for debug -D オプションで コンパイル時に コンパイラに対して 直接マクロを定義出来る 12 エラー処理 • 今の例ではexit関数で終了せよと指示されて いたが、エラーだからと言って、いきなり終了さ れると困ることもある。 • 従って、普通は戻り値などでエラーを返して、そ の後の処理は呼び出し元に任せる。(例:標準ラ イブラリのpow等) • 戻り値でエラーを返せない場合は、引数にエ ラー通知用のポインタ変数を与える等の方法で 対処する。(例:標準ライブラリのstrtol等) 13 文字列 14 𝑁進数 • 各桁は𝑁種類の数字 (0~𝑁 − 1)で表す • 下の桁から、 𝑁 0 の桁、 𝑁 1 の桁、 𝑁 2 の桁、 … 8進数 10進数 16進数 0 0 0 0 1 1 1 1 10 2 2 2 11 3 3 3 100 4 4 4 101 5 5 5 6 6 6 7 7 7 8 8 9 9 110 8の桁へ 桁上がり 111 1000 • 現在の桁数で表せない 数値は桁上がりする 16の桁へ 桁上がり 2進数4桁 ⇕ 16進数1桁 2進数 2の桁へ 桁上がり 4の桁へ 桁上がり 2進数3桁 ⇕ 8進数1桁 8の桁へ 桁上がり 10 10の桁へ 桁上がり 1001 11 1010 12 10 a 1011 13 11 b 1100 14 12 c 1101 15 13 d 1110 16 14 1111 17 15 10000 20 16 e 16の桁へ 桁上がり f 10 15 𝑁進数 2進数 4桁(場合の数 2 4 ) 16進数 1桁(場合の数16 1 ) 2進数 8桁(場合の数 2 8 ) 16進数 2桁(場合の数16 2 ) 2進数16桁(場合の数 216 ) 16進数 4桁(場合の数16 4 ) 232 ) 2進数32桁(場合の数 16進数 8桁(場合の数16 8 ) 64 2進数64桁(場合の数 2 ) 16進数16桁(場合の数1616 ) 𝑥バイト(8𝑥ビット)の数値は 2𝑥桁の16進数で表すことが出来る 256の桁へ 桁上がり 2進数3桁 ⇕ 8進数1桁 2進数4桁 ⇕ 16進数1桁 2進数 8進数 10進数 16進数 11111000 370 248 f8 11111001 371 249 f9 11111010 372 250 fa 11111011 373 251 fb 11111100 374 252 fc 11111101 375 253 fd 256の桁へ 桁上がり 11111110 376 254 fe 11111111 377 255 ff 100000000 400 256 100 100000001 401 257 101 100000010 402 258 102 100000011 403 259 103 100000100 404 260 104 100000101 405 261 105 100000110 406 262 106 100000111 407 263 107 100001000 400 264 108 16 8bit整数の10進表現 下位4ビット 2進 上 位 4 ビ ッ ト 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 16進 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 2進数と10進数は桁数の対応で収まりが悪い 17 8bit整数の2進表現 下位4ビット 2進 上 位 4 ビ ッ ト 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 16進 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 0000 0000 0001 0000 0010 0000 0011 0000 0100 0000 0101 0000 0110 0000 0111 0000 1000 0000 1001 0000 1010 0000 1011 0000 1100 0000 1101 0000 1110 0000 1111 0001 0000 0001 0001 0001 0010 0001 0011 0001 0100 0001 0101 0001 0110 0001 0111 0001 1000 0001 1001 0001 1010 0001 1011 0001 1100 0001 1101 0001 1110 0001 1111 0010 0000 0010 0001 0010 0010 0010 0011 0010 0100 0010 0101 0010 0110 0010 0111 0010 1000 0010 1001 0010 1010 0010 1011 0010 1100 0010 1101 0010 1110 0010 1111 0011 0000 0011 0001 0011 0010 0011 0011 0011 0100 0011 0101 0011 0110 0011 0111 0011 1000 0011 1001 0011 1010 0011 1011 0011 1100 0011 1101 0011 1110 0011 1111 0100 0000 0100 0001 0100 0010 0100 0011 0100 0100 0100 0101 0100 0110 0100 0111 0100 1000 0100 1001 0100 1010 0100 1011 0100 1100 0100 1101 0100 1110 0100 1111 0101 0000 0101 0001 0101 0010 0101 0011 0101 0100 0101 0101 0101 0110 0101 0111 0101 1000 0101 1001 0101 1010 0101 1011 0101 1100 0101 1101 0101 1110 0101 1111 0110 0000 0110 0001 0110 0010 0110 0011 0110 0100 0110 0101 0110 0110 0110 0111 0110 1000 0110 1001 0110 1010 0110 1011 0110 1100 0110 1101 0110 1110 0110 1111 0111 0000 0111 0001 0111 0010 0111 0011 0111 0100 0111 0101 0111 0110 0111 0111 0111 1000 0111 1001 0111 1010 0111 1011 0111 1100 0111 1101 0111 1110 0111 1111 1000 0000 1000 0001 1000 0010 1000 0011 1000 0100 1000 0101 1000 0110 1000 0111 1000 1000 1000 1001 1000 1010 1000 1011 1000 1100 1000 1101 1000 1110 1000 1111 1001 0000 1001 0001 1001 0010 1001 0011 1001 0100 1001 0101 1001 0110 1001 0111 1001 1000 1001 1001 1001 1010 1001 1011 1001 1100 1001 1101 1001 1110 1001 1111 1010 0000 1010 0001 1010 0010 1010 0011 1010 0100 1010 0101 1010 0110 1010 0111 1010 1000 1010 1001 1010 1010 1010 1011 1010 1100 1010 1101 1010 1110 1010 1111 1011 0000 1011 0001 1011 0010 1011 0011 1011 0100 1011 0101 1011 0110 1011 0111 1011 1000 1011 1001 1011 1010 1011 1011 1011 1100 1011 1101 1011 1110 1011 1111 1100 0000 1100 0001 1100 0010 1100 0011 1100 0100 1100 0101 1100 0110 1100 0111 1100 1000 1100 1001 1100 1010 1100 1011 1100 1100 1100 1101 1100 1110 1100 1111 1101 0000 1101 0001 1101 0010 1101 0011 1101 0100 1101 0101 1101 0110 1101 0111 1101 1000 1101 1001 1101 1010 1101 1011 1101 1100 1101 1101 1101 1110 1101 1111 1110 0000 1110 0001 1110 0010 1110 0011 1110 0100 1110 0101 1110 0110 1110 0111 1110 1000 1110 1001 1110 1010 1110 1011 1110 1100 1110 1101 1110 1110 1110 1111 1111 0000 1111 0001 1111 0010 1111 0011 1111 0100 1111 0101 1111 0110 1111 0111 1111 1000 1111 1001 1111 1010 1111 1011 1111 1100 1111 1101 1111 1110 1111 1111 2進数は桁が多過ぎて直感的に分かり難い 18 8bit整数16進表現 下位4ビット 2進 上 位 4 ビ ッ ト 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 16進 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 01 11 21 31 41 51 61 71 81 91 a1 b1 c1 d1 e1 f1 02 12 22 32 42 52 62 72 82 92 a2 b2 c2 d2 e2 f2 03 13 23 33 43 53 63 73 83 93 a3 b3 c3 d3 e3 f3 04 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f4 05 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 06 16 26 36 46 56 66 76 86 96 a6 b6 c6 d6 e6 f6 07 17 27 37 47 57 67 77 87 97 a7 b7 c7 d7 e7 f7 08 18 28 38 48 58 68 78 88 98 a8 b8 c8 d8 e8 f8 09 19 29 39 49 59 69 79 89 99 a9 b9 c9 d9 e9 f9 0a 1a 2a 3a 4a 5a 6a 7a 8a 9a aa ba ca da ea fa 0b 1b 2b 3b 4b 5b 6b 7b 8b 9b ab bb cb db eb fb 0c 1c 2c 3c 4c 5c 6c 7c 8c 9c ac bc cc dc ec fc 0d 1d 2d 3d 4d 5d 6d 7d 8d 9d ad bd cd dd ed fd 0e 1e 2e 3e 4e 5e 6e 7e 8e 9e ae be ce de ee fe 0f 1f 2f 3f 4f 5f 6f 7f 8f 9f af bf cf df ef ff 2進数と16進数は相性が良い。2進数4桁が16進数1桁に対応するので直感的に分かり易い 19 教科書 p.51.,第2週資料 p.51. ASCII文字コード表 16進 上 位 4 ビ ッ ト 0 1 2 3 4 5 6 7 8 9 A B C D E F 下位4ビット 0 1 2 NUL SOH STX DLE DC1 DC2 SP ! " 0 1 2 @ A B P Q R ` a b p q r 3 ETX DC3 # 3 C S c s 4 EOT DC4 $ 4 D T d t 5 ENQ NAK % 5 E U e u 6 ACK SYN & 6 F V f v 7 BEL ETB ' 7 G W g w 8 BS CAN ( 8 H X h x 9 A B C D E F HT LF VT FF CR SO SI EM SUB ESC FS GS RS US ) * + , - . / 9 : ; < = > ? I J K L M N O Y Z [ \ ] ^ _ i j k l m n o y z { | } ~ DEL http://ja.wikipedia.org/wiki/ASCII 赤字は制御コード 20 [1] pp.303. ctype.h // 文字コードの調査(cが該当する文字なら真を返す) int islower(int c); //小文字 int isupper(int c); //大文字 int isdigit(int c); //10進数(数字) int isxdigit(int c);//16進数 int isalpha(int c); //英字 (isupper(c)||islower(c)) int isalnum(int c); //英数字(isalpha(c)||isdigit(c)) int iscntrl(int c); //制御文字(0x00~0x1f, 0x7f) int isspace(int c); //空白文字(' ','\f','\n','\r','\t','\v') int isprint(int c); //印字可能文字(0x20~0x7e) int isgraph(int c); //印字可能文字(スペースを除く) isprint(c)&&!isspace(c) int ispunct(int c); //印字可能文字(スペース、英数字を除く)isgraph(c)&&!isalnum(c) // 文字コードの変換 int tolower(int c); //cを小文字に変換 int toupper(int c); //cを大文字に変換 講義資料の ctype_test.c, ctype_test.xlsx も参照 JM: isalpha (3) toupper (3) 21 教科書 pp.44, 96-99., 第2週資料 pp.54-63. char型変数と文字コード • char, unsigned char 型 • 半角文字の文字コードを1つ つまり1バイト(=8ビット)を格納出来るサイズ • char : -128~127 • unsigned char : 0~255 0110 1000 16進数リテラルによる初期化 char c = 0x68; // =104='h' c 変数の実体はNバイト(8Nビット)のメモリ つまり内部的には2進数が入っている 文字コードに対応する文字を表示 printf("%c\n", 104); // "%c"に文字コードを与えると対応する文字が表示される 22 教科書 pp.44, 96-99., 第2週資料 pp.54-63. char型変数と文字コード • 以下の変数宣言と初期化は全く同じ結果 10進数リテラルによる初期化 char c = 104; // 'h' 16進数リテラルによる初期化 char c = 0x68; // 'h' 文字定数リテラルによる初期化 char c = 'h'; // 0x68 必要であれば 読んだ人が分かり易いよう コメントで情報を補うと良い 104 結果は同じでも読んだ時 分かり易いのはどれだろう? c 0x68 c 'h' c 0110 1000 c 文字コードを代入したい場合 文字定数リテラルで書くと 数値リテラルで書くよりも 意味が分かり易くなる どの方法で初期化しようと結局 char型(1バイト)の変数 c を 0b01101000 で初期化している 23 教科書 pp.44, 96-99., 第2週資料 pp.54-63. char型配列と文字列 • 以下の変数宣言と初期化は全く同じ結果 10進数リテラルによる初期化 char s[] = {104, 101, 108, 108, 111, 0}; 16進数リテラルによる初期化 char s[] = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00}; 文字定数リテラルによる初期化 char s[] = {'h', 'e', 'l', 'l', 'o', '\0'}; 文字列定数リテラルによる初期化 char s[] = "hello"; 'h' 'e' 'l' 'l' 'o' '\0' s[0] s[1] s[2] s[3] s[4] s[5] どれで書いても良いが 普通は面倒だから 文字列の初期化は 文字列定数リテラルを 用いる 文字列は配列に格納した 一連の文字コード 終端には 0 を格納する 24 教科書 pp.44, 96-99., 第2週資料 pp.54-63. char型配列と文字列 • 文字列の表示 文字列定数リテラルによる初期化 char s[] = "hello"; 'h' 'e' 'l' 'l' 'o' '\0' s[0] s[1] s[2] s[3] s[4] s[5] 文字列の表示 printf("%s\n", s); // "%s"に与えたアドレス以降'\0'が現れるまで // メモリに格納された文字コードに対応する文字が表示される 25 関数の引数とよく使われる名前 • • • • • • • • • • • • • • p, ptr, pointer c, ch, chr, character s, str, string s, src, source d, dst, destination t, txt, text l, len, length w, wid, width h, hei, height n, num, number s, size b, buf, buff, buffer i, idx, index s, stat, status : : : : : : : : : : : : : : ポインタ 文字 文字列 発信元 送信先 テキスト 長さ 幅 高さ (個)数 サイズ バッファ 添え字 状態 26 教科書 p.312., [1] pp.313-315. strlen 関数 • size_t strlen(const char *s); • 文字列 s の長さを返す • 引数: • s: 長さを調べる文字列 • 戻り値 • 文字列 s の長さを返す • 要 string.h JM: strlen (3) 27 教科書 p.308., [1] pp.313-315. strcpy 関数 • char *strcpy(char *dst, const char *src); • '\0'を含めてsrcをdstへコピーする • 引数: • dst: コピー先のアドレス • src: コピー元の文字列 • 戻り値 • dst を返す • dst が十分な大きさでないとバッファオーバーフロー を引き起こすので注意 • 要 string.h JM: strcpy (3) 28 教科書 p.308., [1] pp.313-315. strncpy 関数 • char *strncpy(char *dst, const char *src, size_t n); • srcから最大n文字dstへコピーする • 引数: • dst: コピー先のアドレス • src: コピー元の文字列 • n: コピーする最大文字数 • 戻り値 • dst を返す • src が n 文字より短い場合は、残りの dst の末尾に '\0' を詰めて、合計 n バイト書き込む • 要 string.h JM: strcpy (3) 29 教科書 p.309., [1] pp.313-315. strcat 関数 • char *strcat(char *dst, const char *src); • 文字列dstの末尾に文字列srcを連結する • 引数: • dst: 連結先の文字列 • src: 連結元の文字列 • 戻り値 • dst を返す • dst が十分な大きさでないとバッファオーバーフロー を引き起こすので注意 • 要 string.h JM: strcat (3) 30 教科書 p.309., [1] pp.313-315. strncat 関数 • char *strncat(char *dst, const char *src, size_t n); • 文字列dstの末尾に文字列srcを最大n文字連結する • 引数: • dst: 連結先の文字列 • src: 連結元の文字列 • n: 連結する最大文字数 • 戻り値 • dst を返す • dst は strlen(dst)+min(strlen(stc),n)+1 の 大きさがなければバッファオーバーフローが発生する • 要 string.h JM: strcat (3) 31 教科書 p.309., [1] pp.313-315. strcmp 関数 • char *strcmp(const char *s1, const char *s2); • 文字列s1とs2を比較する • 引数: • s1: 比較する文字列1 • s2: 比較する文字列2 • 戻り値 • • • • s1がs2に比べて小さければマイナスの値を返す s1とs2が等しければ0を返す s1がs2に比べて大きければプラスの値を返す 要 string.h JM: strcmp (3) 32 教科書 p.310., [1] pp.313-315. strncmp 関数 • char *strncmp(const char *s1, const char *s2, size_t n); • 文字列s1とs2の先頭n文字を比較する • 引数: • s1: 比較する文字列1 • s2: 比較する文字列2 • n: 比較する最大文字数 • 戻り値 • strcmpに同じ • 要 string.h JM: strcmp (3) 33 教科書 p.312., [1] pp.313-315. strchr 関数 • char *strchr(const char *s, char c); • 文字列sのなかで最初に現れるcを見つける • 引数: • s: 検索する文字列 • c: 検索する文字 • 戻り値 • 最初に見つかったcへのポインタを返す • 見つからなかった場合はNULLを返す • 要 string.h JM: strchr (3) 34 教科書 p.313., [1] pp.313-315. strrchr 関数 • char *strrchr(const char *s, char c); • 文字列sのなかで最後に現れるcを見つける • 引数: • s: 検索する文字列 • c: 検索する文字 • 戻り値 • 最後に見つかったcへのポインタを返す • 見つからなかった場合はNULLを返す • 要 string.h JM: strchr (3) 35 [1] pp.313-315. strspn 関数 • int strspn(const char *s, const char *t); • 文字列sの先頭から、tに含まれる文字だけからなる 文字列の長さを返す • 引数: • s: 検索する文字列 • t: 検索する文字の集合 • 戻り値 • tに含まれる文字からなる接頭子(prefix)の長さを 返す • 要 string.h JM: strspn (3) 36 [1] pp.313-315. strcspn 関数 • int strcspn(const char *s, const char *t); • 文字列sの先頭から、tに含まれない文字だけからな る文字列の長さを返す • 引数: • s: 検索する文字列 • t: 検索する文字の補集合 • 戻り値 • tに含まれない文字からなる接頭子(prefix)の長さ を返す • 要 string.h JM: strspn (3) 37 [1] pp.313-315. strpbrk 関数 • char *strpbrk(const char *s, const char *t); • 文字列sのなかで、tに含まれる文字が最初に出てく る位置を見つける • 引数: • s: 検索する文字列 • t: 検索する文字の集合 • 戻り値 • tに含まれる文字が最初に見つかった位置へのポイ ンタを返す • 見つからなかった場合はNULLを返す • 要 string.h JM: strpbrk (3) 38 教科書 p.314., [1] pp.313-315. strstr 関数 • char *strstr(const char *s, const char *t); • 文字列sのなかで、文字列tが最初に現れる位置を見つ ける • 引数: • s: 検索する文字列 • t: 検索する文字列 • 戻り値 • 文字列tが最初に見つかった位置へのポインタを返す • 見つからなかった場合はNULLを返す • 要 string.h JM: strstr (3) 39 [1] pp.313-315. strtok 関数 • char *strtok(char *s, const char *t); • 文字列sのなかから、 tに含まれる文字で区切られるトークン を見つける • 引数: • s: 検索する文字列 • t: トークンを区切る文字の集合 • 戻り値 • トークンへのポインタを返す • 2つ目以降のトークンは s を NULL にして呼ぶことで順次切 り出される • トークンがなくなったらはNULLを返す • s は区切り文字の位置が終端文字'\0'で破壊される • 要 string.h JM: strtok (3) 40 [1] pp.313-315. memset 関数 • void *memset(void *s, int c, size_t n); • sの先頭からnバイトをcで埋めsを返す • 引数: • s: データで埋める先頭アドレス • c: メモリを埋める1バイトのデータ • n: データcを埋めるバイト数 • 戻り値 • s を返す • 要 string.h JM: memset (3) 41 [1] pp.313-315. memcpy 関数 • void *memcpy(void *dst, const void *src, size_t n); • dstにsrcの内容をnバイトコピーする • dstとsrcは領域が重なっていてはならない。重なっ ている場合はmemmoveを用いる • 引数: • dst: データのコピー先 • src: データのコピー元 • n: コピーするバイト数 • 戻り値 • dst を返す • 要 string.h JM: memcpy (3) 42 [1] pp.313-315. memmove 関数 • void *memmove(void *dst, const void *src, size_t n); • dstとsrcは領域が重なっていても良い点を除けば、 memcpyと同じ • 引数: • dst: データのコピー先 • src: データのコピー元 • n: コピーするバイト数 • 戻り値 • dst を返す • 要 string.h JM: memmove (3) 43 [1] pp.313-315. memcmp 関数 • int memcmp(const void *s1, const void *s2, size_t n); • s1とs2の最初のnバイトを比較する • 引数: • s1: 比較するメモリ1 • s2: 比較するメモリ2 • n: 比較するバイト数 • 戻り値 • strcmpに同じ • 要 string.h JM: memcmp (3) 44 [1] pp.313-315. memchr 関数 • void *memchr(const void *s, int c, size_t n); • sの中でcが最初に現れる位置を見つける • 引数: • s: 検索するメモリ • c: 検索する値 • n: 検索する範囲のバイト数 • 戻り値 • cが最初に見つかった位置へのポインタを返す • 見つからなかった場合はNULLを返す要 string.h JM: memchr (3) 45 [1] pp.316-317. stdlib.h // 文字列を数値に変換 double atof(const char *s); //文字列をdouble型の数値に変換 int atoi(const char *s); //文字列をint型の数値に変換 long atol(const char *s); //文字列をlong型の数値に変換 double strtod(const char *s, char **endp); long strtol(const char *s, char **endp, int base); unsigned long strtoul(const char *s, char **endp, int base); // 文字列を double, long, unsigned long 型の数値に変換する // endp が NULL でない場合、 // *endp は変換に用いた最後の文字の次の文字へのポインタとなる // base は変換元の文字列の基数 // base が 0 の場合、文字列先頭の 0 や 0x を解釈し JM: atof // 8 進数や 16 進数として扱う atoi strtod strtol (3) (3) (3) (3) 46 演習 47 演習: べき乗関数(powi)の作成 • 整数𝑥, 𝑦についてべき乗𝑥 𝑦 を求める • ヒント • 再帰の場合 • ループの場合 𝑥 𝑦 = 𝑥 ⋅ 𝑥 𝑦−1 𝑥 𝑦−1 = 𝑥 ⋅ 𝑥 𝑦−2 ⋮ 𝑥1 = 𝑥 ⋅ 𝑥 0 𝑥0 = 1 𝑥𝑦 = 1 ⋅ 𝑥 ⋅ 𝑥 ⋅ 𝑥 ⋯ 𝑥 𝑦 48 演習: powi_with_loop.c • 整数𝑥, 𝑦についてべき乗(power)𝑥 𝑦 を求める関 数powi(x,y)をループを用いて実装せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに 作成せよ • powi_test.c と共にコンパイルして動作を確 認する事 • 引数 • int x,y • 戻り値 • 𝑥 𝑦 をint型で返せ mintty + bash + GNU C $ gcc x = ? y = ? x^y = powi_test.c powi_with_loop.c && ./a 2 8 256 49 演習: powi_with_recursion.c • 整数𝑥, 𝑦についてべき乗(power)𝑥 𝑦 を求める関 数powi(x,y)を再帰を用いて実装せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに 作成せよ • powi_test.c と共にコンパイルして動作を確 認する事 • 引数 • int x,y • 戻り値 • 𝑥 𝑦 をint型で返せ mintty + bash + GNU C $ gcc x = ? y = ? x^y = powi_test.c powi_with_recursion.c && ./a 2 8 256 50 シーザー暗号 • アルファベットをN文字シフトする暗号 • 例: IBM→1文字左へ→HAL 51 演習: caesar.c • • • • • 与えられた文字列をシーザー暗号で暗号化する関数caesar(s,n)を作成せよ。 文字コードが0x20~0x7eの文字ついてのみ処理し、それ以外の文字について は処理せずそのまま残すこと。 0x20~0x7eからはみ出す値は値域の反対側に繋がるよう循環するよう変換せ よ。例えばn=1なら0x61('a')は0x62('b')に、0x7eは0x20に変換される変換 される。n=-1の場合も同様で、0x20は0x7eに変換される。 caesar_test.c と共にコンパイルして動作を確認せよ 引数: • • • char *s : 暗号化する文字列(終端が'\0') int n : 暗号鍵(シフトする文字数) 戻り値 • • 要するに最初に与えられたsを そのまま返せば良いという事 暗号化した文字列へのポインタを返す。 引数 s の内容は暗号化した結果で上書きされる。 mintty + bash + GNU C 改行後、CTRL+Dで終了 cmd 場合は CTRL+Z で終了 $ gcc caesar_test.c caesar.c && ./a n = ? 1 s = ? hal ibm 52 演習: dectoint.c • 10進数で用いられる「0~9」までの文字をint型の数値0~9に変 換する関数numtoint(c)を実装せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに作成せよ • エラーの際、DEBUGマクロが定義されていたら、標準エラー出力に 警告メッセージを表示せよ • dectoint_test.c と共にコンパイルして動作を確認する事 • 引数 pp.10-11参照 • int c : 「0~9」までの文字コード(0x30~0x39) • 戻り値 • cで与えられた文字コードに対応する数値0~9をint型で返す • エラーの場合は-1を返す mintty + bash + GNU C $ gcc dectoint_test.c dectoint.c && ./a c = ? 9 9 53 演習: dectoint.c • ヒント 文字 0 1 2 3 4 5 6 7 8 9 文字コード(16進数) 30 31 32 33 34 35 36 37 38 39 • 文字定数リテラル'0'は48や0x30と同じであ る。この事の意味が理解できない場合、以下 の結果を確認してみよ。 文字定数リテラルと値 printf("%#d\n", '0'); printf("%#x\n", '0'); 54 演習: hextoint.c • 16進数で用いられる「0~9,A~F,a~f」までの文字をint型の数 値0~15に変換する関数hextoint(c)を実装せよ • 関数のプロトタイプ宣言はmyfunc_week10.hに作成せよ • エラーの際、DEBUGマクロが定義されていたら、標準エラー出力に 警告メッセージを表示せよ • hextoint_test.cと共にコンパイルして動作を確認する事 • 引数 • int c : 「0~9,A~F,a~f」までの文字コード(0x30~ 0x39,0x41~0x46,0x61~0x66) • 戻り値 • cで与えられた文字コードに対応する数値0~15をint型で返す • エラーの場合は-1を返す mintty + bash + GNU C $ gcc hextoint_test.c hextoint.c && ./a c = ? f 15 55 演習: hextoint.c • ヒント 文字 0 1 2 3 4 5 6 7 8 9 文字コード(16進数) 30 31 32 33 34 35 36 37 38 39 文字 A B C D E F 文字コード(16進数) 41 42 43 44 45 46 文字 a b c d e f 文字コード(16進数) 61 62 63 64 65 66 56 演習: strtoi_dec.c • 文字列として格納された10進数をint型の値に変換する関 数strtoint_dec(s,endp)を書け • strtoi_dec_test.cと共にコンパイルして動作を確認す る事 • 引数 • char *s : 変換する文字列 • char ** endp : char型へのポインタのポインタ。NULL以外が与 えられた場合は *endp に変換出来た最後の文字の次の文字 へのポインタを返す。 • 戻り値 • 文字列s数値に変換した結果をint型で返す。 mintty + bash + GNU C $ gcc strtoi_dec_test strtoi_dec.c && ./a s = ? 255 255 57 演習: strtoi_dec.c • ヒント: "1234"を𝑁進数として変換する場合 • 文字列sの先頭から1文字ずつ取り出し、int型の数値 に変換すると 1,2,3,4 となる • 先頭から1文字ずつ取り出す毎に、既に取り出した値 を𝑁倍にしていくと、以下のようになる • • • • step1: 1 step2: 1𝑁 1 , 2 step3: 1𝑁 2 , 2𝑁 1 , 3 step4: 1𝑁 3 , 2𝑁 2 , 3𝑁 1 ,4 • つまり、各桁が𝑁 𝑥 の位として計算出来ている • あとはこれを全部足せば良い。 58 演習: strtoi_dec.c • ヒント: • 先頭から取り出した値は、変換済みの値の格納用の 変数に足していけば全部覚えておく必要はない。 • 前の値を𝑁 倍すれば1桁繰り上がる。 • • • • • result result result result result = = = = = 0; result result result result * * * * N N N N + + + + 1; 2; 3; 4; // // // // // ↓ N=10 result result result result • あとはこれを return すれば良い。 だと = 1; = 12; = 123; = 1234; 59 演習: strtoi_dec.c • ヒント: • 途中で変換不能な(0~9以外の)文字が出てき たらそこで変換を終了する。 • *endp にはその時点の s を入れておけば良い (ただしendpがNULLなら何もしない)。 60 演習: strtoi_hex.c • 文字列として格納された16進数をint型の値に変換する関 数strtoint_hex(s,endp)を書け • strtoi_hex_test.cと共にコンパイルして動作を確認す る事 • 引数 • char *s : 変換する文字列 • char ** endp : char型へのポインタのポインタ。NULL以外が与 えられた場合は *endp に変換出来た最後の文字の次の文字 へのポインタを返す。 • 戻り値 • 文字列s数値に変換した結果をint型で返す。 mintty + bash + GNU C $ gcc strtoi_hex_test strtoi_hex.c && ./a s = ? ff 255 61 演習: strtoi_oct.c • 文字列として格納された8進数をint型の値に変換する関 数strtoint_oct(s,endp)を書け • strtoi_oct_test.cと共にコンパイルして動作を確認す る事 • 引数 • char *s : 変換する文字列 • char ** endp : char型へのポインタのポインタ。NULL以外が与 えられた場合は *endp に変換出来た最後の文字の次の文字 へのポインタを返す。 • 戻り値 • 文字列s数値に変換した結果をint型で返す。 mintty + bash + GNU C $ gcc strtoi_oct_test strtoi_oct.c && ./a s = ? 377 255 62 演習: strtoi.c • 文字列として格納された数値をint型の値に変換する 関数strtoint(s,endp,base)を書け。 • 引数 • char *s : 変換する文字列 • int base : 基数。0が与えられた場合、文字列の先頭に0が あれば8、0xがあれば16、それ以外なら10として扱う。 • char ** endp : char型へのポインタのポインタ。NULL以外 が与えられた場合は *endp に変換出来た最後の文字の 次の文字へのポインタを返す。 • 戻り値 • 文字列sを基数baseとして数値に変換した結果をint型で 返す。 第13週へ移動+改訂 63 参考文献 • [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準 拠、共立出版(1989)
© Copyright 2025 ExpyDoc