静岡理工科大学 菅沼ホーム 全体目次 演習解答例 付録 索引

第Ⅱ部

第3章 簡単なプログラム

  1. 3.1 プログラムの書き方
    1. 3.1.1 基本原則
    2. 3.1.2 わかりやすいプログラム
  2. 3.2 データ型
    1. 3.2.1 定数
    2. 3.2.2 変数
    3. 3.2.3 列挙型変数(Javaを除く)
    4. 3.2.4 typedef 宣言(Javaを除く)
  3. 3.3 算術演算子と代入演算子
    1. 3.3.1 算術演算子
    2. 3.3.2 代入演算子
    3. 3.3.3 インクリメント,デクリメント演算子
    4. 3.3.4 型変換( cast 演算子)
  4. 3.4 簡単なプログラム
    1. (プログラム例 3.1 ) 2 つのデータの和と差
    2. (プログラム例 3.2 ) 2 つのデータの和と差(cout,cin)(C++)
  5. 3.5 その他
    1. 3.5.1 キーワード
    2. 3.5.2 アスキーコード
    3. 3.5.3 エスケープシーケンス
  6. 演習問題3

3.1 プログラムの書き方

3.1.1 基本原則

  C/C++ は,フリーフォーマットで書くことができる言語です.つまり,日本語などのように,一つの文を任意の行・列から書き始めることが可能ですし,どこで終わっても構いません.また,日本語の場合,一つの文章が「。」で終わるように,C/C++ においてはセミコロン(;)で一つの文章が終了します.

  文章内及び文書間には,単語を分割するような位置でなければ,適当な位置に,また,適当な数だけ区切り記号(半角スペース,タブ,復改,コメント)を入れても構いません.

  コメント(説明,注釈comment)は,/* で始まり */ で終わります.コメントを複数行にわたって書くこともできますが,入れ子(ネスト)にすることは許されません.

----------------------(C++,Java)コメント-----------------------

  C++ や Java では,
	// から行末まで
		
というコメントの書き方が許されます.例えば,
	x = 10.0;			// 変数 x に 10.0 を代入
		
のように書く方法です./* と */ を使用した方法で書けば
	x = 10.0;			/* 変数 x に 10.0 を代入 */
		
となります.なお,以下に示すプログラム例にいて,C のプログラムに対しても,コメントだけは,// という記述を利用する場合があります.

---------------------(C++,Java)コメント終わり------------------

3.1.2 わかりやすいプログラム

  プログラムも一種の文章です.従って,よほど特殊な事情がない限り,読みやすく,理解しやすいことが,プログラムにとって最も重要な課題となります.もちろん,誤りさえなければ,読みやすい,読みにくいに関わらず,プログラムは正しく実行されます.しかし,プログラムを実行するのはコンピュータであっても,プログラムを書いたり,誤りを修正したりするのは人間です.読みやすいプログラムを書くことにより,その内容を他人に説明することが容易になると共に,まず,自分自身が誤りを犯しにくくなります.

  次に示すのは二次方程式を解くためのプログラムです.ただし,各行の最初の番号は,説明のために付加した行番号です.プログラムの内容とは関係ありません(以下のプログラムにおいても同様).
01	#include <stdio.h>
02	#include <math.h>
03	int main(){double a,b,c,d,x,x1,x2;
04	printf("係数a,b,及び,cは? ");scanf("%lf %lf %lf",&a,&b,&c);
05	if(fabs(a) <= 1.0e-10){
06	if(fabs(b) <= 1.0e-10)printf("解を求めることができません!\n");
07	else{x=-c/b;printf("x=%f\n",x);}}
08	else{d=b*b-4.0*a*c;
09	if(d >= 0.0){d=sqrt(d);x1=0.5*(-b-d)/a;x2=0.5*(-b+d)/a;
10	printf("x=%f %f\n",x1,x2);}
11	else{d=sqrt(-d);x1=-0.5*b/a;x2=0.5*d/a;
12	printf("x=%f ± i%f\n",x1,x2);}}return 0;}
		
  上のプログラムを見て読みやすいと感じるでしょうか.もちろん,プログラム言語に関する説明がまだですので,内容自身を的確に把握することは困難かと思います.しかし,同じプログラムを下のように書いたらどうでしょうか.内容自身についてもある程度想像が付くのではないでしょうか.

01	/*********************************/
02	/* 二次方程式を解く              */
03	/*     a * x * x + b * x + c = 0 */
04	/*          coded by Y.Suganuma  */
05	/*********************************/
06	#include <stdio.h>
07	#include <math.h>
08	
09	int main()
10	{
11		double a, b, c, d, x, x1, x2;
12	/*
13	           係数の読み込み
14	*/
15		printf("係数a,b,及び,cは? ");
16		scanf("%lf %lf %lf",&a,&b,&c);
17	/*
18	          一次方程式
19	*/
20		if (fabs(a) <= 1.0e-10) {
21			if (fabs(b) <= 1.0e-10)
22				printf("   解を求めることができません!\n");
23			else {
24				x = -c / b;
25				printf("   x=%f\n",x);
26			}
27		}
28	/*
29	          二次方程式
30	*/
31		else {
32	
33			d = b * b - 4.0 * a * c;
34	               // 2実根
35			if (d >= 0.0) {
36				d  = sqrt(d);
37				x1 = 0.5 * (-b - d) / a;
38				x2 = 0.5 * (-b + d) / a;
39				printf("   x=%f %f\n",x1,x2);
40			}
41	               // 虚数
42			else {
43				d  = sqrt(-d);
44				x1 = -0.5 * b / a;
45				x2 = 0.5 * d / a;
46				printf("   x=%f ± i%f\n",x1,x2);
47			}
48		}
49
50		return 0;
51	}
		

  プログラムをどのように書けば読みやすいかということに対する明確な定義があるわけではありません.しかし,経験的に,以下に示すような規則を守って書くと良いと思います.もちろん,個人的な好みの問題もありますので,自分自身でも適当に工夫してみて下さい.

  1. プログラム全体,主要な変数・引数の説明( 1~5 行目)や,プログラムの各部分に対する説明( 12~14 行目等)を必ず入れる.

  2. 機能ブロック毎に字下げ(上のプログラムでは,tab を使用して字下げを行っている)を行う.字下げを行うことにより,その機能ブロックの範囲が一目でわかるようになる.例えば,11~50 行目は,10 行目及び 51 行目に対して,字下げしてある(プログラムの内容であることを示している).また,36~39 行目は,35 行目及び 40 行目に対して字下げしてあるので,条件 「 d >= 0 」 が満たされたときの処理であることが一目でわかる.

  3. 一つの行に複数の文を書かない(場合によっては,複数の文を書いた方が見やすい場合もある).

  4. 読み易さを考えて適当にスペースを入れる.特に,演算子の前後には必ずスペースを入れ,また,代入文が続いたときは等号をそろえる( 36~38 行目等).

  5. 一つのプログラムは,せいぜい,50~100 行程度以内にする.

  6. C/C++ で記述可能だからといって,あまり凝った表現を使用しない.

3.2 データ型

  数式と同じように,C/C++ においても,定数や変数を使用できます.その意味するところは,数学の場合とかなり似ています.しかし,直接対応するものが数学にはない「データ型」という概念が存在します.

  プログラムの中で使用した変数variable )や定数constant )は,必ず,主記憶上のどこかに記憶されます.また,変数に記憶されている値や定数が整数なのか,浮動小数点数(実数)なのか,文字なのか,さらに,記憶するのに何バイト必要なのか等によって,記憶する領域の大きさや表現方法が異なります.これらのことを規定するのがデータ型です.

3.2.1 定数

  定数には,整数定数浮動小数点定数文字定数,および,文字列定数の 4 種類があります( C++ や Java の場合は,truefalse からなる論理型定数が加わります).定数の場合,そのデータ型は,定数の記述方法によって一意的に決まります.

  整数定数は,以下のように,10 進数,16 進数,または,8 進数で記述します.

10 進数: 0 以外の数字または +,- で始まる数字列(例えば,132,-34 等)
16 進数: 0x または 0X で始まる数字列(例えば,0xFD4C.なお,16 進数における a ~ f は,大文字でも小文字でも構いません)
8 進数 : 0 で始まる数字列(例えば,0734)

  例えば,1234 のように書けば,整数定数とみなされ,2 バイトまたは 4 バイトの領域が確保され(コンパイラによって異なる),基本的に,1.2.3.1 節で述べた整数の表現方法に従って記憶されます( int 型定数).int 型が 2 バイトで定義されており,かつ,値がその領域に入りきらないようなときは,例えば,123456789L のように,後ろに「l(エル)」または「L」(接尾子)を付加する必要があります( long int 型定数).int 型が 4 バイトで定義されているような場合は,long int 型と int 型は同じものになり,このようなことを考慮する必要はありません.ただし,8 バイトで定義される long long int 型定数の場合は,123451234512345LL のように,「ll」または「LL」を付加する必要があります.

  1234.0 のように,小数点を使用して数値を記述すると,それは浮動小数点型定数となり,8 バイトの領域が確保され,基本的に,1.2.3.2 節で述べた浮動小数の表現方法に従って記憶されます( double 型定数long double 型定数の場合は,1234.0L のように,l,または,L を付加する必要がある).もし,多くの有効桁数を必要とせず,かつ,メモリを節約したい場合には,1234.0F のように,接尾子「f」または「F」を付けることにより,4 バイトの浮動小数で表現することも可能です( float 型定数).また,1234.0 を,1.234e+3 ( 1.234×10+3 の意味)のようにも表現可能です.

  文字定数は 'a'( a は 1 バイトの文字),また,文字列定数は "abc" のように記述します.ここで注意すべきことは,'a' と "a" が同じでは無いという点です.前者は文字 a が入る 1 バイトの領域が確保されますが,後者では,2 バイトの領域が確保され,文字 a と共に,文字列の終わりであることを示す '\0'(ヌル文字)が記憶されます.このように,文字列定数の場合,与えられた文字列の最後にヌル文字が付加され,実際の文字数より 1 文字文だけ多い領域が確保されます.なお,'漢'は文字定数として正しい表現のように見えますが,全角文字は 2 バイトで表現されますので,誤りとなります.全角文字は,たとえそれが 1 文字であっても,"漢"のように,文字列定数として記述する必要があります.

3.2.2 変数

  変数は,数値や文字を記憶するメモリ内の特定の領域に着けられた名前です.定数とは異なり,あらかじめそこに記憶されるデータが常に決まっているわけではありません.しかし,データの型により,必要とする領域の大きさや表現方法が異なりますので,ある変数が示す領域に任意のデータを記憶するわけにはいきません.前もって,その領域に記憶すべきデータのtype )を指定してやる必要があります.これを,変数の型宣言と言います.

  基本的に,C/C++ で使用するすべての変数に対して,次のような型宣言文を使用して,その型を定義してやる必要があります.これらの型宣言は,プログラムの最初で,つまり,各プログラム(関数)において,後に述べる代入文,if 文等の現れる前に行われていなければなりません.

  変数の型宣言は,以下のような形式で行います.
	データ型 変数名1[= 初期値], 変数名2[= 初期値], ・・・;
		
データ型とは,char,int 等であり,例えば,変数 x の型を宣言するためには,基本的に,以下のいずれかの型を選択します.
	データ型                バイト数と値の範囲
	void                    *  *
	char                    1  -128 ~ 127(文字型,1バイトの整数型)
	unsigned char           1  0 ~ 255(文字型,1バイトの符号無し整数型)
	short                   2  -32,768 ~ 32,767(2バイトの整数型)
	unsigned short          2  0 ~ 65,535(2バイトの符号無し整数型)
	int                     *  システム依存(整数型)
	unsigned int            *  システム依存(符号無し整数型)
	long int                4  -2,147,483,648 ~ 2,147,483,647(4バイトの整数型)
	unsigned long           4  0 ~ 4,294,967,295(4バイトの符号無し整数型)
	long long int           8  -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807(8バイトの整数型)
	unsigned long long int  8  0 ~ 18,446,744,073,709,551,615(8バイトの符号無し整数型)
	float                   4  3.4E±38(浮動小数点型,有効桁は約7桁)
	double                  8  1.7E±308(浮動小数点型,有効桁は約15桁)
	long double             *  拡張精度,システム依存(浮動小数点型)
	bool(C++)    1  true(0以外) or false(0)(論理型)
		
  変数が定義されただけでは,その変数が示す領域にどのようなデータが入っているかは未定です.もし,最初,その変数の領域に何らかの値を設定しておきたい場合は,初期値の項を記述してやることによって可能です(初期化初期設定).例えば,double 型変数 x の初期値を 10.5 としたい場合は,以下のように記述します(この段階で,変数 y の値は未定).
	double x = 10.5, y;
		
  変数名としては,英字と数字を利用でき,通常,小文字で書きます.ただし,第 1 文字は英字でなくてはなりません.また,下線 「 _ 」 は,英字に含まれ,例えば,english_test のように,長い変数名を読みやすくするために使用されます.変数名の長さについては,特別な制限はありませんが,31 文字を超えた部分については一義性が保証されません.

  基本的には,変数名としてどのような名前を付けても構いませんが,C/C++ 言語の中で特別な意味を持っている if,else,int,float 等のキーワード(keyword,予約語)は予約済みであり,変数名として使用してはいけません.

  以上述べたことのまとめとして,型宣言文の例を挙げておきます.
	int abc, _bef;   // 正.複数の変数をカンマで区切って並べることが可能
	double abc, _bef = 3.5;   // 正.変数 _bef に対しては初期設定を行っている
	int a, A;   // 正.変数 a と A は異なる
	char a = 'A';   // 正.変数 a を A という文字(アスキーコードで 65 )で初期化
	char a = 65;   // 正.変数 a を 65 で初期化(上と同等,char は,1 バイトの整数とみなすことができる)
	int a, abc, a;   // .同じ変数を 2 度定義してはいけない
	int if;   // .キーワードは変数名として使用できない
	int 10a;   // .変数名の最初は,英字または下線
	int a+10;   // .変数名に使用できるのは,英数字と下線だけ
	int a = 3.5;   // .int 型の変数の初期値として不適当
	char a = "ABC", b = "漢";   // いずれも.単純変数に文字列を記憶することはできない
		
-----------------(C++, Java)変数の型宣言の位置--------------------

  C++ や Java では,変数を最初に使用する位置,または,その前の任意の位置で宣言し,初期化も同時に行うことが可能です.例えば,
	  ・・・
	x = 10.0;
	double y = x + 5.0;
	  ・・・
		
のようなプログラムは,C ではエラーになりますが,C++ では許されます.変数を最初に使用する場所で変数宣言を行うことにより,初期化する前の変数を参照するとか,また,宣言しただけで使用しなかったといったバグを防ぐ効果はありますが,場合によっては,プログラムを読みにくくしますので注意して下さい.

  また,上のようにして宣言された変数を使用(参照,変更)できるのは,宣言された位置からその宣言が入っているブロック( { } で囲まれた部分等)の終わりまです.たとえば,以下に示す例において,変数 k の有効範囲は,for ループ(後述)の { } で囲まれた部分だけであり,それ以外の場所で型宣言を行わずに変数 k を使用すればエラーになります.
	for (int k = 0; k < 10; k++) {
	  ・・・
	  ・・・
	}
		
-----------------(C++, Java)変数の型宣言の位置終わり---------------

3.2.3 列挙型変数(Javaを除く)

  変数・定数の特別な型として,列挙型変数・列挙定数があります.例えば,変数 color の値が 0 のときは赤,1 のときは青等を表したいとします.しかし,このような数字での記述だと各数字が何色を表現しているのかが分かり難くなります.そこで,変数 color を列挙型変数として,
	enum coltype {red, blue, black, white} color;
		
のように宣言しておくと( red,brue 等を列挙定数と呼びます),
	color = blue;           /* 変数 color に青を代入 */
	if (color == red)       /* もし,色が赤ならば */
		
のような表現が可能になります.列挙定数は int 値を持ち,その値は,順に,0,1,2,・・・となります.ただし,'=' 演算子を使用して,その値を変更することができます.例えば,
	enum coltype {red, blue, black=5, white} color;
		
とすると,各列挙定数の値は,
	red : 0,  blue : 1,  black : 5,  white : 6
		
となります.列挙型の宣言方法の一般形式は以下のようになります.
	enum [列挙型名] [{列挙定数リスト}] [変数リスト];
		
また,型宣言と変数の宣言を以下のように,別々に書くこともできます.
	enum coltype {red, blue, black, white};
	enum coltype color;
		

3.2.4 typedef 宣言(Javaを除く)

  次の方法により,既存のデータ型に別の名前を与え,新しいデータ型の名前を作成することが可能です.
	typedef 既存のデータ型 同義語名
		
例えば,
	typedef int word;
		
と宣言することにより,変数 x を int で宣言するのに,
	word x;
		
と書くことができます.

3.3 算術演算子と代入演算子

  C/C++ において使用できる演算子operator )には,多くのものが存在しますが,この節では,その代表的なものについて説明します.

3.3.1 算術演算子

  プログラムを構成する最も基本的な処理は,定数と変数を使用し何らかの計算を行うことです.その際使用される算術演算子としては,以下のようなものがあります.

+ : 加算
- : 減算
* : 乗算
/ : 除算
% : 余り(整数演算に対してだけ使用可能)

数学の場合と同様に,これらの算術演算子と括弧を使用して,様々な計算を行うことができます.

  記述された計算式は,基本的に,左から順に計算されていきます.しかし,「+」や「-」は,「*」や「/」や「%」より優先度が低いため,「*」等より後に計算されます.しかし,括弧があれば,その中が最も優先的に計算される点は,数学の場合と同じです.

  しかし,整数同士の演算には十分注意して下さい.例えば,

10.0 / 4.0 * 2.0

と記述すれば,各定数は浮動小数点数として解釈され,10.0 を 4.0 で割った結果 2.5 に 2.0 が掛けられ結果は 5.0 になります.しかし,人間が計算する場合は同じであっても,

10 / 4 * 2

と記述すると,各定数は整数として解釈され,10 を 4 で割った結果 2 (整数計算であるので,結果も整数になり,この段階で,小数点以下が切り捨てられる)に 2 が掛けられ,結果は 4 になります.これは,定数だけでなく変数を含む演算であっても同様です.

  同じような演算とその結果を以下に示します.なぜ,そのような結果になるかを十分理解してください.

演算 説明
7 / 3 * 3 7 / 3 * 3 = 2 * 2 = 6
7 / (3 * 3) 7 / (3 * 3) = 7 / 9 = 0
7 / 3 / 3 7 / 3 / 3 = 2 / 3 = 0

3.3.2 代入演算子

  プログラムによっては,演算した結果をどこかへ記憶しておき,その値を別の箇所で使用したいような場合がしばしば起こります.それを実現するのが代入演算子「 = 」です.代入演算子の左辺は必ず変数でなければなりません.例えば,前節の 2 つの演算結果を double 型変数 data 及び int 型変数 i_data に代入するためには,以下のように書きます.
	data   = 10.0 / 4.0 * 2.0;
	i_data = 10 / 4 * 2;
		
  右辺で演算した結果と,代入する変数の型が異なる場合は,演算結果を代入する変数の型に変換した後,代入されます.例えば,x を int 型の変数とした場合,
	x = 10.0 / 4.0;
		
のような代入を行うと,演算結果が int 型に変換された後(小数点以下が切り捨てられる),変数 x に代入されます.その結果,x の値は 2 となります.しかし,予期せぬ結果が発生する場合もありますので,原則的には行わないようしにしてください.どうしても必要な場合は,後に述べる cast 演算子を利用してください.

  代入演算子は,一見,等号のように見えますが,等号ではないことに注意して下さい.例えば,
	k = 2;
	k = k + 3;
		
という 2 つの文が順に実行される場合を考えてみます.まず,最初の文の実行により変数 k に値 2 が代入されます.次に,2 番目の文により,現在の変数 k の値( = 2 )と 3 を加えた結果 5 が変数 k に代入されます.したがって,この時点で,変数 k の値は 5 になっています.明らかに,等号とは異なることが分かると思います.

  また,ある変数に関する演算と,結果のその変数への代入を同時に行う演算子が存在します.例えば,上の 2 番目の例は,
	k += 3;
		
のようにも書けます.この演算子は,「-」,「*」,「/」,及び,「%」に対しても存在します.

  さらに,同じ値を複数の変数に代入したいとき,
	x = y = z = 20.4;
		
のような記述が可能です.

  先に述べたように,単に変数を定義した(型宣言した)だけでは,領域が確保されるだけであり,その変数に記憶されている値は未定です.例えば,プログラム
	int x = 5, y;
	x  = 3;   // 初期設定された 5 という値は失われる
	x *= 5;
	y  = x + 2;
		
の 1 行目において,変数 x の値は初期値によって確定しますが,y の値は未定です.変数の値が決まるのは,代入,又は,後に述べる入力文によってその変数に値が入力されたときです.上に示すプログラム例では,4 行目の実行が終了した後,変数 y の値が確定( 17 )します.変数の値が確定する前に,その変数を参照するようなことは絶対に行ってはなりません.例えば,4 行目より前に,
	x = y + 5;
		
のように,y の値を参照するような演算を行うことはできません.

  また,各変数には,最後に代入または入力された値が記憶されています.ある変数に最後の代入または入力が行われた時点(例えば,3 行目)で,その変数( x )がそれ以前に記憶していた値(初期設定された 5 や 代入された 3 )はすべて失われます.

3.3.3 インクリメント,デクリメント演算子

  1 だけ増やしたり減らしたりするのに,「++」(インクリメント演算子)や「--」(デクリメント演算子)といった演算子を使用できます.例えば,
	k++;
	n = 3 + m++;
		
のような使い方をします.1 行目は,
	k = k + 1;
		
と同じ意味です.また,2 行目は,
	n = 3 + m;
	m = m + 1;
		
と同じ意味です.上の例では,「++」を変数の後ろに付けましたが,これは,現在の値を演算に使用した後,「++」の付いた変数の値を 1 だけ増加させることを意味します.しかし,「++」を変数の前に付けると,その変数の値を 1 だけ増加させた後,演算に使用されます.例えば,
	n = 3 + ++m;
		
は,
	m = m + 1;
	n = 3 + m;
		
と同じ意味になります.演算子「--」についても,1 だけ減少させる点を除き,「++」と同様です.

3.3.4 型変換(キャスト(cast)演算子)

  演算は同じ型同士で行われ,また,代入も同じ型の変数に代入されるのが普通です.しかし,場合によっては,異なる型同士で演算したり,異なる型の変数へ代入したい場合が起こります.

  コンピュータは,基本的に,異なる型同士の演算を行うことができません.従って,そのような演算式が現れるとデータをいずれかの型に変換した後演算が行われます.例えば,
	10.0 / 4;
		
のような計算は,整数定数 4 を浮動小数点数に変換した後,演算が行われ,結果は,浮動小数点数になります(この場合は,2.5 ).一般に,複数のデータ型が混在した場合,変換によって失われる情報が少なくなることを目的として,以下に示すように,より上位の型に変換されます.
	char < int < long < float < double < ・・・
		
  また,代入の際は,代入すべき変数の型に変換され,代入が実行されます.例えば,db を double 型変数,k を int 型変数とします.このとき,
	db = 10 / 3;
	k  = 10.0 / 4.0;
		
のような代入を行うと,最初の文では,整数 10 を整数 3 で割った結果 3 が,浮動小数点数( double 型)に変換され,変数 db には 3.0 が代入されます.また,2 番目の文では,演算の結果 2.5 が整数( int 型)に変換され,変数 k には小数点以下が切り捨てられた 2 が代入されます.

  このように,異なる型の処理は自動的な型変換により実行できますが,場合によっては,思いもかけないことが起こります.また,自動的型変換により,自分自身の型宣言の誤りに気付かないまま実行されてしまう場合も,しばしば起こります.従って,できるだけ自動的な型変換は使用せず,明示的に型を変換した方が良いと思います.それを行うのが,キャスト演算子cast operator )です.キャスト演算子を変換したい定数または変数の前に付加して,希望の型に変換します.例えば,変数 db1,db2 を double 型とします.
	db1 = 10.4;
	db2 = (double)((int)db1 / 4)
		
2 番目の文では,変数 db1 が int 型に変換された後,10 / 4 の整数演算が行われ,その結果が 2 となります.次に,整数 2 が double 型に変換され( 2.0 ),変数 db2 に代入されます.

  同じような演算とその結果を以下に示します.この例によって,キャスト演算子や自動的型変換について十分理解してください.

演算 説明
(double)(7 / 2) (double)(7 / 2) = (double)3 = 3.0
7 / (double)2 7 / (double)2 = 7 / 2.0 = 7.0 / 2.0 = 3.5
7 / 2.0 7 / 2.0 = 7.0 / 2.0 = 3.5
7 / 2 3

3.4 簡単なプログラム

  以上の説明により,入出力に関する項を除いて,簡単なプログラムが書けるはずです.この節では,2 つのデータを入力し,その和と差を出力するプログラムについて検討します.プログラムは,特別な命令が存在しない限り,書かれた順序に従って実行されていきます.以下に示すプログラム例では,この原則通り,最初の行から順に(実行可能な文が)実行されていきます.

  C/C++ のプログラムは,関数の集まりと言っても過言ではありません.プログラム例 3.1 に現れる printf や scanf も関数です.関数に関する詳細な説明は,後の章で行いますが,ある面で,数学の関数と非常に似ています.数学の関数は,その関数の中の変数に適当な値を代入すればそのときの関数値が得られます.C/C++ においても,例えば,正弦を計算する関数 sin(x) は,変数 x に適当な値を代入してやれば,その角度における正弦が計算されて返されます.ただし,printf や scanf のように,単に値を返すだけでなく,出力や入力といった複雑な処理を行う関数も多く存在します.

  完全に関数を理解することは,現在の段階では困難であり,また,printf や scanf という関数に対しても,初心者が誤って使用する例が多く見受けられます.そこで,C++ に興味がなくても,もし,C++ のコンパイラが手元にあるようでしたら,しばらくの間,入出力文だけはプログラム例 3.2 の方法を使用するのも良い方法かもしれません.

(プログラム例 3.1 ) 2 つのデータの和と差 

01	/****************************/
02	/* 2つのデータの和と差     */
03	/*      coded by Y.Suganuma */
04	/****************************/
05	#include <stdio.h>
06
07	int main()
08	{
09		double sa, wa, x, y;
10	/*
11			データの入力
12	*/
13		printf("2つのデータを入力して下さい ");
14		scanf("%lf %lf", &x, &y);
15	/*
16			和と差の計算
17	*/
18		wa = x + y;   // double wa = x + y;
19		sa = x - y;   // double sa = x - y;
20	/*
21			結果の出力
22	*/
23		printf("和は=%f 差は=%f\n", wa, sa);
24
25		return 0;
26	}
		
1 ~ 4 行目

  プログラム全体に対する注釈です.注釈は,人間がプログラムを読む際,理解しやすくするためのものであり,コンパイラ等によって特別な処理はされません.プログラムを実行するのはコンピュータですが,プログラムを書いたり修正したりするのは人間です.従って,プログラムを書く際に最も注意すべきことは,如何に読み易く,かつ,分かり易いプログラムを書くかという点です.できるだけ多くの注釈を入れておいて下さい.そのことにより,他の人がプログラムを理解しやすくなると共に,プログラム上のエラーも少なくなるはずです.

  C/C++ の場合,「/*」と「*/」で挟まれた部分は,注釈とみなされます.従って,10~12 行目,15~17 行目,及び,20~22 行目も注釈であり,プログラムの該当する部分における処理内容を説明しています.

5 行目

  「#」で始まる文は,プリプロセッサ(第 9 章参照)により処理され,結果がコンパイラに渡されます.#include は,ヘッダファイル stdio.h の取り込みを行います.C/C++ では,関数を多く使用します.例えば,13,14 行目の printf,scanf もシステムが用意した関数です.これらの関数を使用するためには,使用するに先立って,様々な宣言等を行う必要があります.その宣言等を自分で書くのは面倒なため,システムには,使用する関数毎に必要な宣言を記述したファイルが準備されており,それをヘッダファイルと呼びます.関数によってどのようなヘッダファイルを必要とするかは,マニュアル等に書いてありますので,その都度必要なヘッダファイルを記述して下さい.stdio.h は,関数 printf や scanf を使用するために必要なヘッダファイルであり,プログラムを作る場合,この行を常に付加しておいた方が良いと思います.

  なお,ヘッダファイルを自分で作成することもできます.

7 行目

  プログラムの最初であることを表します.8 行目の「{」と 26 行目の「}」に囲まれた部分がプログラムの本体になります.従って,7,8,25,及び,26 行目は,C/C++ のプログラムにとって常に必要となります.

  また,プログラムの本体に当たる 9 行目から 25 行目までは,段落が下げて(字下げして)書かれていますが,これも,プログラムを読みやすくするための一つの手段であり,必ず,このように,段落を下げて書いて下さい(どの程度下げるかは任意ですが,タブを使用する方法が一般的です).

9 行目

  プログラムで使用する変数の型を宣言している型宣言文です.変数 sa,wa,x,及び,y が double 型であることを宣言しています.初期値の指定を行っていませんので,この段階では 4 つの変数の値は未定となります.なお,この文のように,一般的に,C/C++ における一つの文の終わりにはセミコロン「;」を付ける必要があります.なお,C++ の場合は,プログラム例 3.2 と同様,この位置で型宣言を行わず,14 行目の前で,
	double x, y;
			
のような型宣言を行うと共に,18,19 行目をコメントに示すように変更することによっても可能です.

13 ~ 14,23 行目

  13,14 行目は,2 つのデータを入力するための文です.単に,入力のためだけなら,14 行目の scanf だけで十分ですが,その場合,何のメッセージも出力されずキーボードからの入力待ちになってしまうため,一見コンピュータが止まってしまったように感じます.また,多くの入力を要求するような場合は,scanf だけでは,どの入力を要求しているのかが分かりません.そのため,13 行目の printf が使用されています.

  標準入出力装置(一般的には,キーボードとディスプレイ)に対して入出力を行う場合,対象とするものは文字列です.キーボードから入力する場合,たとえ数値であっても,2 進数を使用したコンピュータの内部表現ではなく,例えば「123.45」のように,我々が読むことができる文字列として入力します.しかし,数値データを,入力された文字列としてそのまま記憶したならば,演算等を行うことができません.そのため,入力された文字列をコンピュータ内部で使用する表現方法に変換して記憶してやる必要があります.例えば,「123.45」という文字列を数値として扱いたければ,浮動小数点表現に変換して記憶しておく必要があります.もちろん,「123.45」を文字列として内部的に扱いたければ,文字列として記憶しておく必要があります.

  また,ディスプレイに出力する場合も,メモリ(変数)に記憶されているデータを文字列に変換して出力します.さもなければ,我々は,0 と 1 の並びとして出力される結果を自分自身で解釈しなければなりません.次に示すプログラム例のように,C++ における cin や cout を使用する場合は,これらの変換を自動的に行ってくれますが,scnaf や printf を使用する場合,これらの変換方法を指定してやる必要があります.

  例えば,scanf は,以下のようにして使用します(以下の説明において,char 部分に対する説明は,ここでは無視して下さい).
   double d_data;
   int i_data;
   char c_data[10];
   scanf("%lf %d %s", &d_data, &i_data, c_data);
			
「"%lf %d %s"」の部分が,入力されたデータをどのように変換するかを指定する部分です.「%」に続く文字列が 3 つありますので,3 つのデータが入力されることを意味します.入力された文字列に対して,「%lf」は double 型( float 型は %f,long double 型は %Lf )の浮動小数点表示に変換して,「%d」は int 型( long int 型は %ld であるが,int 型と long int 型のサイズが等しいときはいずれも %d とする.また,long long int 型は %lld となる.)の整数に変換して,また,「%s」は文字列としてそのまま,記憶することを意味しています.これら 3 つの「%」で始まる文字列は,次に続く 3 つのデータに順番に対応していますので,この scanf 関数に対して,例えば,
   3.14 123 abc
			
のように入力すると,d_data に「3.14」が double 型に変換され,i_data に「123」が int 型に変換され,また,c_data に文字列「abc」が,記憶されます.各変数に対して,そのアドレスを指定しなければならない(アドレスについては,後の章で説明します.ここでは,変数に「&」記号が付くという程度で理解しておいてください)点に注意してください.

  printf は,scanf とは逆に,記憶されたデータを文字列に変換する操作を行います.例えば,以下のようにして使用します.
   double d_data;
   int i_data;
   char c_data[10];
     ・・・・・
   printf("結果は %f %10.3f %d %5d %s\n", d_data, d_data, i_data, i_data, c_data);
			
この結果,まず,「結果は 」という文字列が出力されます.printf においては,「%」で始まる文字列とエスケープシーケンス(後述)以外は,記述された内容がそのまま出力されます.次に,以下の順序で 5 つのデータが出力されます(各データ間には,1 つのスペースが入る).

  1. 「%f」は double 型( %Lf は long double 型)のデータを固定小数点表現の文字列に変換します.なお,1.23x10-3 のような表現方法に対応する 1.23e-03 という方法-浮動小数点表現-も存在します( %e,%Le).「%」と「f」の間に何も記述しなければ,全体の桁数や小数点以下の桁数がシステムの標準形式に従います.この場合,d_data の内容が,システムの標準形式に従って出力されます.
  2. 最初のデータと変換方法は同じですが,この場合は,出力形式を指定しています.d_data の内容が,小数点以下 3 桁,全体の桁数 10 桁で出力されます(例: △△△-12.345 ).桁数が 10 桁に満たない場合は,左側にスペースが挿入されます.全体の桁数を指定しない場合は,「10」の部分を省略しても構いません.
  3. 「%d」は int 型( long int 型は %ld であるが,int 型と long int 型のサイズが等しいときはいずれも %d とする.また,long long int 型は %lld となる.)のデータを文字列に変換します.「%」と「d」の間に何も記述しなければ,システムの標準形式に従って出力されます.この場合,i_data の内容が,システムの標準形式に従って出力されます.
  4. 上の i_data と変換方法は同じですが,この場合は,出力形式を指定しています.i_data の内容が,全体の桁数 5 桁で出力されます(例: △△-12 ).桁数が 5 桁に満たない場合は,左側にスペースが挿入されます.
  5. c_data の内容が文字列として出力されます.なお,1 文字に対する入出力には,「%c」を使用します.

  以上の説明に従うと,13 行目の printf は,入力を促すメッセージを出力するだけです.23 行目では,wa と sa の値を出力しています.23 行目の「"」の中の最後の記号「\n」も 1 文字を表し,そのまま出力されますが,「\」の付いた記号は,エスケープシーケンス(escape sequence)といって,特別な働きをします.例えば,「\n」が出力されると改行が行われます.

  14 行目の scanf では,キーボードから入力された 2 つのデータが変数 x 及び y に代入されます.ここで初めて,2 つの変数の値が確定することになります.もちろん,この時点では,まだ,変数 wa,及び,sa の値は未定のままです.この関数では,各変数の前に「&」を付加する必要があることに注意して下さい.

18 ~ 19 行目

  これらの文では,見て明らかなように,和と差の計算をし,結果を変数 wa と sa に代入しています.その結果,18 行目で変数 wa の値が,また,19 行目で変数 sa の値が未定ではなくなります.変数 x,及び,y に対しては,それらの値が参照されているだけですので,14 行目で確定した値がそのまま保たれています.

  一般的に,変数の値が変化する(記憶されている値が破壊される)のは,その変数に対して,代入,または,入力が実行された場合だけです.たとえば,19 行目以降で,変数 sa に対して,
	scanf("%lf", &sa);
			
または,
	sa = 20;
			
のような文が実行されると,19 行目で代入された値は失われ,新たに入力された値(最初の文),または,代入された値( 2 番目の文,この場合は,20 )が,変数 sa の値として記憶されます.

  このプログラムを実行し,5 と 3 を入力すると,以下のような結果が得られます.
		和は=8.000000 差は=2.000000
			

(プログラム例 3.2 ) 2 つのデータの和と差(cout,cin)(C++)

  プログラム例 3.1 と全く同じ内容を C++ で使用できる入出力方法を使って書いてみました.初心者は,printf や scanf の使用に際し,特にデータ型の不一致が原因である誤りをよく起こします.そのため,結果が正しく出力されなかったり,場合によっては,プログラム自身を破壊してしまうことも少なくありません.このプログラムの入出力文では,変数の型を考慮せず,単に変数を並べるだけで入出力が行えるようになっています.

  このプログラムは,プログラム例 3.1 と,5 行目のヘッダファイル,及び,13,14,23 行目の入出力文が異なっているだけです.以下に現れるプログラムにおいても,上の箇所だけを修正してやれば,全く同じように実行できるはずです.なお,23 行目の std::endl は,改行を意味し,"\n" または '\n' と記述しても構いません.

  cout,cin,endl の前に付加してある「std::」の意味については,名前空間に関する節で説明します.それまでは,形式的に std:: 付加しておいてください.なお,5 行目の後ろに,
	using namespace std;
		
という行を挿入することによって,std:: を付加せず,単に,cout,cin,endl と記述することも可能です.

01	/****************************/
02	/* 2つのデータの和と差     */
03	/*      coded by Y.Suganuma */
04	/****************************/
05	#include <iostream>
06
07	int main()
08	{
09	/*
10			データの入力
11	*/
12		double x, y;
13		std::cout << "2つのデータを入力して下さい ";
14		std::cin >> x >> y;
15	/*
16			和と差の計算
17	*/
18		double wa = x + y;
19		double sa = x - y;
20	/*
21			結果の出力
22	*/
23		std::cout << "和は=" << wa << " 差は=" << sa << std::endl;
24
25		return 0;
26	}
		

  重要なことですので,再度述べておきます.上で述べたいずれの例においても同様ですが,ある変数に対して初期値を指定しない型宣言を行うと,その変数に対応した記憶場所は確保されますが,その値は未定です.変数の値を確定するためには,「型宣言文で初期値を指定する」,「代入演算子によってその変数に値を代入する」「入力文によって,その変数に値を入力する」などの処理が必要です.また,代入や入力処理が行われると,その変数にそれまで記憶されていた内容は失われます.

  以下に示す表では,入力データとして 5 を入力した場合,プログラムの各行が実行された後に変数 x 及び y の値がどのようになっているかを示しています(「-」は値が未定であることを示す).このように,書かれたプログラムを読み,そのプログラムがどのような順序で実行され,かつ,変数の値がどのように変化していくかを確認することは,プログラムを書く上で非常に重要な作業になります.今後,プログラムを書く際は,必ず行ってください.

実行順序 プログラム x の値 y の値
1 int x, y = 10; - 10
2 scanf("%d", &y); - 5
3 x = y + 3; 8 5
4 x *= 5; 40 5
5 printf("%d\n", x); 40 5

3.5 その他

3.5.1 キーワード

  C/C++ のキーワードkeyword )は以下の通りです.
	auto      break       case        char        const       continue
	default   do          double      else        enum        extern
	float     for         goto        if          int         long
	register  return      short       signed      sizeof      static
	struct    switch      typedef     union       unsigned    void
	volatile  while
	
	(C++)
	asm       catch       class       delete      false       friend
	inline    new         operator    private     protected   public
	template  this        throw       true        try         virtual
		

3.5.2 アスキーコード

  アスキーコードASCII code )表です
                  ASCII/JIS コードテーブル (0~127)

	000 ^@ (nul)  016 ^P (dle)  032 (sp)  048 0  064 @  080 P  096 `  112 p
	001 ^A (soh)  017 ^Q (dc1)  033 !     049 1  065 A  081 Q  097 a  113 q
	002 ^B (stx)  018 ^R (dc2)  034 "     050 2  066 B  082 R  098 b  114 r
	003 ^C (etx)  019 ^S (dc3)  035 #     051 3  067 C  083 S  099 c  115 s
	004 ^D (eot)  020 ^T (dc4)  036 $     052 4  068 D  084 T  100 d  116 t
	005 ^E (enq)  021 ^U (nak)  037 %     053 5  069 E  085 U  101 e  117 u
	006 ^F (ack)  022 ^V (syn)  038 &     054 6  070 F  086 V  102 f  118 v
	007 ^G (bel)  023 ^W (etb)  039 '     055 7  071 G  087 W  103 g  119 w
	008 ^H (bs)   024 ^X (can)  040 (     056 8  072 H  088 X  104 h  120 x
	009 ^I (tab)  025 ^Y (em)   041 )     057 9  073 I  089 Y  105 i  121 y
	010 ^J (lf)   026 ^Z (eof)  042 *     058 :  074 J  090 Z  106 j  122 z
	011 ^K (vt)   027 ^[ (esc)  043 +     059 ;  075 K  091 [  107 k  123 {
	012 ^L (np)   028 ^\ (fs)   044 ,     060 <  076 L  092 \  108 l  124 |
	013 ^M (cr)   029 ^] (gs)   045 -     061 =  077 M  093 ]  109 m  125 }
	014 ^N (so)   030 ^^ (rs)   046 .     062 >  078 N  094 ^  110 n  126 ~
	015 ^O (si)   031 ^_ (us)   047 /     063 ?  079 O  095 _  111 o  127 
		

3.5.3 エスケープシーケンス

  記号(\)とそれに続く文字または数字の組み合わせをエスケープシーケンスEscape Sequence )と呼びます.文字定数の一種であり,端末やプリンタ上でのキャリッジリターンやタブなどの動作を指定するために使います.また,ダブルコーテーションマーク(")など通常は特別な意味を持つ文字や,出力できない文字を表すときにも使用します.C/C++ のエスケープシーケンスは,次のとおりです.
	Seq.   名前              Seq.   名前
	\a     ベル              \?     リテラル クオーテーション
	\b     バック スペース   \'     シングル クォーテーション
	\f     改ページ          \"     ダブル クォーテーション
	\n     復改              \\     円記号
	\r     改行              \ddd   8進表記による ASCII 文字
	\t     水平タブ          \xdd   16進表記による ASCII 文字
	\v     垂直タブ
		

演習問題3

[問1]以下の演算を C/C++ のプログラム内で実行した結果を答えよ.
(1)4.0 / 5.0
(2)4 / 5
(3)(double)4 / 5
(4)(double)(4 / 5)
(5)(int)(4.0 / 5.0)
(6)(20 / 5) * (19 / 4)
(7)(20.0 / 5.0) * (19.0 / 4.0)
(8)20 / 5 * 19 / 4

[問2]台形の上底 t1,下底 t2,及び,高さ h の値を,それぞれ,3.5,1.0,及び,0.7 としたとき(これらの値は,各変数に代入または初期設定せよ),台形の面積を計算し,出力するプログラムを書け.

[問3]円の半径を読み込み,その円の円周と面積を出力するプログラムを書け.

[問4] x の値を読み込み,次の各関数の値( y )を出力するプログラムを書け.
(1)y = x3 + 3x2 + 2
(2)y = (x + 3)2 / 3 + 5

[問5] 2 つの整数データを読み込み,商と余りを出力するプログラムを書け.

[問6]千円札だけを使用でき,かつ,千円以下の切符を売る自動販売機がある.任意の料金( 10 円単位)の切符を買った(切符の料金を入力データとして読み込む)とき,その釣り銭を出力するプログラムを書け.ただし,釣り銭の総額だけでなく,必要な硬貨の枚数,例えば,500 円硬貨 1 枚,100 円硬貨 2 枚,50 円硬貨 1 枚,10 円硬貨 3 枚という結果も出力すること.
(ヒント)例えば,「 turi / 500 」という演算により,500 円硬貨の枚数が得られる

[問7]ある値段(入力)の商品を購入したとき,消費税( 3 %)を含めた実際の支払価格を以下の 3 つの場合について計算し,それぞれの値を出力するプログラムを書け.ただし,浮動小数点数を使用すると誤差が生じる可能性があるので,すべて整数を使用して計算せよ.
(1)1 円未満を切り捨てる
(2)1 円未満を切り上げる
(3)1 円未満を4捨5入する
(ヒント)例えば,切り捨ての演算は,「nedan * 103 / 100」という演算により可能

静岡理工科大学 菅沼ホーム 全体目次 演習解答例 付録 索引