-
Notifications
You must be signed in to change notification settings - Fork 0
/
chap02.tex
440 lines (376 loc) · 42.6 KB
/
chap02.tex
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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
前講では、パソコンが何かを出すプログラムを作成した。一方、通常のソフトウェアは何らかの指令――\textbf{入力}\index{にゅうりょく@入力}(input)――を受けて、それをプログラム中で保持して活用する。ここでは、標準出力に対応した入力である、\textbf{標準入力}\index{ひょうじゅんにゅうりょく@標準入力}(standard input)から入力して、それを保持・活用する為の手法である変数について学ぶ。
\section{変数とデータ型}
まずは、「変数とは何か」から掴んでいくことにしよう。
\subsection{変数とは}
\textbf{変数}\index{へんすう@変数}(variable)とは、プログラムのソースコードにおいて、扱われるデータを一定期間記憶し必要なときに利用できるようにするために、データに固有の名前を与えたものである。 一人一人の人間が異なる名前によって区別されるように、一つ一つの変数も名前によって区別される。これにより、複数のデータを容易に識別することができる。また一般に、変数が表しているデータをその変数の値という。最も簡単に例えれば、データを入れる箱が「変数」であり、その箱の名称が変数名(識別子)、その箱の中身が変数の値ということになる。
\minisec{変数使用の3ステップ}
変数を扱う際には、\textbf{宣言}\index{せんげん@宣言}(declare)・\textbf{初期化}\index{しょきか@初期化}(initialize)・\textbf{参照}\index{さんしょう@参照}(refer)の3ステップが行われる。これは、次のような順番である。
\begin{enumerate}
\item まず、どのような名前で、何を格納するための変数なのかを定める(宣言)。
\item 次に、その変数に初期値が代入される(初期化)。
\item その後、必要に応じて代入されたり計算に用いられたりする(参照)。
\end{enumerate}
これらについての例は次節以後に譲る。このような3ステップを経て利用されることを知っていれば良い。
\minisec{データ型}
先に何を格納するための変数なのか定めると書いたが、一般の容器に用途があるように、変数にも用途がある。例えば、整数用の変数、小数も入れられる変数、文字を入れる変数などである。このような、変数が何を入れるためのものかというのを、その変数の\textbf{データ型}\index{データがた@データ型}(data type)あるいは単に型と呼ぶ。より正確に言えば、メモリ上のビット列をどのように解釈して値を保持するか定めるのがデータ型である。そのため、変数を使えるように宣言するとは、変数の型と名前を定めるということである。
1999年に定まったC言語の規格における、基本的なデータ型(基本型)を表\ref{clang_datatypelist}に示す。なお、C99以前の規格から定まっている型には何も記さないが、それ以降から定まった型には(C99)と記した。
\begin{table}[H]
\caption{C言語におけるデータ型(基本型)}
\centering
\begin{tabular}{|c|c|}\hline
型名&扱えるデータ\\ \hline
&\\[-16pt]\hline
short&整数\\ \hline
int&整数(範囲がshort以上)\\ \hline
long&整数(範囲がint以上)\\ \hline
long long&整数(範囲がlong以上)(C99)\\ \hline
\_Bool&ブール代数(整数)(C99)\\ \hline
float&浮動小数点数\\ \hline
double&浮動小数点数(範囲がfloat以上)\\ \hline
long double&浮動小数点数(範囲がdouble以上)\\ \hline
\_Complex&複素数型(C99)\\ \hline
\_Imaginary&虚数型(C99)\\ \hline
char&文字(整数)\\ \hline
\end{tabular}
\label{clang_datatypelist}
\end{table}
各変数の型についての説明はここには記さず、別で丁寧に説明する。ここでは、各々に何が入るか、範囲がどれぐらいか(何より何が大きいか)ということを知っておけば良い。
\subsection{識別子の命名}
変数の名前には規則があり、その規則を守らない名前は許されない。また、規則以外にもマナーもある。我々が変数はじめ様々なものを命名するときには、規則とマナーの両方を守らねばならない。これらの違いについて考えよう。
規則はコンパイラがソースファイルを解釈する際に必要とするものである。したがって、規則は変数を明確に識別できるものである必要がある。識別の為に使う言葉を\textbf{識別子}\index{しきべつし@識別子}(identifier)と呼び、Cでは概ね変数等の名前と同義と考えて良い。
マナーは、仮に守らなかったとしてもプログラムは動作するであろうが、可読性その他の観点において問題が生じるというものである。規則は実生活での法律に対応し、マナーはそのまま日常生活のマナーに対応する。スーパーマーケットのレジで並んでいるとき、それに割り込むのは、違法ではないかもしれないが、マナーに反する。同じことで、識別子を定める際にも、マナーというものがあるのである。
一般的な、C言語における識別子命名のマナーと規則についてまとめておく。
\begin{itembox}[l]{識別子の命名規則・マナー}
\minisec{命名規則}
\begin{itemize}
\item 識別子の第1文字目は半角英字でなければならない。
\item 識別子に含まれる文字は、半角英数字及びアンダースコアのみである。
\item 識別子は前もってCの命令として用意されている単語である\textbf{予約語}\index{よやくご@予約語}(reserved words)と同じであってはならない\footnote{予約語については付録で述べる。}。
\item 識別子は他の識別子と重複してはならない。\footnote{厳密には、後で学習する名前空間が違っていれば同一識別子でも規約上問題ないのだが、マナーとして書かないほうが良い。名前空間が同一の場合はそもそも(規約上)付けられない。}
\end{itemize}
\minisec{命名のマナー}
\begin{itemize}
\item 識別子はその用途が明確になるように命名すべきである。
\item 識別子はあまり長くするべきではない。
\item 慣例的に定まっている識別子に反する名称をつけるべきではない\footnote{例えば、後日学習する反復処理においてカウンタとして用いる変数には一般にはi,j,kを用いる。特別な理由なくこれら以外の識別子を使うとソースが読みにくくなる。}。
\item 大文字と小文字が違うだけのような間違いを誘発する名前は避ける。
\end{itemize}
\end{itembox}
\subsection{整数型の仕組み}
それでは、実際に型の内部を見ていくことにしよう。ここでは、整数型と浮動小数点数型、文字型について解説する。\\ \\
整数型の特徴は、次のとおりである。
\begin{itembox}[l]{整数型の特徴}
\begin{itemize}
\item 符号付き(signed)整数と符号なし(unsigned)整数があり、宣言時に指定できる。ただし、signedは通常省略される。
\item 符号付き整数は、定められた範囲における整数を扱うことができる。
\item 符号なし整数は、定められた範囲における非負整数を扱うことができる。
\end{itemize}
\end{itembox}
ここに書いた、「定められた範囲」とは何だろうか。
整数型に限らず、変数はいずれも、メモリ上\footnote{ここで学ぶ変数については、メモリ上のスタック領域と呼ばれる部分である。}にある一定サイズの領域を確保する。よくある環境では、short型は2Byte,int型とlong型は4Byte,long long型は8Byteである\footnote{整数型変数の型名は元々short int,int,long int,long long intであった。だが、長いのでintを略記し、ここに書いたようにshort,int,long,long longと書くことが一般化している。実際のプログラムでは、short intなどと省略せずに書いても問題ない。同じことがunsigned intにも言えて、コードを書く際にはunsignedとだけ書いても良い。}。ここで、例えばshort型のビットパターン数は65536通り\footnote{2Byte=2$\times$8bitなので、$2^{16}=65536$と求められる。}である。これを全て0以上の数に当てはめると、0から65535までの値を扱うことができ、これがunsigned shortである。一方、先頭ビットが0であるようなビットパターンを0及び正に、先頭ビットが1であるようなビットパターンを負に当てはめると-32768から32767までの値を扱うことができる。これが(signed) shortである。
今見たように、変数には扱える値に範囲がある。この範囲を超えてしまうことを\textbf{オーバーフロー}\index{オーバーフロー}(over flow)と呼ぶ。オーバーフローするとプログラムがおかしなことになるので、変数の範囲については概ね覚えておくと便利である。例えば、32bit整数は約21億まで、64bit整数は20桁の数の途中まで扱える。
\minisec{2の補数表現}
先に、ビットパターンを割り当てると書いたが、その仕組みについてもう少し掘り下げることとしよう。なお、この内容は後で解説するビット演算に大きく関わるので、よく理解されたい。
\\ \\
まず、unsigned整数型のビットパターンであるが、これは単純である。すなわち、表したい10進数をそのまま2進数に変換して、それをビットパターンに割り当てれば良いのである(勿論、オーバーフローはおきていないものとする)。
\\ \\
難しいのは符号付き整数型の場合である。このビットパターンには\textbf{2の補数表現}\index{ほすうひょうげん@補数表現} と呼ばれる表現が用いられる。この表現は、次のようなものである。\\
まず、0を基準とする。10進法における0を、2進法における0と対応させるのは自然な考えであろう。さて、これから1を引いた数、すなわち-1をどう表すべきであろうか??\\
4ビットで考えることとしよう。-1を1001とすれば、先頭ビットが符号を示し、残りが絶対値を示すという風に解釈できる。しかし、この方法では、先頭ビットに応じて引き算や足し算を使い分けなければならない。そのため、内部的な実装が面倒になってしまう。\\
そこで、使い分けなくていいようにビットを定めることにしたのが2の補数表現である。1=0001から1を引いて0にするには、0001から1を引いて0000にすることができる。では、それより1小さいものはどうすればいいか。これは、1111とすれば良いのである。ビットがあふれる部分への繰り上がりを無視して考えれば、1111+0001=0000, 0000+0001=0001となり、確かに-1+1=0となる。さらに、この方法を用いた場合でも、先頭ビット0は+または符号なしを、1は-を示す。このように、-aのビット表現を、0からaを引いたものとして表現するのが2の補数表現である。\\ \\
参考として、表\ref{hosu}に、2の補数表現を用いた4ビットの場合の符号なし整数・符号あり整数一覧を示す。
\begin{table}[htb]
\centering
\caption{4bit符号なし整数・符号あり整数の一覧}\label{hosu}
\begin{tabular}{|c|c|c||c|c|c|}\hline
ビット列&符号なし整数&符号あり整数&ビット列&符号なし整数&符号あり整数\\ \hline
&&&&&\\[-16pt]\hline
0000&0&0&1000&8&-8\\ \hline
0001&1&1&1001&9&-7\\ \hline
0010&2&2&1010&10&-6\\ \hline
0011&3&3&1011&11&-5\\ \hline
0100&4&4&1100&12&-4\\ \hline
0101&5&5&1101&13&-3\\ \hline
0110&6&6&1110&14&-2\\ \hline
0111&7&7&1111&15&-1\\ \hline
\end{tabular}
\end{table}
表\ref{hosu}からもわかるように、$n$ビットの整数が2の補数表現により表されているならば、その数値の範囲は$-2^{n-1}\sim 2^{n-1}-1$である。
\subsection{浮動小数点数型の仕組み}
float,double,long doubleは浮動小数点数型といい、実数を格納するための変数である。この型は整数型と違い、符号が必ず存在し、誤差が生じうるという特徴を持つ。ここでは、これらが実数を格納する仕組みについて説明する。
\minisec{固定小数点数}
ビットパターンを小数に当てはめる方法として、もっとも考え易いだろうものが\textbf{固定小数点数}\index{こていしょうすうてんすう@固定小数点数}(fixed point number)\footnote{英単語からもわかるとおり、これは固定-小数点-数という事になる。したがって、「固定小数」という言い方は間違いである。ただし、慣用的に固定小数と使われている場合も少なくない。}である。この方式は一般に、定められた範囲において誤差が出ず、計算も高速である代わりに、表現できる数の範囲が小さくなる。そのため、細かな値は不要だが誤差が生ずると困るような経済計算などで用いられている。Cには固定小数点数型はないが、後述の浮動小数点数型の理解のために簡単な解説を行う。
\\ \\
固定小数点による数値表現は、ある定まったビットまでを整数部として、そこから下の部を小数部としてみなす方法である。例えば、16ビットある時に、上位8ビットがその数の整数部を示し、下位8ビットが小数部を示すようにすれば良い。この時、$2^0=1$を示すビットのすぐ下のビットは$2^{-1}$を、その下は$2^{-2}$を$\cdots$というように、桁が連続的に定まっていくのが普通である。
\minisec{浮動小数点数}
\textbf{浮動小数点数\index{ふどうしょうすうてんすう@浮動小数点数}(floating point number)}は、小数点の場所を上手く変えながら(浮動)表す方法で、C言語で実数を扱う型はこの方式である。この方式の場合、表現できる数の範囲は広いが、誤差が出る上に、計算も固定小数点型に比べて遅い。そのため、経済計算等には向かず、科学計算などで使われることが多い。以下、これについて説明する。
\\ \\
浮動小数点方式では、変数のビットを符号部(1bit)、指数部(符号付き整数)、仮数部(符号なし整数部)に分割して、これを用いて数値を表現する。すなわち
\[\text{(符号)}\text{(仮数)}\times\text{(基数)}^\text{(指数)}\]
という表現である。一般に、基数には2が用いられ、仮数部は1以上2未満の数の小数点以下を示す\footnote{IEEE754方式と呼ばれる方式である。}。この説明だけでは分かりにくいと思うので、実際の例を見ることにしよう。
-4.8という数字を浮動小数点数で表現することを考えよう。$-4.8=-1.2\times 2^2$である。したがって、符号部には-が、仮数部には0.2が、指数部には2が格納されることになる。
このように、指数部の値によって、絶対値が非常に小さい値や非常に大きい値を計算できるようにしたのが浮動小数点数型である。
\minisec{例外演算}
先のような形式で定義された数では表現できないような計算もある。このような計算を\textbf{例外演算}\index{れいがいえんざん@例外演算}(arithmetic exception)と呼ぶ。例外演算は通常不要なものあるいはバグを示すものであるため、例外が起こっている場合にはその部分を直さなければならない。
\\ \\
整数の項で記したオーバーフローは例外演算の一つである。これは浮動小数点数でも起こりうる。すなわち、絶対値が大きすぎて表現できないような数になることである。
一方で、浮動小数点数の場合、絶対値が小さすぎて表現できない数になることもありうる。このように、非常に小さな絶対値となって表せなくなる現象を\textbf{アンダーフロー}\index{アンダーフロー}(under flow)と呼ぶ。浮動小数点数におけるオーバーフロー/アンダーフローは、浮動小数点数の指数部の上へのオーバーフロー/下へのオーバーフローと対応している。
\\ \\
この他、0による除算や負の値の平方根も例外である。前者を行った場合、infという特殊な値になり、後者の場合、NaNという特殊な値になる\footnote{infはinfinity(無限)の略であり、NaNはNot a Number(非数)の略である。}。
\\ \\
また、浮動小数点型には通常の0に加え、符号部がマイナスになった-0がある。これも特殊な値であり、アンダーフロー等を示す場合もあるが、例外演算でないこともある。
\\ \\
これらについて詳しく覚える必要はないが、初心者のうちは、これらの見慣れない表現が出てきたら「何かおかしい」と思えば良い。
\subsection{文字型の仕組み}
文字型charは1バイトの整数型でもあり、内部的には整数を保存している。これらの整数を、\textbf{文字コード}\index{もじこーど@文字コード}と呼ばれる規則に従って表示することにより文字を表現している\footnote{文字コードには様々な種類があり、それによって同じ数字でも違う文字に割り当てられることがある。}。例えば、非常によく使われる文字コードであるASCII\footnote{American Standard Code for Information Interchangeの略である。}の場合、数字の9は57であり、文字Aは65である。出力する際に、65をASCIIにしたがって文字として出力すればAになり、数値とすれば65になるわけである。
1バイトで表される文字は少なく、256通りしかない。このように1バイトで表されるのが、一般に言う\textbf{半角文字}\index{はんかくもじ@半角文字}である。半角文字を扱うパソコンは大抵ASCIIに従うため、パソコンでしか動作しないようなプログラム(競技プログラミングなど)はASCIIであることを仮定して作って良い。ASCIIには「0〜9」「A〜Z」「a〜z」の連続性が保証されているという特徴がある。このうち、0から9の連続性についてはCの規格で保証されているが、それ以外はASCII固有の特徴であるので、ASCIIであることが保証されない場合には使わないほうが良い。
文字は、プログラム中ではシングルクォーテーション(\verb|'|)で囲み'1'や'A'のように記す。これはそれぞれ、文字1,Aの文字コードを示している。文字コードは内部的に整数として表されるので、例えば'1'+4は'5'である。
\section{変数の入出力と演算}
長い説明で疲れただろうが、いよいよ、実際のプログラムを見ていく。
\subsection{変数の出力}
\begin{boxnote}
\minisec{変数の使用}
自分で定めた変数を出力するプログラムを作成する。
\begin{multicols}{2}
\minisec{解法}
変数の使い方は
\begin{enumerate}
\item 宣言する。
\item 初期化する。
\item 参照する。
\end{enumerate}
である。これらを順次行えば、リスト\ref{program2_1}のようなプログラムができる。\\
宣言と初期化はリスト\ref{program2_1}の4-6行目に、参照は8-10行目に当たる。
\begin{lstlisting}[caption=変数の出力,label=program2_1]
#include<stdio.h>
int main(void){
int n = 5;
const double pi = 3.14;
char c1 = 'p' , c2 = 'i';
printf( "n:%d\n" , n );
printf( "%c%c=" , c1 , c2 );
printf( "%f\n" , pi );
return 0;
}
\end{lstlisting}
\end{multicols}
\end{boxnote}
新出文法がまだまだ多いので、ソースコードを追って順番に説明していくくこととする。
\minisec{変数の利用}
まず、リスト\ref{program2_1}の4-6行目、宣言と初期化についてみていくことにしよう。
\begin{itembox}[l]{変数の宣言と初期化}
変数の宣言と初期化は
\begin{center}
\verb|(型名) (識別子)=(初期値);|
\end{center}
\begin{flushright}
によって行われる。
\end{flushright}
\end{itembox}
\\ \\
実際は、
\begin{center}
\verb|(型名) (識別子);|
\end{center}
が宣言であり、これにイコールと初期値を付与することで初期化を行っている。たとえば、この4,6行目の意味を記せば
\begin{description}
\item[$l$.4] int型(整数型)の変数(箱)であるnを使うことを宣言し、nを5で初期化する。
\item[$l$.6] char型(文字型)の変数(箱)であるc1,c2を使うことを宣言し、c1を文字pで、c2を文字iで初期化する。
\end{description}
となる。
5行目についている\textbf{const修飾子}\index{constしゅうしょくし@const修飾子}はRead onlyを表す修飾子で、その変数が読み込み専用で用いられることを示す。これは、後述する文字列リテラルなどの際によく用いられるが、通常の変数に用いる場合は定数の宣言であると思って差し支えない。例えばここでは円周率を定義しているが、円周率を他で書き換えてしまうと計算結果がおかしなことになりかねないため、この部分に集約し、容易に書き換えられないようにしている。
const修飾子を用いた宣言の際には、宣言の後に\verb|=(初期値)|を記し、必ず初期化しなければならない。一方で、通常の変数については、宣言と同時に初期化をしなくても構わない。例えば、先のリスト\ref{program2_1}のソースの4-6行目は、次のように書き換えても支障ない。
\begin{lstlisting}[firstnumber=4]
int n;
const double pi = 3.14;
char c1 , c2;
n=5;
c1='p';
c2='i';
\end{lstlisting}
この時の初期化は、厳密に言えば代入であるが、このような宣言後最初の代入は初期化であると言える。変数を用いる場合、その変数に最初何が入っているかは特別な場合を除いてわからないので、必ず初期化(代入や入力受け取り等の、初期化に代わる処理を含む)せねばならない。
\minisec{書式指定出力}
続いて、8-10行目である。ここで出てくる、printf関数は書式を指定した文字列(\textbf{書式文字列}\index{しょしきもじれつ@書式文字列})を標準出力(コンソール)に出力する関数である。第1引数に書式文字列を指定し、以後の可変引数に式の引数リスト(変数名、定数、\verb|2*a|などの式)を与えることで、その式の値を出力する。例えば、9行目では、\verb|%c|が文字型出力書式指定子であるので、それに対応した文字が出力される。1つ目の\verb|%c|に対しては1つ目の可変引数である\verb|c1|が、2つ目の\verb|%c|に対しては2つ目の可変引数である\verb|c2|が対応するので、\verb|pi=|という出力になる(=はそのまま出力される)。
\\ \\
さて、書式文字列とは一体何なのかについて説明していこう。書式文字列は、特定の書式を用いて変数などを出力できるようにした文字列であり、表\ref{shoshiki_sitei}に示す\textbf{書式指定子}\index{しょしきしていし@書式指定子}を含む。これらに対して、先に説明したように可変引数に適当な変数を取れば、その値が出力されるのがprintf関数である。なお、書式指定子はprintf関数以外にも、後述するscanf関数などでも用いられる。
\begin{table}[htb]
\centering
\caption{書式指定子一覧}\label{shoshiki_sitei}
\begin{tabular}{|c|c|} \hline
書式指定子 & データ型 \\ \hline
&\\[-16pt]\hline
\verb|%d| & int型\\ \hline
\verb|%u| & unsigned int型 \\ \hline
\verb|%o| & int型, unsigned int型(8進数)\\ \hline
\verb|%x|, \verb|%X| & int型, unsigned int型(16進数/X:大文字、x:小文字出力)\\ \hline
\verb|%h| & (後ろにd/u/o/xを伴い)short型\\ \hline
\verb|%ll| & (後ろにd/u/o/xを伴い)long long型\\ \hline
\verb|%f| & float型, double型 \\ \hline
\verb|%lf| & double型 [入力時のみ] \\ \hline
\verb|%e| & double型(指数表示) [出力時のみ]\\ \hline
\verb|%g| & double型(\verb|%f|と\verb|%e|を自動選択)\\ \hline
\verb|%L| & (後ろにf/e/gを伴い)long double型\\ \hline
\verb|%c| & char型(文字)\\ \hline
\verb|%s| & char *型(文字列) \\ \hline
\verb|%p| & ポインタ全般 \\ \hline
\end{tabular}
\end{table}
それでは、書式指定子について簡単に解説を行っておく。概ね必要なことは表に書いておいたが、補足すべき点や、オプションについて述べる。
後ろに何かを伴う書式指定子は、\verb|%llu|や\verb|%Le|のように使い、その当該の型を後ろにつけた指定の書式で出力する。この例でいうと、\verb|%llu|はunsigned long long型の出力であり、\verb|%Le|はlong double型の指数出力である。但し、元々\verb|%lf|は後に記す\verb|scanf|系関数の際のみに用いるもので、\verb|printf|関数では使わないことになっていた\footnote{元々は、出力に書式指定子\%lfを用いるのは誤りとされていた。しかし、入力と同じであったほうがわかりやすいこと、あまりに間違える人が多かったことなどから、各コンパイラが独自に\%lfを使えるように拡張していった。これを受けて1999年の改訂により、出力時に\%lfを使えるという仕様が実際に規格に追加された。そのため、現在では\%lfを出力の書式指定子として利用しても問題なくなった。}。
整数の桁数を調整して出力したい場合がある。このようなときには、\verb|%3d|のように、\verb|%|の後に桁数を入れれば良い。さらに、3桁でゼロうめをしたい場合\verb|%03d|のように、桁指定の前に0をつければ良い。同様に、小数についても、\verb|%3.4f|とすれば、整数桁3桁、小数桁4桁での出力になる。整数桁の桁数字を省けば、小数桁のみの指定ができる。
書式指定子には\verb|%|を用いるが、これだと記号の\verb|%|を出力したい時と書式指定子の区別がつかない。そのため、記号の\verb|%|を出力したい時には\verb|%%|と書くことになっている。\footnote{同じことが'や",$\backslash$のエスケープシークエンスなどにも言える。}
\minisec{リテラルの書き方}
変数の初期化について話したので、関連事項として数値リテラルについても解説する。\textbf{リテラル}\index{りてらる@リテラル}(literal)とはプログラムのソースコード中で用いられる定数のことで、その種別に応じて「文字列リテラル」「数値リテラル」などがある。
\\ \\
文字列リテラルはダブルクォーテーションで囲んだ文字列のことであり、これについて、詳細は後の講で説明する。
\\ \\
数値リテラルには、指数表記、8進表記、16進表記など、いくつかの書き方がある。
まず指数表記であるが、\verb|1e3|(\verb|1e+3|とも)や\verb|0.2E-2|のように数値$k$の後にE/eを置き、その後に指数$m$を置くことで$k\times 10^m$を表すことができる。先の例で言えば、前者は$1\times 10^3=1000$に、後者は$0.2\times 10^{-2}=0.002$になる。
8進表記は034のように数字の前に0を、16進表記は0x3aのように0x/0Xをおくことで実現することができる。8進の例は28に、16進の例は58になる。これらの表記は通常整数に用いられる。だが、C99において、浮動小数点数についても16進表記が可能になった。16進指数表現で$a.b\times 2^c$と表される数は0xa.bpcのように、0xのあとa.bを記し、その後にpをつけてcを書くことで実現することができる。
\subsection{変数の入力と簡単な計算}
前節の解説で変数の宣言と出力は理解できたことだろう。今度は、変数の入力と変数を用いた計算を行おう。
\begin{boxnote}
\minisec{変数と四則演算}
2つの整数が入力された時、和・差・積・商・剰余の演算を行うプログラムを作る。
\minisec{解法}
まず変数を入力した後、各計算を行ってその値を出力すれば良い。ここでは、計算結果を変数に保持せずに、直接出力させた。
入力の後計算して出力するプログラムを簡単に書くと、リスト\ref{program2_2}のようなソースになる。
\end{boxnote}
\begin{boxnote}
このソースをコンパイルした後、実行すると入力待ち状態になる。そこで、$a,b$をスペース区切りで\verb|5 4|などと入力すると、値が出力される。printf1行に対して出力の1行が対応するので、各々の対応付けを確認しておこう。
\begin{lstlisting}[caption=変数の四則演算,label=program2_2]
#include<stdio.h>
int main(void){
int a , b;
scanf( "%d %d" , &a , &b );
printf( "%d+%d=%d\n" , a , b , a + b );
printf( "%d-%d=%d\n" , a , b , a - b );
printf( "%d*%d=%d\n" , a , b , a * b );
printf( "%d/%d=%d\n" , a , b , a / b );
printf( "%d+%d=%f\n" , a , b , (float) a / b );
printf( "%dmod%d=%d\n" , a , b , a % b );
return 0;
}
\end{lstlisting}
\end{boxnote}
必要な解説は入力と演算であろう。以下、それらについて説明する。
\minisec{scanfによる入力}
6行目のscanf関数は書式指定文字列に応じた入力を行う関数である。読み方はprintfと同様に、各書式指定子に可変引数が対応している。各変数の前に\verb|&|(アンパサンド)が付いているが、これは現状、約束事と思って受け取ってもらえれば良い\footnote{実際にはアドレスを取得する演算子であり、scanf関数は書式指定子に対応した型の値を標準入力ストリームより入力してもらって可変引数のアドレスから参照される変数に代入する関数である。詳細は後で丁寧に記す。}。この例の場合、空白文字区切りで$a$と$b$を入力してもらうということになる\footnote{実際には、空白・タブ・改行は自動的に区切り文字として検出されるので、空白を入れなくても大丈夫である。}。他に、例えばコンマ区切りにしたい場合
\begin{code}
scanf( "%d,%d" , &a , &b );
\end{code}
のように書式指定文字列を書けば良い。
\\ \\
文字を入力する場合、例えば
\begin{code}
scanf( "%d" , &a );
scanf( "%c" , &c );
\end{code}
のようにすると、cに区切り文字の改行が入力されてしまう。これは、改行の段階で区切りが判定され、入力(入力ストリーム)に改行が残ってしまうのが原因である。このような場合に役立つのが読み飛ばしを示す\verb|*|である。書式指定子の\verb|%|の後に\verb|*|を入れることにより、読み飛ばしを行うことができる。したがって、先に書いたコード断片について、整数を読んだ後1文字読み込みたい場合
\begin{code}
scanf( "%d%*c" , &a );
scanf( "%c" , &c );
\end{code}
のように書きなおせば、意図通りに動作する。
\\ \\
scanf関数についても、各種書式指定子へのオプションを利用できる。とりわけよく利用されるのは文字列の読み込みの時で、文字列の読み込みを30文字にしたい場合は、\verb|"%30s"|という書式指定文字列を用いればよい\footnote{書籍あるいはサイトによっては、「scanf関数ではバッファオーバーランを防げない」として、文字列の読み込みをscanfで行うべきでないと書いていることがある。これについては後に記すが、ここで書いた書式指定子の技法を用いることで防ぐことができるため、見落としのある意見である。}。
\minisec{簡単な計算と演算子}
リスト\ref{program2_2}では、いくつかの演算子を用いた。これらを含め以下の表\ref{operands}に、C言語における基本的な演算子を示す。
\begin{table}[H]
\centering
\caption{算術・代入演算子}\label{operands}
\begin{tabular}{|c|c|c|}\hline
記法&意味&種類\\ \hline
&& \\[-15.5pt] \hline
\verb|+|&左側の値と右側の値を足す&2項演算子\\ \hline
\verb|-|&左側の値から右側の値を引く&2項演算子\\ \hline
\verb|*|&左側の値と右側の値をかける&2項演算子\\ \hline
\verb|/|&左側の値を右側の値で割る&2項演算子\\ \hline
\verb|%|&左側の値を右側の値で割った剰余をとる&2項演算子\\ \hline
\verb|=|&左辺値に右辺値を代入する&代入演算子\\ \hline
\verb|+=|&左辺値に右辺値を加えて新たな左辺値とする&複合代入演算子\\ \hline
\verb|-=|&左辺値から右辺値を引いて新たな左辺値とする&複合代入演算子\\ \hline
\verb|*=|&左辺値に右辺値を乗じて新たな左辺値とする&複合代入演算子\\ \hline
\verb|/=|&左辺値を右辺値で割って新たな左辺値とする&複合代入演算子\\ \hline
\verb|%=|&左辺値の右辺値による剰余を新たな左辺値とする&複合代入演算子\\ \hline
\verb|++|&これのついた変数に1を加える(\textbf{インクリメント}\index{インクリメント})&単項演算子\\ \hline
\verb|--|&これのついた変数に -1 を加える(\textbf{デクリメント}\index{デクリメント})&単項演算子\\ \hline
\verb|+|&プラス符号&単項演算子\\ \hline
\verb|-|&マイナス符号(符号を反転する)&単項演算子\\ \hline
\textbf{sizeof}\index{sizeof} &変数やデータ型のサイズ(バイト)を取得する&単項演算子\\ \hline
\end{tabular}
\end{table}
以下、補足を記す。
演算子には評価順序というものがあり、通常、数学と同じ順番で評価される。例えば3+2*4は2*4が先に計算され11になる。式中で、数学における括弧は全て()によって表現される。すなわち、(2+4)*((1+3)*2)は48になる。
\\ \\
演算子の種類であるが、\textbf{2項演算子}\index{にこうえんざんし@2項演算子}は、その名前のとおり2つの項を結合して値を計算する演算子である。
\textbf{代入演算子}\index{だいにゅうえんざんし@代入演算子}は左辺への操作を示す。例えば、
\begin{code}
a = 3;
a += 5;
\end{code}
というソースは、第1行が「aに3を代入する」となり、第2行が「aに5を加える」という意味になる。これらは演算の評価順序では通常最後になる。つまり、右辺の値がひと通り計算された後で適用される。
\textbf{単項演算子}は一つの項への作用を示すものである。これは少し説明が必要であるので、演算子別に見ていこう。
\begin{enumerate}
\item \textbf{インクリメント}\index{いんくりめんと@インクリメント}/\textbf{デクリメント}\index{でくりめんと@デクリメント}\\
演算子を付した変数に1を加え/減じ、以下それを定数として扱うという演算子である。どういうことかというと、\verb|a++|と書けば、aに1を加えるという意味であるが、これは定数になるので、\verb|(a++)--|などと書いても、正常に動作しない、ということである。これらの演算子は、その項の前後どちらにつけるかによって意味合いが変わる。基本的に、後ろにつけた場合は、ひと通りの評価が終わった後、最後に1を加える/減ずる処理になる。前につけた場合は、最初にこの演算子を評価して、その後他の評価を行うことになる。例えば、a=3,b=5の時、
\begin{code}
c = (a++) + (b++) ;
\end{code}
は、先にcに3+5(=8)が代入されたあと、a,bに1が加えられるが、
\begin{code}
c = (++a) + (++b) ;
\end{code}
はa,bに1が加えられた後、cに(3+1)+(5+1)(=10)が代入されることになる。
\item 符号を示すプラスとマイナス\\
単項演算子のプラスとマイナスは、数学における$-x$や$+2$の$+,-$と同じである。
\item sizeof演算子\footnote{sizeof演算子を関数と混同している初心者がいるが、演算子である。}\\
sizeof演算子は、\verb|sizeof var|のように、変数の前におくことで、その変数の大きさ(バイト)を取得することができる演算子であり、後で解説する派生型の利用などの際に便利である。また、sizeof演算子は後ろに括弧を伴い、その中に変数や型を入れることで、その変数/型の大きさ(バイト)を取得することができる。\verb|sizeof(int)|とすればこれはint型の大きさ、ということになる。基本的には括弧を後ろに伴って用いるが、括弧を必ず伴わなければならないわけではなく、また、括弧の中に変数の型を入れても良い\footnote{これが、sizeofが関数でないことを明確に示す特徴である。}点が他の演算子と違う。
\end{enumerate}
\minisec{型変換}
リスト\ref{program2_2}の11行目と12行目は同じ計算結果を出力しているが、\verb|5 4|と入力したとすると、前者は1になり、後者は1.25になったはずである。これは変数の型が違うことによる。
通常、変数の演算は同じ型の中で行われる。すなわち、int型同士の演算はint型で為される。したがって、5/4は(int型の5)/(int型の4)という計算になり、結果もint型となる。このとき、整数型では、計算結果が通常絶対値の小さい側の整数に丸められる(したがって、-5/4は-1となる。)。
ところが、実際の計算では違う型同士の演算や、同じ型同士の演算でも違う型の結果が欲しい場合がある。このような場合に考慮するのが\textbf{型変換}\index{かたへんかん@型変換}(type conversion)である。型変換には、プログラムが計算内容に応じて自動的に行う\textbf{暗黙の型変換}\index{あんもくのかたへんかん@暗黙の型変換}(implicit type conversion)と、プログラマが変換する型を明示して行う\textbf{キャスト}\index{きゃすと@キャスト}(type casting)がある。
暗黙の型変換は、例えばfloatの値にintの値を足した時などに、floatがintの値をカバーするため、intの値をfloatに変換する等の処理である。違う型同士の計算を行う場合に、カバー範囲の大きい方に自動的に変換してくれる(但し、代入演算子の場合は、左辺の型に合わせて型変換を行う)のが暗黙の型変換である。整数同士や浮動小数点同士でも、float型とdouble型の計算の場合、float型をdouble型に変換するなどの例もある。
一方、キャストは、次のように行う。
\begin{itembox}[l]{キャスト}
キャストは
\begin{center}
\verb|(型名) 変換したい値や式|
\end{center}
\begin{flushright}
によって行われる。
\end{flushright}
\end{itembox}
この時(型)は単項演算子として扱われ、sizeofなどと同様の優先順位で評価される。
以上から、リスト\ref{program2_2}第12行で何が行われているかを解釈してみると
\begin{enumerate}
\item \verb|(float) a|が評価され、\verb|a|がこの式中においてfloat型として扱われる(キャストされた)ことになる。
\item 割り算が評価される。このとき、float型とint型の計算であるので、暗黙の型変換によりfloat型の計算結果が出る。
\end{enumerate}
となる。
型変換も一つの演算であるので、演算に評価順位がある。暗黙の型変換を行う場合、必要なところで初めて行われるのであり、「式中にfloatとintを混在させておけば大丈夫だ」などと考えてはいけない\footnote{試しに、7/3/2.0と、7/2.0/3の2種類を計算してみよう。前者は1.0になるが、後者は1.1以上になるはずである。}。
\newpage
\begin{shadebox}
\section*{本講の要点}
本講では、変数について学習した。
\subsection*{変数について}
\begin{itemize}
\item 変数は、まず型と識別子を指定して宣言を行い、その後初期化を行って、後は変数名を書くことにより参照できる。
\item 変数の名前(識別子)には命名規則があり、それに従わねばならない
\item 符号付き整数型は、通常2の補数表現によって表される。そのため、全てのビットが1であるような数は、int型の場合-1である。
\item Cにおいて、小数を格納する型には浮動小数点型が採用されている。
\item 演算の際には演算例外に注意しなければならない。
\item 文字型は、内部的には整数を格納しており、入出力の際にその整数を文字コードに従って文字に変換して出力している。
\item 文字を'(シングルクォーテーション)で囲むことにより、その文字の文字コードを得ることができる。
\end{itemize}
\subsection*{変数の入出力と演算}
\begin{itemize}
\item 変数を宣言するのは、通常関数の冒頭で、型名の後に変数名を列挙することで行われる。
\item 宣言の際に代入を行うことで変数を初期化することができる。これは、後のコード中において入力や代入で代替することもできる。
\item const修飾子はRead Only(読み取り専用)を示す型修飾子で、これを付して宣言された変数は、以降のコード中において書き換えることができない。
\item scanf関数の引数に指定する変数には、\verb|&|マークを付ける。
\item 演算子は数学と同様に使うことができ、その演算順序も数学と同様である。
\item 型変換には、暗黙の型変換とキャストとがあり、どちらも一種の演算として扱われる。
\end{itemize}
\end{shadebox}