Internet Start Page  TOP  
 Road of Developers
 
 


================================================================================

	Load of Developers C++ Language  ---- Vol. 5            I-ichirow Suzuki

================================================================================

Index

		Vol.5〜
		5 関数の基本
		6 関数の応用
		7 オブジェクトの基本型
		8 式の評価とポインタ



////////////////////////////////////////////////////////////////////////////////////////
5 関数の基本

##############################################################################
Q5-1 2つのint型引数x, yの大きい方の値を返却する関数
	int maxof(int x, int y) {    } を作成せよ

***********************************
View
	整数値を入力せよ:10
	整数値を入力せよ:20
	大きい方は20です

#######################################################
Answer

#include <iostream.h>

int maxof(int x, int y) {
	if ( x > y )
		return(x) ;
		return(y) ;
} // End maxof

int main (void) {

	int a, b ;

	cout << "整数値を入力せよ:" ;
	cin >> a ;

	cout << "整数値を入力せよ:" ;
	cin >> b ;

	cout << "大きい方は" << maxof(a, b) << "です\n" ;

	return(0) ;
} // End main();


関数呼び出し
main関数内で関数maxofを利用している部分に着目しましょう

	cout << "大きい方は" << maxof(a, b) << "です\n" ;

ここで( ) を関数呼び出し演算子(function call operator)と呼びmaxof(a, b)の部分を
関数呼び出し式(function call statement)と呼びます。
ちょうど
「関数maxofさん、a, bという2つの整数値を渡しますから大きい方の値を返してください」
と頼んでいると解釈できます。なお、呼び出す側が渡す引数であるa, bを実引数(argument)と
呼びます。

関数が呼び出されると、プログラムの流れは、その関数へと移ります。
そして、呼び出される側の関数maxofでは、受け取る側の引数x, yが生成されると同時に、実引
数によって初期化されます。

受け取る側の引数を仮引数(parameter)と言います。

関数maxofは呼び出し元に対して、2つの値の最大値を返却します。それに必要なのが
return文です。
return文は呼び出し元の関数にプログラムの流れを戻すと同時に、式の値を返却するものです。
なお返却する値のことを返却値(return value)と呼びます。その方は関数の先頭に書かれた型で
ありこれを返却型(return type)と言います。

従って、関数呼び出し式
	maxof(a, b)
において、a, bの値がそれぞれ10と20であれば、この式全体を評価した値はint型の20になります。


##############################################################################
Q5-2 3つのint型引数x, y, z の最大値を返却する関数
	int maxof(int x, int y, int z) {    } を作成せよ

***********************************
View
	整数値を入力せよ:10
	整数値を入力せよ:20
	整数値を入力せよ:30
	大きい方は30です

#######################################################
Answer

int maxof(int x, int y, int z) {

	int max = x ;

	if ( y > max ) max = y ;
	if ( z > max ) max = z ;

	return( max ) ;
} // End maxof


##############################################################################
Q5-4 3つのint型引数x, y, z の最小値を返却する関数
	int maxof(int x, int y, int z) {    } を作成せよ

***********************************
View
	整数値を入力せよ:10
	整数値を入力せよ:20
	整数値を入力せよ:30
	小さい方は10です

#######################################################
Answer

int minof(int x, int y, int z) {

	int min = x ;

	if ( y < min ) min  y ;
	if ( z < min ) min  z ;

	return( min ) ;
} // End maxof


##############################################################################
Q5-5 2つのint型引数x, yの平均値を返却する関数
	double aveof ( int x, int y ) {      }
を作成せよ

***********************************
View
	整数値を入力せよ:10
	整数値を入力せよ:20
	平均値はは15です

#######################################################
Answer

#include <iostream.h>

double aveof ( int x, int y ) {
	return ( double ( x + y ) / 2 )  ;
} // End aveof

int main (void) {

	int a, b ;

	cout << "整数値を入力せよ:" ;
	cin >> a ;

	cout << "整数値を入力せよ:" ;
	cin >> b ;

	cout << "平均値は" << aveof(a, b) << "です\n" ;

	return(0) ;
} // End main() ;


キャスト
double ( 式 )と言う形の式をキャスト式と呼びます。
もしキャストしていなければ39/2という正数同士の除算が先に行われ、小数点以下が切り捨てら
れる事になります。

	double( x + y ) → double ( 10 + 20 ) → 30.0 double型



##############################################################################
Q5-6 浮動小数点数xをn乗した値を返却する関数
	double power ( double x, int n ) {       }
を 作成せよ

***********************************
View
実数値を入力せよ:3.3
整数値を入力せよ:2
3.3の2乗は10.89です

#######################################################
Answer

#include <iostream.h>
double power( double x, int n) {

	double a = 1.0 ;

	if ( n > 0 )
		if (n > 0 )
			for ( int i = 0 ; i < n ; i++ )
				a *= x ;
		else
			for ( int i = 0 ; i > n ; i-- )
				a /= x ;

	return( a ) ;
} // End power() ;

int main (void ) {

	double a ;
	int b ;

	cout << "実数値を入力せよ:" ;
	cin >>a ;

	cout << "整数値を入力せよ:" ;
	cin >> b ;

	cout <<a <<"の" << b << "乗は" << power( a, b ) << "です\n" ;

	return(0) ;
} // End main() ;

値渡し
関数が受け取る仮引数は、呼び出し側の実引数によって初期化されますので仮引数と実引数の実
体は、全くの別物です。引数のやりとりは、その実体ではなく、値によって行われますのでこれを
引数の値渡し(pass by value)と呼びます。
このプログラムにおいて、仮引数nは実引数bによって初期化されるというだけで、それらは無関係
のものです。
この事は、関数power内において、仮引数nの値をどの様にいじくっても、実引数であるbの値には
何ら影響を与えないと言う事を意味します。


##############################################################################
Q5-7 引数x, yの値を入れ替える関数
	void swap( int& x, int& y ) {        }
を 作成せよ

***********************************
View
整数aの値を入力してください:10
整数bの値を入力してください: 20
整数aとbの値を入れ替えました。
aの値は 20です。
bの値は 10です。

#######################################################
Answer

#include <iostream.h>

void swap ( int& x, int& y ) {

	int temp = x ;

	x = y ;
	y = temp ;

} // End swap() ;

int main( void ) {

	int a ;
	int b ;

	cout << "整数aの値を入力してください:" ;
	cin >> a ;

	cout << "整数bの値を入力してください:" ;
	cin >> b ;

	swap(a, b) ;

	cout << "整数a と bの値を入れ替えました\n" ;
	cout << "aの値は" << a << "です\n" ;
	cout << "bの値は" << b << "です\n" ;

	return(0) ;
} // End main() ;


参照
このプログラムを理解する前にまず参照(reference)について理解しましょう。

	int abc ;
	int& ref = abc ;

この様に&を付け加えて宣言する事によって、refは通常のオブジェクトではなくて参照オブジェク
トとなり、この時「refはabcを参照する」事になります。

従ってabcとrefはオブジェクトを共有しますからabcと呼んでもrefと呼んでも同じ物を表す事にな
ります。
これを逆に考えると、変数abcにrefと言うエイリアスすなわち別名(あだ名)が付いた事になります

	int abc ;
	int& ref = abc ;

	ref = 5 ;

とrefに5を代入する事はabcへの代入を意味しますのでabcの値は5となります。

参照渡し
関数swap側の仮引数x, yに対して渡される実引数はaとbですから、これは丁度

	int& x = a ;
	int& y = b ;

と同じように初期化され、xはaのエイリアスとなり、yはbのエイリアスとなります。関数swapのx,
yの値の交換条件はmain関数のaとbの値の交換を意味しますから期待通りの結果を得る事が出来ます

void 関数
関数swapの返却型はvoidとなっています。
この様に値を返却しない関数をvoid関数と呼びます


##############################################################################
Q5-8 引数a, b, cを昇順に並べ替える関数
	void sort( int& a, int& b, int& c ) {            }
を作成せよ

***********************************
View
整数aの値を入力してください:10
整数bの値を入力してください:30
整数cの値を入力してください:20
整数a, b, cを昇順に並べ替えました
aの値は10です
bの値は20です
cの値は30です

#######################################################
Answer

#include <iostream.h>

void swap( int& x, int& y ) {

	int temp = x ;
	x = y ;
	y = temp ;
} // End swap

void sort( int& a, int& b, int& c ) {
	if ( a > b ) swap(a, b) ;
	if ( b > c ) swap(b, c) ;
	if ( a > b ) swap(a, b) ;
} // End sort

int main( void ) {

	int a, b, c ;

	cout << "整数aの値を入力してください:" ;
	cin >> a ;

	cout << "整数bの値を入力してください:" ;
	cin >> b ;

	cout << "整数cの値を入力してください:" ;
	cin >> c ;

	sort( a, b, c) ;

	cout << "整数a, b, cを昇順に並べ替えました\n" ;
	cout << "aの値は" << a << "です\n" ;
	cout << "bの値は" << b << "です\n" ;
	cout << "cの値は" << c << "です\n" ;

	return(0) ;
} // End main() ;


並べ替え
並べ替えを行う関数sortの本体には、3つのif文が並んでいるだけですが、これで3つの値の並べ
替えを行う事が出来ます。

	5	3	2		if ( a > b ) swap (a, b) ;
	3	5	2		if ( b > c ) swap (b, c) ;
	3	2	5		if ( a > b ) swap (a, b) ;
	2	3	5



##############################################################################
Q5-9 要素数がnであるint型配列xの最小値を返却する関数
	int minof ( int x[], int n ) {           }
を作成せよ
***********************************
View

a[0] = 	10
a[1] = 	12
a[2] = 	100
a[3] = 	95
a[4] = 	82
最小値:10
#######################################################
Answer

#include <iostream.h>

int minof ( int x [], int n ) {

	int min = x[0] ;

	for ( int i = 1 ; i < n ; i++ )
		if ( x[i] < min ) min = x[i] ;

	return( min ) ;
} // End minof

int main( void ) {

	const int max = 5 ;
	int a[max] ;

	for ( int i = 0 ; i < max ; i++ ) {
		cout << "a[" << i << "] = " ;
		cin >> a[i] ;
	} // End for

	cout << "最小値:" << minof(a, max) << '\n' ;

	return(0) ;
} // End main() ;


定数式
このプログラムでは配列のよう素数を

	const int max = 5 ;

と宣言しています。
この様にconstを付けて宣言された整数オブジェクトは定数式(constant expression)として扱われ
ます。従って5という定数に対してmaxという名前を与えているのです。
もし配列のよう素数を変えたいのであれば、この宣言を例えば、

	const int max = 10 ;

と変更すればよいわけです


////////////////////////////////////////////////////////////////////////////////////////
6 関数の応用

##############################################################################
Q6-1 2つの整数a, bの最小値、3tの整数a, b, cの最小値、要素数がnである整数配列xの最小値
を求める、以下に示す多重定義された関数群
	int minof(int a, int b) {                }
	int minof(int a, int b) {                }
	int minof(int x[], int n) {                 }
を作成せよ
***********************************
View

xの値を入力してください:10
yの値を入力してください:5
xとyの小さい方の値は5です

zの値を入力してください:8
x, y, zの最小値は5です

5個の値を入力してください:
a[0] = 10
a[1] = 20
a[2] = 50
a[3] = 30
1[4] = 5
配列aの要素の値の最小値は5です。
#######################################################
Answer

#include <iostream.h>

int minof(int a, int b) {
	return( a < b ? a : b ) ;
} // End minof

int minof(int a, int b, int c) {
	int min = a ;
	if ( b < min ) min = b ;
	if ( c < min ) min = c ;
	return( min ) ;
} // End minof

int minof ( int x[], int n ) {
	int min = x[0] ;
	for ( int i = 1 ; i < n ; i++ )
		if (x[i] < min )
			min = x[i] ;
	return(min) ;
} // End minof

int main ( void ) {
	int x, y, z ;
	cout << "xの値を入力してください:" ;
	cin >> x ;
	cout << "yの値を入力してください:" ;
	cin >> y ;
	cout << "x と yの小さい方の値は" << minof ( x, y ) << "です。\n\n" ;
	cout << "zの値を入力してください:" ;
	cin >> z ;
	cout << "x, y, zの最小値は" << minof(x, y, z) << "です。\n\n" ;

	const int max = 5 ;
	int a[max] ;

	cout << max << "個の値を入力してください:\n" ;

	for (int i = 0 ; i < max ; i++ ) {
		cout << "a[" << i << "] = " ;
		cin >> a[i] ;
	} // End for

	cout << "配列aの要素の値の最小値は" << minof ( a, max) << "です。\n" ;

	return(0) ;
} // End main() ;


関数の多重定義
引数の型や、その個数によって、呼び出すべき関数が明確である限り、同じ名前を持った中身の異
なる関数を定義する事が出来、これを関数の多重定義(over loading)と呼びます。
同一あるいは類似した操作を行う関数に対して、同じ名前を与える事によって、プログラマは関数
の名前の管理や使い分けの労力を少なくする事が出来ます。

条件演算子

	式1 ? 式2 : 式3

この式を評価すると、以下の様になります。
まず式1が評価されます。
その結果が	真であれば Trueである式2が実行されます
		偽であれば  Falseである式3が実行されます

	c = ( a > b ) ? a : b  ;

	aがbより大きければ式2であるaの値
	aがb未満であれば式3であるbの値

	となります。
	その値がcに代入されますから結局a, bの大きい方の値がcに代入される事になるのです。


##############################################################################
Q6-2
与えられた引数xの2乗値を返却するインライン関数3乗値を返却するインライン関数
	inline double square(double x) {           }
	inline double cube(double x) {           }
を作成せよ
***********************************
View

実数値を入力してください 4.2
4.2の2乗は17.64です
4.2の3乗は74.088です。
#######################################################
Answer

#include <iostream.h>

inline double square(double x) {
	return(x * x) ;
} // End double

inline double cube(double x) {
	return( x * x * x) ;
} // End double

int main(void) {
	double a ;

	dout << "実数値を入力してください:" ;
	cin >> a ;
	cout << a << "の2乗は" << square(a) << "です\n" ;
	cout << a << "の3乗は" << cube(a) << "です\n" ;

	return(0) ;
} // End main() ;


インライン関数
関数呼び出しが行われる際は、その呼び出し作業、引数や返却値の受け渡し作業などが生じる為、僅か
ながらプログラムの実行速度が落ち、一時的とはいえ、記憶領域も余分に消費します。
この様な欠点を持たない関数が、インライン関数(inline function)です。
関数定義に一言inline と付け加えるだけで、そのような問題点を持たない関数が作成されます。

	cout << a << "の2乗は" << square(a) << "です\n" ;

と
	cout << a << "の2乗は" << a * a << "です\n" ;

は同じことです。


##############################################################################
Q6-3
与えられた引数の2乗値を返却する関数テンプレート
	template <class Type> Type square(Type x) {              }
を作成せよ
***********************************
View

整数値を入力してください:5
5の2乗は25です。
実数値を入力してください:1.2
1.2の2乗は1.44です
#######################################################
Answer

#include <iostream.h>

template <class Type> Type square(Type x) {
	return( x * x ) ;
} // End Type square

int main(void) {
	int a ;
	cout << "整数値を入力してください:" ;
	cin >> a ;
	cout << a << "の2乗は" << square(a) << "です。\n" ;

	double b ;
	cout << "実数値を入力してください:" ;
	cin >> b ;
	cout << b << "の2乗は" << square(b) << "です。\n" ;

	return(0) ;
} // End main() ;


関数テンプレート
冒頭ににtemplate<.....>を加えて宣言されると、それは普通の関数ではなく、関数テンプレー
ト(funcion template)となり、その引数としてType(型)を受け取る事になります。
例えば、引数Typeにintを受け取ったとします。関数テンプレートsquare中のTypeをintに置き換え
ると(a)になります。
またdoubleを受け取ると(b)になります。
この様なコンパイラによって自動的に作られる関数をテンプレート関数(template function)と呼
びます。

(a)
	int square(int x) {
		return(x * x) ;
	} // End square

(b)
	double square(double x) {
		return(x * x) ;
	} // End square

この技術を利用する事によって、プログラマはそれぞれの型に対して似た様な関数を作成する手間
から解放される事になります。


##############################################################################
Q6-4
以下に示す関数は呼び出されるとどの様な出力を行うかを確認せよ
void func(void) {
		int ax = 0 ;
		static int sx = 0 ;

		cout << "ax : " << ax << " sx : " << sx << '\n' ;
		ax++ ;
		sx++ ;
} // End func


自動記憶寿命
関数func中のオブジェクトaxは、プログラムの流れが、その宣言を通過する際に作られ、その宣言
を囲むブロックの終端である}を通過する時に消滅します。
この様な性質を持つオブジェクトの記憶寿命を自動記憶寿命(automatic strage duration)と呼び
ます。
自動記憶寿命を持つオブジェクトはプログラムの流れが宣言を通過する際に、生成されると同時に
初期化が行われます。
従って関すfuncが呼び出されるたびに、axは0に初期化される事になります。

静的記憶寿命
オブジェクトsxはstatic付きで宣言されている為、プログラムの開始時、具体的にはmain関数が実
行される前の準備段階において作られて、プログラムの終了時まで存在し続けます。
この様な性質を持つオブジェクトの記憶寿命を、静的記憶寿命(static storage duration)と呼び
ます。
静的記憶寿命を持つオブジェクトはmain関数を実行する前の準備段階において初期化が行われます
から、プログラムの流れが、その宣言を通過したからと言って、再度初期化が行われることはあり
ません。


##############################################################################
Q6-5
以下に示すプログラムの実行結果を示せ

#include <iostream.h>

int x = 555 ;

void print_x(void) {
	cout << "6x = " << x << '\n' ;		// ---------x6
} // End print

int main (void) {

	cout << "1x = " << x << '\n' ;		// ---------x1

	int x = 333 ;

	cout << "2x = " << x << '\n' ;		// ---------x2

	for (int i = 0 ; i < 5 ; i ++ ) {
		int x = i * 100 ;
		cout << "3x = " << x << '\n' ;	// ---------x3
	} // End for

	cout << "4x = " << x << '\n' ;		// ---------x4
	cout << "::5x = " << ::x << '\n' ;	// ---------x5

	print_x() ;

	return(0) ;
} // End main() ;

********************************:
View

1x = 555
2x = 333
3x = 0
3x = 100
3x = 200
3x = 300
3x = 400
4x = 333
::5x = 555
6x = 555
Press any key to continue


ファイルスコープ
関数の外で宣言された名前は、その宣言された位置からファイルの最後まで有効となり、この様な
スコープをファイルスコープ(file scope)と呼びます。

ブロックスコープ
関数の中で宣言された名前は、その宣言を囲むブロックの終点である}まで有効となり、この様な
スコープをブロックスコープと呼びます。

スコープ解決演算子
::xと、オブジェクトの名前の前に、スコープ解決演算子(scope resolution operator)付けると、
関数の外で宣言されたxを表す事になります。


////////////////////////////////////////////////////////////////////////////////////////
7 オブジェクトの基本形

##############################################################################
Q7-1
各整数型の表現範囲を表示するプログラムを作成せよ。

***********************************
View

char		:	0〜255
short int 	:	-32768〜32767
int		:	-32768〜32767
long int 	:	-2147483648〜2147483647
#######################################################
Answer

#include <limits.h>
#include <iostream.h>
int main(void) {
	cout << "char 		: " << CHAR_MIN  << "-" << CHAR_MAX  << '\n' ;
	cout << "short int	: " << SHORT_MIN << "-" << SHORT_MAX << '\n' ;
	cout << "int	 	: " << INT_MIN   << "-" << INT_MAX   << '\n' ;
	cout << "long int 	: " << LONG_MIN  << "-" << LONG_MAX  << '\n' ;

	return(0) ;
} // End main() ;


算術型
int型やdouble 型の変数や定数に対しては加算や減算などの算術演算を施す事が出来ますから、こ
れらの型を算術型(arithmetic type)と呼びます。
算術型はインテグラル型(integral type)と浮動小数点型(floating type)に大別されます。

インテグラル型
インテグラル型には整数型(integer type)と列挙型(enumeration type)の2つがあります。

整数型
整数型には負の数、0,正の数を表現する浮動付き整数型(signed integer type)と非負の数のみ
を表現する符号なし整数型(ensigned integer type)とに大別され、さらにその表現が可能な数値
の範囲によってchar, short int, int long int の4種類に分けられます。

int型の使い分け
一般にint型はプログラムが実行される環境において、最も扱い易く高速な演算が可能な型です。
特別に大きな数値を扱う必要がない限りは、なるべくint型やshort型を使うのが賢明です。

列挙型
プログラムのenum MENU { Termination, Dog, Cat, Monkey, Invalid } ;
を列挙子(enumerator)と呼びます。各列挙子には、先頭から純に0, 1, 2, .....と値が与えられ
ます。
この宣言によってMENUは0, 1, 2, 3, 4 という値をとりうる型となります。
この様に選択されたメニューに応じて、処理を択一的に選択するプログラムをメニュードリブンプ
ログラム(menu-doriven program)と呼びます。

#include <iostream.h>
enum menu { Termination, Dog, Cat, Monkey, Invalid } ;

void dog(void) {
	cout << "わんわん!\n" ;
} // End dog() ;

void cat(void) {
	cout << "にゃんにゃん\n" ;
} // End cat() ;

void monkey(void) {
	cout << "きっきっ\n" ;
} // End monkey() ;

menu SelectMenu(void) {
	int ch ;
	do {
		cout << "(0) End\n" ;
		cout << "(1) Dog\n" ;
		cout << "(2) Cat\n" ;
		cout << "(3) Monkey\n" ;
		cin >> ch ;
	} while (ch < Termination || ch >= Invalid) ;

	return(menu(ch)) ;
} // End SelectMenu() ;

int main(void) {
	menu menu ;
	do {
		switch (menu = SelectMenu()) {
			case Dog : dog() ;	break ;
			case Cat : cat() ;	break ;
			case Monkey : monkey() ;	break ;
		} // End switch
	} while (menu !=Termination) ;

	return(0) ;
} // End main() ;


拡張性
メニューを表示・選択する関数SelectMenuの条件判定に着目しましょう。
以下に示すメニューとして0, 1, 2, 3以外の数が入力された時に再入力させる為の繰り返しを行う
為のdo文です

	do {
		cout << "(0) End\n" ;
		cout << "(1) Dog\n" ;
		cout << "(2) Cat\n" ;
		cout << "(3) Monkey\n" ;
		cin >> ch ;
	} while (ch < Termination || ch >= Invalid) ;

ここで、実際のメニュー処理に対応している訳ではない、一見すると無意味である列挙型Invalid(
無効なという意味)が使われています。
もしこの列挙子が用意されていないとすると、この条件判定は、次のようになります。

	} while (ch < Termination || ch >= Monkey) ;

ここで4番目のメニューとしてMouseという項目が追加され、それに伴ってmenuの宣言が

	enum menu { Termination, Dog, Cat, Monkey, Mouse } ;

	} while (ch < Termination || ch >= Mouse) ;

と変更しなければなりません。
すなわちメニューを追加するたびに条件判定を変更しないといけないのです。Invalidが実に有効
に機能していることがわかりましたか?


////////////////////////////////////////////////////////////////////////////////////////
8 式の評価とポインタ

##############################################################################
Q8-1

オブジェクトaがdouble型でオブジェクトbがint型であるとする。
代入式 a = b = 1.5によってa とb の値がどの様になるかをプログラムせよ。
***********************************
View

	a = 1
	b = 1
#######################################################
Answer

#include <iostream.h>
int main (void) {
		double a ;
		int b ;

		a = b = 1.5 ;
		cout << "a = " << a << '\n' ;
		cout << "b = " << b << '\n' ;

		return(0) ;
	} // End main() ;


代入式の評価
代入式は代入後の左オペランドの型と値として評価されますから
式b = 1.5はint型の1と評価されます。個の値がaに代入されますので結局aは1.0となります。

インクリメント演算子・デクリメント演算子
インクリメント演算子++及びデクリメント演算子--にはオペランドの前に適用される前置インクリ
メント演算子(prefix increment operator)・前置デクリメント演算子(prefix decrement operator
)とオペランドの後ろに適用される後置インクリメント演算子(postfix increment)・後置デクリメ
ント演算子(postfix decrement operator)とがあります

式を評価した際に得られる値は、前置形式の演算子が適用されている場合は、インクリメントある
いはデクリメント後の値となるのに対し、後置形式の演算子が適用されている場合はインクリメン
トあるいはデクリメント前の値となります。

y = x++ ;	式x++の評価値であるxの値をyに代入後xをインクリメント
y = ++x ;	xをインクリメント後、式x++の評価値(インクリメント後のxの値)をyに代入


##############################################################################
Q8-2

yearで表された西暦年が閏年であれば1をそうでなければ0を返却する関数

	int isleap(int year) {           }

を作成せよ
閏年は4で割り切れる年のことであるが、400で割り切れないが100で割り切れる年はこの限りでは
ない。
***********************************
View

年を西暦で入力してください:1997
1997年は閏年ではありません。

年を西暦で入力してください:1992
1992年は閏年ではありません。
#######################################################
Answer

#include <iostream.h>
int isleap(int year) {
		return(year %4 == 0 && year % 100 != 0 || year % 400 == 0) ;
	} // End isleap() ;

int main(vdoi) {
		int year ;
		cout << "年を西暦で入力してください:" ;
		cin >> year ;

		if(isleap(year))
			cout << year << "年は閏年です\n" ;
		else
			cout << year << "年は閏年ではありません\n" ;

		return(0) ;
} // End main() ;

等値演算子
等値演算子である==と!=は2つのオペランドを比較した結果、0または1の値を生成する演算子です
から、例えばyearが1600の時は関数isleapにおけるreturn文中の()内の式は閏年を示す1となりま
す。

##############################################################################
Q8-3

for文を用いてint型の変数i, jをそれぞれ同時に0から4までインクリメントしていきそれらの値を
表示するプログラムを作成せよ。カンマ演算子を用いること
***********************************
View

i = 0 j = 0
i = 1 j = 1
i = 2 j = 2
i = 3 j = 3
i = 4 j = 4
#######################################################
Answer

#include <iostream.h>
int main(void) {
	int i, j ;
	for (i = 0, j = 0 ; i < 5 ; i++, j++)
		cout << "i = " << i << " j = " << j << '\n' ;

	return(0) ;
} // End main() ;

カンマ演算子
カンマ演算子(comma operator)を用いた式です
	op1, op2
を評価すると、式op1とop2が順に評価されていき最終的には後者の型と値となります。
for文のparameterもカンマ演算子によって区切られていることがわかります。
カンマ演算子を用いることによって1つの式であるべきところに2つの式をおいています。


優先度(precedence)と結合規則(associativity)
乗除を行う*や/が加減を行う+ や-よりも優先度が高いのは我々が日常生活で使用する数学での規
則と同じです。

結合規則については2つのオペランドを要求する2項演算子を○とした場合a○b○c○を

	( a ○ b ) ○ c	左結合
	a ○ ( b ○ c ) 右結合

とします。
	5 - 3 - 1 →	(5 - 3) - 1	// 左結合

	a = b = 1 →	a = (b = 1)	// 右結合

となります。四則演算は左結合です。代入演算子は右結合となります。


##############################################################################
Q8-4

int型のオブジェクトとdouble型のオブジェクトを定義して、それらのアドレスを表示するプログ
ラムを作成せよ。
***********************************
View

xのアドレス0x0065FDF4
yのアドレス0x0065FDEC

#######################################################
Answer

#include <iostream.h>
int main(void) {
	int x ;
	double y ;
	cout << "xのアドレス" << &x << '\n' ;
	cout << "yのアドレス" << &y << '\n' ;

	return(0) ;
} // End main() ;


オブジェクトとアドレス
オブジェクトが記憶領域空間上の「どこに」格納されているかを表すのがアドレス(address)です。
丁度住所での○○番地のような物です。

アドレス演算子
アドレス演算子(address operator)と呼ばれる&演算子をオブジェクトに適用するとそのオブジェ
クトのアドレスを得る事が出来ます。


##############################################################################
Q8-5

int型の配列とdouble型の配列のオブジェクトを用意して、それらの各要素のアドレスを表示して
、実行結果に対する考察を行いなさい
なお配列xの2番目の要素x[1]のアドレスは&x[1]で取り出すことが出来ます。
***********************************
View

&x[0] = 0x0065FDE4 : &y[0] = 0x0065FDC0
&x[1] = 0x0065FDE8 : &y[1] = 0x0065FDC8
&x[2] = 0x0065FDEC : &y[2] = 0x0065FDD0
&x[3] = 0x0065FDF0 : &y[3] = 0x0065FDD8
Press any key to continue

#######################################################
Answer

#include <iostream.h>
int main(void) {
	const int max = 4 ;
	int x[max] ;
	double y [max] ;

	for (int i = 0 ; i < max ; i++) {
		cout << "&x[" << i << "] = " << &x[i] << " : " ;
		cout << "&y[" << i << "] = " << &y[i] << '\n' ;
	} // End for

	return(0) ;
} // End main() ;


配列の要素のアドレス
ここに示す事項例はsizeof(int)が2であり、sizeof(double)が8である環境での物です。
配列の各要素のアドレス値が先頭から順にsizeof(要素の型)ずつ増えていくことが実行例からもわ
かります。


##############################################################################
Q8-6

2つのint型のオブジェクトと1つのintへのポインタ型でもあるオブジェクトを用意し、それらに
対して適当な値の代入等を行う事によって、ポインタ・アドレス演算子・間接演算子を応用したプ
ログラムを作成せよ
***********************************
View

x : 100 (&x : 0x0064FDF0番地)
y : 200 (&y : 0x0064FDEC番地)

ptr ← &x
ptr : 0x0064FDF0番地
*ptr : 100

ptr ← &y
ptr : 0x0064FDEC番地
*ptr : 200

ptr ← 300
ptr : 0x0064FDEC番地
*ptr : 300
x : 100 (&x * 0x0064FDF0番地
y : 300 (&y * 0x0064FDEC番地

#######################################################
Answer

#include <iostream.h>
int main(void) {
	int x = 100 ;
	int y = 200 ;
	int* ptr = &x ;

	cout << "x : " << x << " (&x : " << &x << "番地)\n" ;
	cout << "y : " << y << " (&y : " << &y << "番地)\n\n" ;

	cout << "ptr ← &x\n" ;
	cout << "ptr : " << ptr << "番地\n" ;
	cout << "*ptr : " << *ptr << "\n\n" ;

	ptr = &y ;

	cout << "ptr ← &y\n" ;
	cout << "ptr : " << ptr << "番地\n" ;
	cout << "*ptr : " << *ptr << "\n\n" ;

	*ptr = 300 ;

	cout << "*ptr ← 300\n" ;
	cout << "ptr : " << ptr << "番地\n" ;
	cout << "*ptr : " << *ptr << '\n' ;
	cout << "x : " << x << " (&x * " << &x << "番地\n" ;
	cout << "y : " << y << " (&y * " << &y << "番地\n" ;

	return(0) ;
} // End main() ;

***********************************


ポインタ
以下に示すのがポインタの宣言です。

	int* ptr = &x ;

オブジェクトptrの方はintではなくint*となっています。
このような方をintへのポインタ型といいます。

int型のオブジェクト
その値として整数を格納する箱

intへのポインタ型のオブジェクト
その値として整数を格納する箱のアドレスを格納する箱

ポインタであるptrはいわゆる整数を格納するのではなく、整数が格納されているオブジェクトのアド
レスを格納することが一般の整数オブジェクトとの大きな違いです。

下の図はxが格納されている値が「100」であり、そのアドレスが「500番地」である場合を示していま
す。

	x 		ptr
	100		500番地
	int x = 100 ;	int* ptr = &x ;

ptrにはその初期値として&xが与えられていますからptrの中身としてxのアドレスである「500番地
」という値が角のされていることが解ります。
このとき「ptrはxを指す」といいます

ptrの方は「intへのポインタ」ですから、それに対する初期化子も同じ方であるはずです。
従って
	int* ptr = &x ;

において&xの方は「intへのポインタ型」と言う事になります。
&演算子はアドレスを得るための演算子であると説明しましたが、より厳密にはポインタを生成する演
算子なのです。
式&xはxを指すポインタであり、具体的な値としてxのアドレスを持ちます。
従って、最初にptrを表示する

	cout << "ptr : " << ptr << "番地\n" ;

ではptrに格納されていつ値、すなわちxの番地が表示されることになります。



##############################################################################
Q8-7
引数x, yが指す値を入れ替える関数
	void swap(int* x, int* y) {                }
を作成せよ。
***********************************
View

整数aの値を入力してください:100
整数bの値を入力してください:200
整数aとbの値を入れ替えました
aの値は200です
bの値は100です
#######################################################
Answer

#include <iostream.h>
void swap(int* x, int* y) {
	int temp = *x ;
	*x = *y ;
	*y = temp ;
} // End swap() ;

int main(void) {
	int a ;
	int b ;

	cout << "整数aの値を入力してください:" ;
	cin >> a ;
	cout << "整数bの値を入力してください:" ;
	cin >> b ;

	swap(&a, &b) ;

	cout <<"整数aとbの値を入れ替えました\n" ;
	cout <<"aの値は" << a << "です\n" ;
	cout <<"bの値は" << b << "です\n" ;

	return(0) ;
} // End main() ;

引数としてのポインタ
C++においてポインタを多用する局面の1つが関数間の引数の受け渡しです。

	swap(&a, &b) ;

と、aへのポインタ、bへのポインタを渡しています。
呼び出される側の関数swapはそれらを仮引数であるxとyに受け取ります。
関数の仮引数はちょうど実引数で「初期化される」かのように受け取るのです。
すなわち関数swap内では

	int* x = &a ;
	int* y = &b ;

と言った感じで引数が初期化されます。
aへのポインタをxにbへのポインタをyに受け取った関数swapはそれらのポインタに対して*演算子を適
用する事によってオリジナルのaやbを間接的に扱う事が出来ます。
と言うのも*xはaのエイリアスであり*yはbのエイリアスなのですから
このように関数に対してオブジェクトの値の変更を頼みたいのであれば、それへのポインタを引数とし
て渡します。

	ポインタを渡しますから、それが指すオブジェクトに対して処理をしてください。

と依頼するのです。
受け取る側はそのポインタに*演算子を適用する事によって、そのポインタの指すオブジェクトを間接
的に扱えるのです。


/////////////////////////////////////////////////////////////////////////////////////////

たまに今まででてきた単語を思い出して復習しましょう!
わからない物は以前のテキスト内容を探して確認しましょう。

ヘッダ	header
#include include
iostream.h	In Out Stream Header
変数	object
型	type
宣言文	declaration statement
<< 挿入演算子	insertion operator
>> 抽出演算子	extraction operator
cout 	C out
cin 	C in
文字列リテラル	string literal
+	binary + operator
-	binary - operator
*	binary * operator
/	binary / operator
%	binary % operator
sizeof演算子	sizeof operator
定数	constant
文字定数	character constant
整数定数	integer constant
浮動小数点数	floating constant
コメント	comment
代入演算子	assignment operator
main関数	main function
if文	if statement
関係演算子	relational operator
等値演算子	equality operator
論理否定演算子	logical negation operator
論理and演算子	logical And operator
論理or演算子	logical OR operator
switch文	switch statement
break文	break statement
while文	while statement
初期化子	initializer
インクリメント演算子	increment operator
デクリメント演算子	decrement operator
do文	do statement
for文	for statement
配列	array
添え字	subscript
添え字演算子	subscript operator
複合代入演算子	compound assignment operator
単純代入演算子	simple assignment operator
識別子	identifier
\a	alert
\n	new line
エスケープシーケンス	escape sequence
処理子	manipulator
関数定義	function definition
関数頭部	function header
関数本体	function body
関数呼び出し演算子	function call operator
関数呼び出し式	functioncall statement
実引数	argument
仮引数	parameter
return文	return statement
返却値	return value
返却型	return type
キャスト式	cast expression
キャスト演算子	cast operator
値渡し	pass by value
参照	reference
参照渡し	pass by reference
定数式		constant expression
多重定義	overloading
条件演算子	conditional operator
条件式	conditional expresstion
インライン関数	inline function
関数テンプレート	function template
テンプレート関数	template function
自動記憶寿命	automatic strage duration
静的記憶寿命	static storage duration
ファイルスコープ	file scope
スコープ演算子	scope resolution operator
定義	definition
内部リンケージ	internal linkage
外部リンケージ	external linkage
算術型	arithmetic type
インテグラル型	integral type
浮動小数点型	floating type
整数型	inteter type
列挙型	enumeration type
符号付き整数型	signed integer type
符号なし整数型	unsigned integer type
文字型	character type
ドリブンプログラム	menu-driven program
列挙子	enumerator
前置インクリメント演算子	prefix increment operator
後置インクリメント演算子	postfix increment operator
前置デクリメント演算子		prefix decrement operator
後置デクリメント演算子		postfix decrement operator
カンマ演算子	comma operator
優先度	precedence
結合規則	associativity
アドレス	address
アドレス演算子	address operator



To be continue.... To Vol.6

==============================================================================


インターネットスタートページ 鈴木維一郎 石橋三重子
        
         
               
                   

©2000 kg-group Inc.