柴田望洋の『新・明解C言語中級編』の中の総合タイピング練習が上手く作動しない

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
naoji
記事: 15
登録日時: 10年前

柴田望洋の『新・明解C言語中級編』の中の総合タイピング練習が上手く作動しない

#1

投稿記事 by naoji » 10年前

柴田望洋の『新・明解C言語中級編』の中の総合タイピング練習をつくってみました。

本来なら、
「(1) 単純ポジション (2) 複数ポジション
printf("(3) C言語の単語  (4) 英会話 (0) 終了 : 」がまずは表示され、
「: 」の部分に該当する数字を入力すれば、その番号のトレーニングが開始されます。

ですが、
実際に起動してみますと、
何も表示されません。

スペースキーを押しても、
反応はなく、
スペースキー以外のキーを押すと、
無限にバグが発生します。

また、
何も表示されない状態で、
プログラムを強制終了させますと、
(1) 単純ポジション (2) 複数ポジション
printf("(3) C言語の単語  (4) 英会話 (0) 終了 : だけ表示されます。

どこに問題があって、
どの部分を修正すれば正常に作動するのでしょうか??
教えてください。
よろしくお願いします。

コード:

/*総合タイピング練習*/

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getputch.h"

#define NO 15				/*トレーニング回数*/
#define KTYPE 16			/*ブロック数*/
#define POS_LEN 10		/*ポジショントレーニングの文字数*/

/*--- 練習メニュー ---*/
typedef enum { Term , KeyPos , KeyPosComp , Clang , Conversation , InValid } Menu;

/*--- 各ブロックのキー ---*/
const char *kstr[] = {
	"12345" ,		"67890-\\",	/*第1段           */
	"!\"#$%" , 	"&'()0=~|" ,	/*第1段 [Shift] */
	"qwert" , 		"yuiop@[" ,	/*第2段           */
	"QWERT" , 	"YUIOP`{" , 	/*第2段 [Shift] */
	"asdfg" , 		"hjkl;:]",		/*第3段           */
	"ASDFG" , 	"HJKL+*}" ,	/*第3段 [Shift] */
	"zxcvb" , 		"nm,./_",		/*第4段           */
	"ZXCVB" , 	"NM<> _",	/*第4段 [Shift] */
};

/*--- C言語のキーワードとライブラリ関数 ---*/
const char *cstr[] = {
	"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",
	"abort",	"abs",		"acos",		"asctime",	"asin",		"assert",
	"atan",		"atan2",	"atexit",	"atof",		"atoi",		"atol",
	"bsearch",	"calloc",	"ceil",		"clearerr",	"clock",	"cos",
	"cosh",		"ctime",	"difftime",	"div",		"exit",		"exp",
	"fabs",		"fclose",	"feof",		"ferror",	"fflush",	"fgetc",
	"fgetpos",	"fgets",	"floor",	"fmod",		"fopen",	"fprintf",
	"fputc",	"fputs",	"fread",	"free",		"freopen",	"frexp",
	"fscanf",	"fseek",	"fsetpos",	"ftell",	"fwrite",	"getc",
	"getchar",	"getenv",	"gets",		"gmtime",	"isalnum",	"isalpha",
	"iscntrl",	"isdigit",	"isgraph",	"islower",	"isprint",	"ispunct",
	"isspace",	"isupper",	"isxdigit",	"labs",		"ldexp",	"ldiv",
	"localeconv",			"localtime","log",		"log10",	"longjmp",
	"malloc",	"memchr",	"memcmp",	"memcpy",	"memmove",	"memset",
	"mktime",	"modf",		"perror",	"pow",		"printf",	"putc",
	"putchar",	"puts",		"qsort",	"raise",	"rand",		"realloc",
	"remove",	"rename",	"rewind",	"scanf",	"setbuf",	"setjmp",
	"setlocale","setvbuf",	"signal",	"sin",		"sinh",		"sprintf",
	"sqrt",		"srand",	"sscanf",	"strcat",	"strchr",	"strcmp",
	"strcoll",	"strcpy",	"strcspn",	"strerror",	"strftime",	"strlen",
	"strncat",	"strncmp",	"strncpy",	"strpbrk",	"strrchr",	"strspn",
	"strstr",	"strtod",	"strtok",	"strtol",	"strtoul",	"strxfrm",
	"system",	"tan",		"tanh",		"time",		"tmpfile",	"tmpnam",
	"tolower",	"toupper",	"ungetc",	"va_arg",	"va_end",	"va_start",
	"vfprintf", "vprintf",	"vsprintf"
};

/*--- 英会話 ---*/
const char *vstr[] = {
	"Hello!",							/* こんにちは。*/
	"How are you?",						/* お元気ですか。 */
	"Fine thanks.",						/* はい元気です。 */
	"I can't complain, thanks.",		/* まあ、何とか。 */
	"How do you do?",					/* 初めまして。 */
	"Good bye!",						/* さようなら。 */
	"Good morning!",					/* おはよう。 */
	"Good afternoon!",					/* こんにちは。 */
	"Good evening!",					/* こんばんは。 */
	"See you later!",					/* さようなら(またね)。 */
	"Go ahead, please.",				/* お先にどうぞ。 */
	"Thank you.",						/* ありがとう。 */
	"No, thank you.",					/* いいえ結構です。 */
	"May I have your name?",			/* お名前は? */
	"I'm glad to meet you.",			/* お目にかかれて光栄です。 */
	"What time is it now?",				/* 何時ですか。 */
	"It's about seven.",				/* 大体7時くらいです。 */
	"I must go now.",					/* もういかなくちゃ。 */
	"How much?",						/* おいくら? */
	"Where is the restroom?",			/* お手洗いはどちらですか。 */
	"Excuse me.",						/* 失礼します(一人)。*/
	"Excuse us.",						/* 失礼します(二人以上)。*/
	"I'm sorry.",						/* ごめんなさい。 */
	"I don't know.",					/* さあ、知らないよ。 */
	"I have no change with me.",		/* 小銭がないのです。 */
	"I will be back.",					/* また戻って来ます。 */
	"Are you going out?",				/* 出かけるの? */
	"I hope I'm not disturbing you.",	/* お邪魔じゃなければいいのですが。*/
	"I'll offer no excuse.",			/* 弁解するつもりはありません。 */
	"Shall we dance?",					/* 踊りませんか。 */
	"Will you do me a favor?",			/* ちょっとお願いしたいのですが。 */
	"It's very unseasonable.",			/* それは季節外れだね。 */
	"You are always welcome.",			/* いつでも歓迎しますよ。 */
	"Hold still!",						/* じっとして! */
	"Follow me.",						/* ついて来て。 */
	"Just follow my lead.",				/* 僕のするとおりにやるだけだよ。 */
	"To be honest with you,",			/* 正直に言うと… */
};

/*--- 文字列strをタイプする練習(ミス回数を返す) ---*/
int go (const char *str)
{
	int i;
	int len = strlen(str);			/*文字数*/
	int mistake=0;				/*ミス回数*/
	
	for (i=0 ; i<len ; i++){
		/*str[i]以降を表示してカーソルを先頭へ戻す*/
		printf("%s \r" , &str[i] );
		fflush(stdout);
		while (getch() != str[i] ){
			mistake++;
		}
	}
	return mistake;
}

/*--- 単純ポジショントレーニング ---*/
void pos_training(void)
{
	int i;
	int stage;
	int temp , line;
	int len;				/*問題のブロックキーの数*/
	int qno , pno;			/*問題番号・前回の問題番号*/
	int tno, mno;			/*文字数・ミス回数*/
	clock_t start,end;		/*開始時刻・終了時刻*/
	
	printf("\n単純ポジショントレーニングを行います。\n");
	printf("練習するブロックを選択してください。\n");
	printf("第1段 (1) 左 %-8s		(2) 右 %-8s\n" , kstr[0] , kstr[1] );
	printf("第2段 (3) 左 %-8s		(4) 右 %-8s\n" , kstr[4] , kstr[5] );
	printf("第3段 (5) 左 %-8s		(6) 右 %-8s\n" , kstr[8] , kstr[9] );
	printf("第4段 (7) 左 %-8s		(8) 右 %-8s\n" , kstr[12] , kstr[13] );
	
	/*ブロックを選択させる*/
	do{
		printf("番号(練習中止は99) : ");
		scanf("%d" , &temp);
		if (temp == 99 ) return;			/*練習中止*/
	}while (temp < 1 || temp > 8);
	line = 4 * ( (temp-1) / 2) + (temp-1) %2;
	
	printf("%sの問題を%d回練習します。\n" , kstr[line] , NO );
	
	printf("スペースキーで開始します。\n");
	while (getch() != ' ')
		;
	
	tno = mno = 0;						/*文字数・ミス回数をクリア*/
	len = strlen(kstr[line] );				/*練習するブロックのキー数*/
	
	start = clock();						/*開始時刻*/
	
	for (stage=0 ; stage<NO ; stage++){
		char str[POS_LEN + 1];
		
		for (i=0 ; i<POS_LEN ; i++)			/*問題文字列を作成*/
			str[i] = kstr[line] [rand() % len];
		str[i] = '\0';
		
		mno += go(str);					/*練習実行*/
		tno += strlen(str);
	}
	end = clock();							/*終了時刻*/
	
	printf("問題 : %d文字 / ミス : %d回\n" , tno , mno);
	printf("%.1f秒でした。\n" , (double)(end - start) / CLOCKS_PER_SEC);
}

/*--- 複合ポジショントレーニング ---*/
void pos_training2(void)
{
	int i;
	int stage;
	int temp , line;
	int sno;						/*選ばれたブロック数*/
	int select[KTYPE];				/*選ばれたブロック*/
	int len[KTYPE];					/*問題のブロックのキー数*/
	int tno , mno;					/*文字数・ミス回数*/
	clock_t start,end;				/*開始時刻・終了時刻*/
	char *format = "第%d段 (%2d) 左 %-8s (%2d) 右 %-8s"
					     "(%2d) [左] %-8s (%2d) [右] %-8s\n";
	
	printf("\n複合ポジショントレーニングを行います。\n");
	printf("練習するブロックを選択してください。(複数選べます)。\n");
	
	for (i=0 ; i<4 ; i++){
		int k = i * 4;
		printf(format , i + 1 , k + 1 , kstr[k] ,	k + 2 , kstr[k + 1],
							    k + 3 , kstr[k +2] , k + 4 , kstr[k + 3] );
	}

	/* ブロックを重複させずに選択させる(最大16個) */
	sno =0;
	while (1){
		printf("番号 (選択終了は50 / 練習中止は99) : ");
		
		do{
			scanf("%d" , &temp);
			if (temp == 99)	 return;			/*練習中止*/
		}while ( (temp < 1 || temp > KTYPE) && temp != 50);
		
		if (temp == 50)
			break;
		for (i=0 ; i<sno ; i++)
			if (temp == select[i] ){
				printf("\aその段は既に選ばれています。\n");
				break;
			}
		if (i == sno)
			select[sno++] = temp;			/*選ばれたブロックを登録*/
	}
	
	if (sno == 0)
		return;							/*一つも選ばれなかった*/
	
	printf("以下のブロックの問題を%d回練習します。\n" , NO);
	
	for (i=0 ; i<sno ; i++)
		printf("%s " , kstr[select[i] - 1 ] );
	
	printf("\nスペースキーで開始します。\n");
	while (getch() != ' ')
		;
	
	tno = mno = 0;						/*文字数・ミス回数をクリア*/
	for (i=0 ; i<sno ; i++)
		len[i] = strlen(kstr[select[i] - 1 ] );	/*ブロックのキー数*/
	
	start = clock();						/*開始時刻*/
	
	for (stage=0 ; stage<NO ; stage++){
		char str[POS_LEN +1 ];
		
		for (i=0 ; i<POS_LEN ; i++){		/*問題文字列を作成*/
			int q = rand() % sno;
			str[i] = kstr[select[q] -1] [rand() % len[q] ];
		}
		str[i] = '\0';
		
		mno += go(str);				/*練習実行*/
		tno += strlen(str);
	}
	
	end = clock();						/*終了時刻*/
	
	printf("問題 : %d文字 / ミス : %d回\n" , tno , mno);
	printf("%.1f秒でした。\n" , (double)(end - start) / CLOCKS_PER_SEC );
}

/*--- C言語/英会話トレーニング ---*/
void word_training(const char *mes , const char *str[] , int n)
{
	int stage;
	int qno , pno;					/*問題番号・前回の問題番号*/
	int tno , mno;					/*文字数・ミス回数*/
	clock_t start , end;				/*開始時刻・終了時刻*/
	
	printf("\n%sを%d回練習します。\n" , mes , NO);
	
	printf("スペースキーで開始します。\n");
	while (getch() != ' ')
		;
	
	tno = mno = 0;					/*文字数・ミス回数をクリア*/
	pno = n;						/*前回の問題番号 (存在していない番号) */
	
	start = clock();					/*開始時刻*/
	
	for (stage=0 ; stage<NO ; stage++){
		do{						/*同じ問題を連続して出題しない*/
			qno = rand() % n;
		}while ( qno == pno);
		
		mno += go(str[qno] );		/*問題はstr[qno] */ 
		tno += strlen(str[qno] );
		pno = qno;
	}
	
	end = clock();					/*終了時刻*/
	
	printf("問題 : %d文字 / ミス : %d回\n" , tno , mno);
	printf("%.1f秒でした。\n" , (double)(end - start) / CLOCKS_PER_SEC );
}

/*--- メニュー選択 ---*/
Menu SelectMenu (void)
{
	int ch;
	
	do{
		printf("\n練習を選択してください\n");
		printf("(1) 単純ポジション	   (2) 複数ポジション\n");
		printf("(3) C言語の単語     (4) 英会話             (0) 終了 : ");
		scanf("%d" , &ch);
	}while (ch < Term || ch >= InValid );
	
	return (Menu)ch;
}

int main(void)
{
	Menu menu;							/*メニュー*/
	int cn = sizeof (cstr) / sizeof (cstr[0] );		/*C言語の単語数*/
	int vn = sizeof (vstr) / sizeof (vstr[0] );		/*英会話の単語数*/
	
	init_getputch( );
	
	srand(time(NULL ) );					/*乱数の種を設定*/
	
	do{
		switch (menu = SelectMenu() ){
			
			case KeyPos :					/*単純ポジショントレーニング*/
						pos_training();
						break;
						
			case KeyPosComp : 			/*複合ポジショントレーニング*/
						pos_training2();
						break;
			
			case Clang : 					/*C言語の単語*/
						word_training("C言語の単語" , cstr , cn);
						break;
			
			case Conversation : 			/*英会話*/
						word_training("英会話の文章" , vstr , vn);
						break;
			case Term: 
						break; 
			
			case InValid: 
						break;
		}
	}while (menu != Term);
	
	term_getputch( );
	
	return 0;
}
ちなみにgetputch.hのコードはこれです。

コード:

/*getch/putch用の共通ヘッダ"getputch.h"*/

#ifndef __GETPUTCH

	#define __GETPUTCH
	
	#if defined  (_MSC_VER) || (__TURBOC__)  || (LSI_C)
	
		/*MS-Windows/MS-DOS(Visual C++ , Borland C++ , LSI-C 86 etc... ) */
	
		#include <conio.h>
		
		static void init_getputch(void) { /* 空 */ }
		
		static void term_getputch(void) { /* 空 */ }
	
	#else
	
		/*Cursesライブラリが提供されるUNIX/Linux/OS X */
	
		#include <curses.h>
	
		#undef putchar
		#undef puts
		#undef printf
		static char __buf[4096];
	
		/*--- putchar : putchar関数と同等 ( 改行を[改行+復帰]で出力) ---*/
		static int __putchar(int ch)
		{
			if ( ch == '\n')
				putchar('\r');
			return putchar(ch);
		}
	
		/*--- putch : 1文字表示してバッファを掃き出す ---*/
		static int putch(int ch)
		{
			int result = putchar(ch);
		
			fflush(stdout);
			return result;
		}
	
		/*--- __printf : printf関数と同等(改行を[改行+復帰]で出力) ---*/
		static int __printf( const char *format , ...)
		{
			va_list ap;
			int		count;
			
			va_start (ap , format);
			vsprintf (__buf , format , ap);
			va_end (ap);
			
			for ( count=0 ; __buf[count] ; count++){
				putchar (__buf[count] );
				if (__buf[count] == '\n' )
					putchar ('\r');
			}
			return count;
		}
	
		/*--- __puts: puts関数と同等 ( 改行を[改行+復帰]で出力) ---*/
		static int __puts(const char *s)
		{
			int i , j;
			
			for (i=0 , j=0 ; s[i] ; i++){
				__buf[j++] = s[i];
				if (s[i] == '\n')
					__buf[j++] = '\r';
			}
			return puts(__buf);
		}
		
		/*--- ライブラリ初期処理 ---*/
		static void init_getputch(void)
		{
			initscr();
			cbreak();
			noecho();
			refresh();
		}
		
		/*---  ライブラリ終了処理 ---*/
		static void term_getputch(void)
		{
			endwin();
		}
		
		#define putchar __putchar
		#define printf __printf
		#define puts __puts
	
	#endif

#endif
	
 
最後に編集したユーザー naoji on 2015年7月23日(木) 13:25 [ 編集 2 回目 ]

naohiro19
記事: 256
登録日時: 14年前
住所: 愛知県

Re: 起動しても何も表示されない

#2

投稿記事 by naohiro19 » 10年前

ところが、このコードの動作は未定義だということをご存知でしょうか? _FOO のように、下線(アンダースコア、アンダーバー)で始まり、下線または大文字が続く識別子は「予約済み識別子」です。予約済み識別子というのは、規格がライブラリに使うか、処理系が作業用または拡張用に使うために予約されている識別子で、それらをユーザープログラムで使用することはできません(使用した場合の動作は未定義です)

未定義の動作ですから、実行時におかしな振る舞いをするかもしれませんし、コンパイル時にエラーになったり、コンパイラがフリーズしたりするかもしれません。そうはいっても、現実には問題ないだろうと思われるかもしれません。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 起動しても何も表示されない

#3

投稿記事 by みけCAT » 10年前

前のトピックを解決にしてください。
http://dixq.net/forum/viewtopic.php?f=3&t=16848
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

naoji
記事: 15
登録日時: 10年前

Re: 起動しても何も表示されない

#4

投稿記事 by naoji » 10年前

未定義なのですか、、、
初めて知りました。

では、
もし正常に動作させるためにはコードをどのようにすれば良いのでしょうか??

みけCATさん。
前のトピックを解決にしました!
お手数おかけしてすみません(^^;)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 柴田望洋の『新・明解C言語中級編』の中の総合タイピング練習が上手く作動しない

#5

投稿記事 by みけCAT » 10年前

naoji さんが書きました:どこに問題があって、
どの部分を修正すれば正常に作動するのでしょうか??
バッファに入ったデータがすぐに出力されないことがあるようです。
・141行目
・149行目
・171行目
・200行目
・226行目
・252行目
・265行目
・287行目
・298行目
の直後にそれぞれfflush(stdout);を追加すると、動作が改善しました。
naoji さんが書きました:未定義なのですか、、、
初めて知りました。

では、
もし正常に動作させるためにはコードをどのようにすれば良いのでしょうか??
素直に「予約済み識別子」をグローバルなマクロ、変数名、関数名、構造体名などで使わないようにすればいいと思います。
(他にも未定義動作になる条件は大量にあります)
[search=google]C言語 未定義動作[/search]
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

naoji
記事: 15
登録日時: 10年前

Re: 柴田望洋の『新・明解C言語中級編』の中の総合タイピング練習が上手く作動しない

#6

投稿記事 by naoji » 10年前

naohiro19 さん、みけCATさんありがとうございます!
おかげで正常に動作しました!!

閉鎖

“C言語何でも質問掲示板” へ戻る