K&R 演習4-2 解答 (プログラミング言語C 第2版)

スポンサーリンク

鍛錬 700

K&R 演習4-2 解答 (プログラミング言語C 第2版)

atof を拡張して,次のような科学記法を扱えるようにせよ。

123.45e-6

ここで,浮動小数点数のうしろには, e や E と符号の付きうる指数部が続いてもよいとする。

B.W.カーニハン D.M.リッチー 石田晴久 訳 『プログラミング言語C 第2版 ANSI 規格準拠』, (共立出版, 2017), pp.89.

スポンサーリンク

プログラム

以下は、本書中のatof関数を拡張して、科学記法にも対応した原始的な電卓プログラム、kr_4_2.c です。

atof()関数は stdlib.h で定義されているため、本プログラムではmy_atof()と関数名を変更しています。

pp.89 の時点でまだ登場していないライブラリ関数などはできる限り使用しないようにし、本書中で作成した関数を使用するようにしています。
記述方法(「 char *s 」または「 char s[] 」など)についても、できる限り pp.89 時点での記載通りにしています。

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

// preprocessor
#define MAXLINE 100	// 入力行の最大長

// prototype
int my_getline(char s[], int lim);
double my_atof(char s[]);
void copy(char from[], int elmt_num, char to[]);

// main
int main(void)
{
	char line[MAXLINE];
	double sum;
	
	sum = 0;
	while (my_getline(line, MAXLINE) > 0) {
		printf("\t%lf\n", sum += my_atof(line));
	}
	
	return 0;
}

// ========================================
// @brief  sに入力行を格納し,その長さを返す
// @param  lim [in],入力行の最大長
// @param  s   [out],入力された文字列
// @return i -> 入力された文字列の文字列長
// @note   無し
// ========================================
int my_getline(char s[], int lim)
{
	int c, i;
	
	i = 0;
	while (--lim > 0 && (c = getchar()) != EOF && c != '\n') {
		s[i++] = c;
	}
	if (c == '\n') {
		s[i++] = c;
	}
	s[i] = '\0';
	
	return i;
}

// ================================================
// @brief  文字列sをdouble型の数値に変換する
// @param  s [in],入力行
// @return sign * val / power -> 変換後の数値
// @note   以下の科学記法に対応
// @note   e+nnn.. , e-nnn... , E+nnn... , E-nnn...
// ================================================
double my_atof(char s[])
{
	char s_tmp[256] = "";
	double val, power;
	int i, n, len, cnt, sign;
	
	len = strlen(s);
	n = 0;
	for (i = 0; i < len; i++) {
		if (s[i] == '\0') {
			break;
		}
		else if (s[i] == ' ') {
			;
		}
		else {
			s_tmp[n++] = s[i];
		}
	}
	copy(s_tmp, 0, s);
	i = 0;
	
	sign  = (s[i] == '-') ? -1 : 1;
	
	if (s[i] == '+' || s[i] == '-') {
		i++;
	}
	for (val = 0.0; isdigit(s[i]); i++) {
		val = 10.0 * val + (s[i] - '0');
	}
	
	if (s[i] == '.') {
		i++;
	}
	for (power = 1.0; isdigit(s[i]); i++) {
		val = 10.0 * val + (s[i] - '0');
		power *= 10.0;
	}
	
	if (s[i] == 'e' || s[i] == 'E') {
		i++;
		if (s[i] == '+') {
			i++;
			cnt = (s[i] - '0');
			for (; cnt > 0; cnt-- ) {
				power /= 10;
			}
		}
		else if (s[i] == '-') {
			i++;
			cnt = (s[i] - '0');
			for (; cnt > 0; cnt-- ) {
				power *= 10;
			}
		}
	}
	
	return sign * val / power;
}

// ==================================================
// @brief  開始位置を指定して配列に文字列をコピーする
// @param  from     [in],コピー元の文字列
// @param  elmt_num [in],コピー開始位置
// @param  to       [out],コピー先の文字列
// @return 無し
// @note   無し
// ==================================================
void copy(char from[], int elmt_num, char to[])
{
	int i;
	
	i = 0;
	while ((to[elmt_num] = from[i]) != '\0') {
		elmt_num++;
		i++;
	}
}
スポンサーリンク

実行結果

以下は、プログラム kr_4_2.c を実行しています。

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -Wall -Wextra kr_4_2.c -o kr_4_2
***@ubuntu:~/***/test/c$ ./kr_4_2
1.234e-3
	0.001234
+1.0e+2
	100.001234
-0.234e-3
	100.001000
+0.23e+2
	123.001000
タイトルとURLをコピーしました