C言語入門 - メディア基盤センター

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)