C言語でストップウォッチを作成するプログラムの書き方

C言語でストップウォッチを作る方法は簡単です。

使う関数はgetchar関数 clock関数 printf関数だけです。この4つを使うだけでストップウォッチを作成することができます。

知らない関数があるかもしれませんが、随時解説します

このページではサンプルコードを交えながらストップウォッチの作り方を解説していますので、ストップウォッチの作り方が分からない方は参考にしてください。

ストップウォッチのサンプルプログラム

#include<stdio.h>
#include<time.h>

int main() {
	clock_t start, end;
	printf("エンターキーを押すと計測開始");
	getchar();
	start = clock();
	printf("エンターキーを押すと計測を終了します");
	getchar();
	end = clock();

	printf("%.2f秒です。\n", (double)(end - start) / 1000);

	return 0;
}

解説

getchar関数は入力が完了するまで(エンターキーを押すまで)処理が先に進まない関数です。

その仕様を応用し、エンターキーを押したらストップウォッチのカウントがスタートするように、8行目にgetchar関数で文字入力待ち状態にしています。

getchar関数はエンターキーを押すと次の処理に進んでいくので、エンターキーが押された直後にclock関数を使ってストップウォッチのタイマーを開始します。

start = clock();

その直後にもう一度getchar関数を記述し、エンターキーを押したらストップウォッチを止めるという流れになっています。

printf("エンターキーを押すと計測を終了します");
c = getchar();
end = clock(); //ストップウォッチ停止

あとはストップウォッチを止めた時間から開始した時間を引けばストップウォッチでカウントしたタイマーの秒数を取得できます。

clock関数で取得できるのはミリ秒ですので、秒数に直すときは1000で割ることを忘れないようにしましょう。

double diff = (double)(end - start);
printf("%.4f秒です。\n", diff / 1000);

clock_t型は整数値しか扱えない型(long型)なので、秒数に直すときはdouble型・float型どちらかに変換(キャスト)してから計算するようにしてください。
そうしないと1秒未満の値が切り捨てられます。

これでストップウォッチ完成です。プログラムの仕組みがわかったかと思います。

【応用テクニック】経過時間をリアルタイムで表示する

先程紹介したストップウォッチのサンプルプログラムでは、計測を完了したときしか時間を表示することができませんでした。

できれば経過時間をリアルタイムで表示させたいところですが、コンソールプログラムでも可能です。実際に作成すると以下のような挙動になります。

リアルタイムでストップウォッチの経過時間を表示するコンソールプログラム

リアルタイムで表示させるようにしたい場合はマルチスレッドを使います。

マルチスレッドとは、非同期処理のことです。getchar関数で入力待ち状態にしている間はプログラムが一時停止してしまいますが、マルチスレッド化することで、getchar関数で入力待ち状態にしつつも別の処理を走らせることが可能です。

ここで紹介するのはWindowsでC言語プログラミングしている方向けの記述方法です。スレッド周りはWindowsかUNIX/LINUX系かで異なるので注意しましょう。

サンプルコード

リアルタイムで経過時間を表示できるストップウォッチのサンプルコードです。

#include<stdio.h>
#include<time.h>
#include<Windows.h>

int exitflag = 0; //経過時間を表示するスレッド終了を管理するフラグ
int _stdcall PrintUpdate(void* start) {
	clock_t now = 0;
	while (exitflag == 0) {
		now = clock();

		double diff = (double)(now - *(clock_t*)start);
		fflush(stdout);
		printf("\r経過時間%.2f秒です", diff / 1000);

	}
	//スレッド終了フラグが立ってループを抜けたら最終的な経過時間を表示
	double diff = (double)(now - *(clock_t*)start);
	fflush(stdout);
	printf("\r経過時間は%.2f秒でした。\n", diff / 1000);

	return 0;
}

int main() {
	
	clock_t start = 0, end;

	//スレッドの作成
	HANDLE thread1 = CreateThread(NULL,0,PrintUpdate,(void*)&start,CREATE_SUSPENDED,NULL);
	
	printf("エンターキーを押すと計測開始");
	int c;
	getchar();
	//ストップウォッチ開始
	start = clock();
	printf("エンターキーを押すと計測を終了します\n");

	//スレッドの開始(経過時間の表示を開始)
	ResumeThread(thread1);


	getchar();
	//スレッドを停止させるフラグを立てる
	exitflag = 1;

	printf("エンターキーを押すとプログラムを終了します\n");

	//入力待ち中に経過時間を表示させるスレッドが停止する
	getchar();
	return 0;
}

実行結果サンプル

上記のコードを実際に実行すると、以下のような動作になります。

マルチスレッドの話をすると長くなるので、getchar関数でエンターキーの入力を待ちながら経過時間を表示するプログラムを別で動かしていると思っておいてください。

実はエスケープシーケンス\rを上手に使うことでprintf関数で出力したテキストを上書きすることができるのです。

\rは行の先頭にカーソル位置を戻すという意味で、カーソル位置を行の先頭に戻した状態でprintf関数を使って文字を出力すると、その行のテキストを上書きすることができるのです。

この仕様を応用して、マルチスレッドで経過時間を取得・計算・表示するようにしています。

マルチスレッドは難しいですが、使いこなせるととても便利ですので、少し練習してみるといいかもしれません。

カテゴリー:
関連記事