Powered by SmartDoc

ソフトウェア概論A/B (2017/05/26)
Ver. 1.0

2017年5月26日
栗野 俊一
kurino@math.cst.nihon-u.ac.jp
http://edu-gw2.math.cst.nihon-u.ac.jp/~kurino/2017/soft/soft.html
ソフトウェア概論 A/B2017年5月26日 の資料

目次

講義資料

当日の OHP 資料

Download

講義で利用するサンプルプログラム

Download : sample-001.c

sample-001.c
/*
 * 2017/05/26 sample-001.c
 */

#include <stdio.h>
#include <string.h>

/*
 *	myPrintf (No.1)
 *
 *  myPrintf の考え方
 *
 *	<意味を考える>
 *	「文字列」を全部を出力
 *		=	文字列の先頭の文字を出力 + 残りの文字列を出力
 *      =	「文字列」の先頭の文字を出力 + 「残りの文字列」を全部を出力(再帰)
 *
 *	<再帰関数の形にする>
 *		myPrintf ( 「文字列」 )
 *		=	putchar ( 「文字列」の先頭 ) + myPrintf ( 「文字列」の残り )
 *		=	putchar ( *「文字列」 ) + myPrintf ( 「文字列」+ 1 )
 *
 *	<再帰を利用する場合は「終了の場合」を作る>
 *		myPrintf ( 「文字列」 )
 *		=	if ( 「文字列」が空文字列の時 ) {
 *				なにもしない
 *			} else {
 *				putchar ( *「文字列」 );
 * 				myPrintf ( 「文字列」+ 1 );
 *			}
 *
 */

void myPrintf ( char *string ) {

	if ( !strcmp ( string, "" ) ) {	/* 空文字列なら..(終了条件) */
		/* 何もしなくてよい */
	} else {						/* まだ出力する文字があれば */
		putchar ( *string );		/* 先頭の文字を出力する */
		myPrintf ( string + 1 );	/* 残りの文字列を出力する */
	}
}

/*
 * main
 */

int main ( void ) {

  myPrintf ( "abcde\n" );
  myPrintf ( "xyz\n" );

  return 0;
}
sample-001.c の実行結果
$ ./sample-001.exe
abcde
xyz
$ 

Download : sample-002.c

sample-002.c
/*
 * 2017/05/26 sample-002.c
 */

#include <stdio.h>
#include <string.h>

/*
 *	myPrintf (No.2)
 *
 *	終了条件を EOS ( '\0' : End Of String) で判定
 */

void myPrintf ( char *string ) {

	if ( *string == '\0' ) {		/* 先頭が空文字('\0')なら空文字列 */
									/* 文字の比較は 「==」で行う */
		/* 何もしなくてよい */
	} else {						/* まだ出力する文字があれば */
		putchar ( *string );		/* 先頭の文字を出力する */
		myPrintf ( string + 1 );	/* 残りの文字列を出力する */
	}
}

/*
 * main
 */

int main ( void ) {

  myPrintf ( "abcde\n" );
  myPrintf ( "xyz\n" );

  return 0;
}
sample-002.c の実行結果
$ ./sample-002.exe
abcde
xyz
$ 

Download : sample-003-01.c

sample-003-01.c
/*
 * CDATE sample-003-01.c
 */

#include <stdio.h>	/* putchar の為に必要 */

/*
 *	println : 文字列を出力するついでに最後に改行を付加する
 */

void println ( char *string ) {

	if ( *string == '\0' ) {
		putchar ( '\n' );			/* 最後に改行を出力する */
	} else {
		putchar ( *string );
		println ( string + 1 );
	}
}

Download : sample-003.c

sample-003.c
/*
 * 2017/05/26 sample-003.c
 */

#include <stdio.h>

/*
 * println の extern 宣言
 */

extern void println ( char *string );	/* 関数の頭部の前に extern 後に ; */

/*
 * main
 */

int main ( void ) {

  println ( "abcde" );	/* 改行(\n)が不要になった */
  println ( "xyz" );

  return 0;
}
sample-003.c の実行結果
$ ./sample-003.exe
abcde
xyz
$ 

Download : sample-004-01.c

sample-004-01.c
/*
 * 2017/05/26 sample-004-01.c
 */

/* もはや printf も putchar も使わないので #include <stdio.h> も不要 */

/*
 * println の extern 宣言
 */

extern void println ( char *string );

/*
 *	triangle again
 *
 */

void triangle ( char *string ) {

	if ( *string == '\0' ) {
		/* 何もしなくてよい */
	} else {
		println ( string );			/* println を利用する */
		triangle ( string + 1 );
	}
}

Download : sample-004.c

sample-004.c
/*
 * 2017/05/26 sample-004.c
 */

/*
 * triangle, println の extern 宣言
 */

extern void println ( char *string );
extern void triangle ( char *string );

/*
 * main
 */

int main ( void ) {

	triangle ( "****" );		/* 間接的に println を使うので、改行が不要 */
	println ( "" );				/* 空行を出力する */
	triangle ( "*******" );

	return 0;
}
sample-004.c の実行結果
$ ./sample-004.exe
****
***
**
*

*******
******
*****
****
***
**
*
$ 

Download : sample-005-01.c

sample-005-01.c
/*
 * 2017/05/26 sample-005-01.c
 */

/*
 * println の extern 宣言
 */

extern void println ( char *string );

/*
 *	rtriangle	-- triangle の「逆」版
 */

void rtriangle ( char *string ) {

	if ( *string == '\0' ) {
		/* 何もしなくてよい */
	} else {
		rtriangle ( string + 1 );	/* 最初に残りをやって.. */
		println ( string );			/* 最後に先頭を処理する */
	}
}

Download : sample-005.c

sample-005.c
/*
 * 2017/05/26 sample-005.c
 */

/*
 * rtriangle, println の extern 宣言
 */

extern void println ( char *string );
extern void triangle ( char *string );
extern void rtriangle ( char *string );

/*
 * main
 */

int main ( void ) {

	triangle ( "****" );
	rtriangle ( "*******" );

	return 0;
}
sample-005.c の実行結果
$ ./sample-005.exe
****
***
**
*
*
**
***
****
*****
******
*******
$ 

Download : sample-006-01.c

sample-006-01.c
/*
 * 2017/05/26 sample-006-01.c
 */

/*
 * extern 宣言
 */

extern println ( char *string );

/*
 * string の文字列の長さ回 「Hello World\n」を表示する
 */

void nhello ( char *string ) {

	if ( *string == '\0' ) {		/* 既に全てすんだ */
		/* 何もしなくてよい */
	} else {						/* まだ、やる事がある */
		println ( "Hello, World" );	/* 取り敢えず、一度出力 */
		nhello ( string + 1 );		/* 文字列を短くして、残りを行う (再帰) */
	}
}

Download : sample-006.c

sample-006.c
/*
 * 2017/05/26 sample-006.c
 */

/*
 * extern 宣言
 */

extern println ( char *string );
extern nhello ( char *string );

/*
 * n 回数の繰返し
 */

int main ( void ) {

	 println ( " 3 回 Hello : " );
	 nhello ( "***" );				/* 長さ 3 の文字列を指定 */
	 println ( " 5 回 Hello : " );
	 nhello ( "12345" );			/* 長さ 5 の文字列を指定 */

	 return 0;
}
sample-006.c の実行結果
$ ./sample-006.exe
 3 回 Hello : 
Hello, World
Hello, World
Hello, World
 5 回 Hello : 
Hello, World
Hello, World
Hello, World
Hello, World
Hello, World
$ 

Download : sample-007-01.c

sample-007-01.c
/*
 * 2017/05/26 sample-007-01.c
 */

/*
 * extern 宣言
 */

extern println ( char *string );

/*
 * string の文字列の長さ回 message を出力する
 *		基本は nhello と同じだが、出力する message が異なる
 */

void nprintln ( char *string, char *message ) {

	if ( *string == '\0' ) {		/* 既に全てすんだ */
		/* 何もしなくてよい */
	} else {						/* まだ、やる事がある */
		println ( message );		/* 取り敢えず、一度出力 */
		nprintln ( string + 1, message );
	}
}

Download : sample-007.c

sample-007.c
/*
 * 2017/05/26 sample-007.c
 */

/*
 * extern 宣言
 */

extern void nprintln ( char *string, char *message );

/*
 * n 回数の繰返し
 */

int main ( void ) {

	 println ( " 3 回「Hello」: " );
	 nprintln ( "***", "Hello" );

	 println ( " 5 回「こんにちは」: " );
	 nprintln ( "12345", "こんにちは" );

	 return 0;
}
sample-007.c の実行結果
$ ./sample-007.exe
 3 回「Hello」: 
Hello
Hello
Hello
 5 回「こんにちは」: 
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
$ 

Download : sample-008-01.c

sample-008-01.c
/*
 * 2017/05/26 sample-008-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 * extern 宣言
 */

extern println ( char *string );

/*
 * itemize ( char *item, char *message )
 *	個々の文字の前にマークを付ける
 */

void itemize ( char *item, char *message ) {

	if ( *item == '\0' ) {		/* 既に全てすんだ */
		/* 何もしなくてよい */
	} else {						/* まだ、やる事がある */
		putchar ( *item );		/* 項目 */
		putchar ( ' ' );			/* 一文字空けて */
		println ( message );		/* 一行出力 */
		itemize ( item + 1, message );
	}
}

Download : sample-008.c

sample-008.c
/*
 * 2017/05/26 sample-008.c
 */

/*
 * extern 宣言
 */

extern void itemize ( char *item, char *message );

/*
 * n 回数の繰返し
 */

int main ( void ) {

	 println ( " 3 回「Hello」: " );
	 itemize ( "***", "Hello" );

	 println ( " 5 回「こんにちは」: " );
	 itemize ( "12345", "こんにちは" );

	 return 0;
}
sample-008.c の実行結果
$ ./sample-008.exe
 3 回「Hello」: 
* Hello
* Hello
* Hello
 5 回「こんにちは」: 
1 こんにちは
2 こんにちは
3 こんにちは
4 こんにちは
5 こんにちは
$ 

Download : sample-009-01.c

sample-009-01.c
/*
 * 2017/05/26 sample-009-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 * extern 宣言
 */

extern println ( char *string );
extern nprintln ( char *string, char *message );

/*
 * mnprintln ( char *m, char *n, char *message )
 *	m * n 回数 message を出力する
 */

void mnprintln ( char *m, char *n, char *message ) {

	if ( *m == '\0' ) {
	} else {
		nprintln ( n, message );			/* n 回数は nprintln にお任せ */
		mnprintln ( m + 1, n, message );
	}
}

Download : sample-009.c

sample-009.c
/*
 * 2017/05/26 sample-009.c
 */

/*
 * extern 宣言
 */

extern void mnprintln ( char *m, char *n, char *message );

/*
 * n 回数の繰返し
 */

int main ( void ) {

	 println ( " 3 x 5 回「Hello」: " );
	 mnprintln ( "***", "*****", "Hello" );

	 println ( " 4 x 4 回「こんにちは」: " );
	 mnprintln ( "1234", "1234", "こんにちは" );

	 return 0;
}
sample-009.c の実行結果
$ ./sample-009.exe
 3 x 5 回「Hello」: 
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
 4 x 4 回「こんにちは」: 
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
$ 

Download : sample-010-01.c

sample-010-01.c
/*
 * 2017/05/26 sample-010-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 *	nprinttail
 *	n 回数 message を出力するが、行末を変更する。
 */

void nprinttail ( char *tail, char *message ) {

	if ( *tail == '\0' ) {
	} else {
		printf ( message );
		if ( *tail == '\n' )	{	/* 改行の時のみ */
			putchar ( '\n' );		/* 改行する */
		} else {					/* それ以外は */
	  		/* 何もしない */
		}

		nprinttail ( tail + 1, message );
	}
}

Download : sample-010.c

sample-010.c
/*
 * 2017/05/26 sample-010.c
 */

/*
 * extern 宣言
 */

extern void println ( char *message );
extern void nprinttail ( char *tail, char *message );

/*
 * n 回数の繰返し
 */

int main ( void ) {

	 println ( "毎回改行「Hello」: " );
	 nprinttail ( "\n\n\n", "Hello" );

	 println ( "3 回目, 7 回目だけ改行「Hello」: " );
	 nprinttail ( "12\n456\n", "Hello" );

	 return 0;
}
sample-010.c の実行結果
$ ./sample-010.exe
毎回改行「Hello」: 
Hello
Hello
Hello
3 回目, 7 回目だけ改行「Hello」: 
HelloHelloHello
HelloHelloHelloHello
$ 

Download : sample-011.c

sample-011.c
/*
 * 2017/05/26 sample-011.c
 */

#include <stdio.h>

/*
 * 文字の扱い
 */

int main ( void ) {

	printf ( "abc\n" );		/* 「abc(改行)」とでる */
	printf ( "abc\n" + 1 );	/* 「bc(改行)」とでる ( 1 を加えると短くなる ) */

	putchar ( 'A' );		/* 「A」とでる */
	putchar ( '\n' );		/* 「(改行)」とでる */

	putchar ( 'A' + 1 );	/* 文字に 1 を加えると ? */
	putchar ( '\n' );		/* 「(改行)」とでる */

	return 0;
}
sample-011.c の実行結果
$ ./sample-011.exe
abc
bc
A
B
$ 

Download : sample-012-01.c

sample-012-01.c
/*
 * 2017/05/26 sample-012-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 * printcharln ( char ch )
 *	文字を出力して改行する
 */

void printcharln ( char ch ) {

	 putchar ( ch );	/* 指定された文字を出力 */
	 putchar ( '\n' );	/* その後に改行 */

}

Download : sample-012.c

sample-012.c
/*
 * 2017/05/26 sample-012.c
 */

/*
 * extern 宣言
 */

extern void printcharln ( char ch );

/*
 * 文字の扱い(2)
 */

int main ( void ) {

	printcharln ( 'A' + 1 );		/* 'B' になった */
	printcharln ( 'B' + 1 );		/* 'C' になる */
	printcharln ( 'A' + 1 + 1 );	/* これも 'C' になる */

	printcharln ( 'A' + 0 );		/* これはもちろん 'A' */
	printcharln ( 'A' + 10 );		/* 'A', 'B', .., 'J', 'K' になるはず */

	printcharln ( 'A' + 25 );		/* 'Z' !! */

	printcharln ( 'Z' + 1 );		/* ??? */

	return 0;
}
sample-012.c の実行結果
$ ./sample-012.exe
B
C
C
A
K
Z
[
$ 

Download : sample-013-01.c

sample-013-01.c
/*
 * 2017/05/26 sample-013-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 * nprintcharln ( char ch )
 *	文字を連続 n 個だけ、出力する
 */

void nprintcharln ( char *n, char ch ) {

	 if ( *n == '\0' ) {
		 putchar ( '\n' );	/* 改行 */
	 } else {
		 putchar ( ch );	/* 指定された文字を出力 */
		 nprintcharln ( n + 1, ch + 1 );
	 }
}

Download : sample-013.c

sample-013.c
/*
 * 2017/05/26 sample-013.c
 */

/*
 * extern 宣言
 */

extern void nprintcharln ( char *n, char ch );
extern void printcharln ( char ch );
extern void println ( char *string );

/*
 * 文字の扱い(3)
 */

int main ( void ) {

	println ( "'A' から 10 個 :" );
	nprintcharln ( "1234567890", 'A' );

	println ( "'U' から 10 個 :" );
	nprintcharln ( "1234567890", 'U' );

	println ( "'k' から 10 個 :" );
	nprintcharln ( "1234567890", 'k' );

	println ( "'0' から 10 個 :" );
	nprintcharln ( "1234567890", '0' );

	println ( "'9' + 1 は.. :" );
	printcharln ( '9' + 1 );		/* 残念ながら "10" ではない */

	return 0;
}
sample-013.c の実行結果
$ ./sample-013.exe
'A' から 10 個 :
ABCDEFGHIJ
'U' から 10 個 :
UVWXYZ[\]^
'k' から 10 個 :
klmnopqrst
'0' から 10 個 :
0123456789
'9' + 1 は.. :
:
$ 

Download : sample-014-01.c

sample-014-01.c
/*
 * 2017/05/26 sample-014-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 * printonedigit ( int n )
 *	一桁の整数を出力する
 */

void printonedigit ( int n ) {

	 putchar ( '0' + n );	/* n が 0 〜 9 の場合だけ、正く動く */
}

/*
 * printonedigitln ( int n )
 *	一桁の整数を出力して改行する
 */

void printonedigitln ( int n ) {

	 printonedigit ( n );	/* 一桁の数値を出力し.. */
	 putchar ( '\n' );		/* 改行する */

}

Download : sample-014.c

sample-014.c
/*
 * 2017/05/26 sample-014.c
 */

/*
 * extern 宣言
 */

extern void println ( char *string );
extern void printonedigit ( int n );
extern void printonedigitln ( int n );

/*
 * 整数
 */

int main ( void ) {


	println ( "整数値 0 の出力" ); 
	printonedigitln ( 0 );			/* 「'0'」 でも 「"0"」 でもなく 「0」 */

	println ( "整数値 9 の出力" ); 
	printonedigitln ( 9 );			/* 一桁は OK */

	println ( "整数値 11 の出力" ); 
	printonedigitln ( 11 );		   /* 上手く行かない */

	println ( "整数値 1 + 1 の出力" ); 
	printonedigitln ( 1 + 1 );		/* やっと計算がでてきた */

	println ( "整数値 5 - 2 の出力" ); 
	printonedigitln ( 5 - 2 );		/* 引算 */

	println ( "整数値 3 * 2 の出力" ); 
	printonedigitln ( 3 * 2 );		/* かけ算 */

	println ( "整数値 8 / 3 の出力" ); 
	printonedigitln ( 8 / 3 ); 		/* 小数点以下は余りは切り捨て */

	println ( "整数値 8 % 3 の出力" ); 
	printonedigitln ( 8 % 3 ); 		/* 余りは「%」をで計算 */

	println ( "整数値 8 - ( 8 / 3 ) * 3 の出力" ); 
	printonedigitln ( 8 - ( 8 / 3 ) * 3 ); 		/* 余りを求めるもう一つの方法 */

	return 0;
}
sample-014.c の実行結果
$ ./sample-014.exe
整数値 0 の出力
0
整数値 9 の出力
9
整数値 11 の出力
;
整数値 1 + 1 の出力
2
整数値 5 - 2 の出力
3
整数値 3 * 2 の出力
6
整数値 8 / 3 の出力
2
整数値 8 % 3 の出力
2
整数値 8 - ( 8 / 3 ) * 3 の出力
2
$ 

Download : sample-015-01.c

sample-015-01.c
/*
 * 2017/05/26 sample-015-01.c
 */

#include <stdio.h>		/* putchar が必要なので.. */

/*
 * extern 宣言
 */

extern void printonedigit ( int n );

/*
 * printpositiveintsub ( int n )
 *	正の整数を出力する
 */

void printpositiveintsub ( int n ) {

	if ( n == 0 ) {						/* 0 の場合 */
		/* もう出力なくてよい */
	} else {
		printpositiveintsub ( n / 10 );	/* 上位の桁を出力し */
		printonedigit ( n % 10 );		/* 1 の位を出力する */
	}
}

/*
 * printpositiveint ( int n )
 *	非負の整数を出力する
 */

void printpositiveint ( int n ) {

	if ( n == 0 ) {					/* 0 の場合は特別扱い */
		putchar ( '0' );			/* 0 を出力 */
	} else {						/* その他の場合は、n 桁の処理 */
		printpositiveintsub ( n );	/* 正の場合の処理 */
	}
}

/*
 * printpositiveintln ( int n )
 *	正の整数を出力して改行する
 */

void printpositiveintln ( int n ) {

	 printpositiveint ( n );	/* 正の整数値を出力し.. */
	 putchar ( '\n' );		/* 改行する */

}

Download : sample-015.c

sample-015.c
/*
 * 2017/05/26 sample-015.c
 */

/*
 * extern 宣言
 */

extern void println ( char *string );
extern void printpositiveint ( int n );
extern void printpositiveintln ( int n );

/*
 * 整数
 */

int main ( void ) {

	println ( "整数値 0 の出力" ); 
	printpositiveintln ( 0 );

	println ( "整数値 11 の出力" ); 
	printpositiveintln ( 11 );

	println ( "整数値 12345 の出力" ); 
	printpositiveintln ( 12345 );

	println ( "整数値 12 * 34 の出力" ); 
	printpositiveintln ( 12 * 34 );

	return 0;
}
sample-015.c の実行結果
$ ./sample-015.exe
整数値 0 の出力
0
整数値 11 の出力
11
整数値 12345 の出力
12345
整数値 12 * 34 の出力
408
$ 

講議中に作成したプログラム

本日の課題

課題 20170526-01 : 与えられた文字列を逆順に出力する rprintf を定義しなさい

Download : 20170526-01.c

20170526-01.c
/*
 * 20170526-01-QQQQ.c
 *
 *	与えられた文字列を逆順に出力する rprintf を定義しなさい
 */

#include <stdio.h>

/*
 * rprintf
 */
 
void rprintf ( char *string ) {

	 if ( *string == '\0' ) {	/* 空文字ならば.. */
		/* 何もしない */
	 } else {

	/*
	**	 この部分を完成させなさい
	*/

	 }

}

/*
 * main
 */

int main ( void ) {

	rprintf ( "abcd" );
	putchar ( '\n' );
	rprintf ( "123456" );
	putchar ( '\n' );

	return 0;
}
20170526-01.c の実行結果
$ ./20170526-01-QQQQ.exe
dcba
654321
$ 

課題 20170526-02 : 出力する繰返し回数を整数で指定する ntimeprint を作りなさい

Download : 20170526-02.c

20170526-02.c
/*
 * 20170526-02-QQQQ.c
 *	出力する繰返し回数を整数で指定する ntimeprint を作りなさい
 */

#include <stdio.h>

/*
 * ntimeprint ( int times, char *message )
 */

void ntimeprint ( int times, char *message ) {

	if ( times <= 0 ) {	/* 非正なら、回数として不適切か、終わり */
		/* 何もしないくてよい */
	} else {								/* 繰返し回数が正ならば.. */
		printf ( message );					/* 少なくても一度は出力し.. */

	/*
	**	 この部分を完成させなさい
	*/

	}
}

/*
 * main
 */

int main ( void ) {

	printf ( "「Hello」を 3 回\n" );
	ntimeprint ( 3, "Hello\n" ); 

	printf ( "「ハ」を 30 回\n" );
	ntimeprint ( 30, "ハ" ); 
	printf ( "\n" );

	return 0;
}
20170526-02.c の実行結果
$ ./20170526-02-QQQQ.exe
「Hello」を 3 回
Hello
Hello
Hello
「ハ」を 30 回
ハハハハハハハハハハハハハハハハハハハハハハハハハハハハハハ
$ 

課題 20170526-03 : 負の整数も処理できる printint を作成しなさい

Download : 20170526-03.c

20170526-03.c
/*
 * 20170526-03-QQQQ.c
 *	負の整数も処理できる printint を作成しなさい
 *	ただし、正の整数を出力する printpositiveintsub, printpositiveint を利用してよい
 */

#include <stdio.h>

/*
 * printint
 */

void printint ( int n ) {

	 if ( n < 0 ) {		/* 負の時は.. */

	/*
	**	 この部分を完成させなさい
	*/

	 } else {			/* 正の時には.. */
		printpositiveint ( n );
	 }

}

/*
 * printintln
 */

void printintln ( int n ) {

	printint ( n );
	putchar ( '\n' );

}

/*
 * main
 */

int main ( void ) {

	printf ( "123 の出力\n" );
	printintln ( 123 );

	printf ( "-123 の出力\n" );
	printintln ( -123 );

	printf ( "123 + 456 の出力\n" );
	printintln ( 123 + 456 );

	printf ( "123 - 456 の出力\n" );
	printintln ( 123 - 456 );

  return 0;
}
20170526-03.c の実行結果
$ ./20170526-03-QQQQ.exe
$