ページ 11

テキストファイルの計算式を読み込無方法

Posted: 2017年6月07日(水) 13:52
by ki
はじめまして。
2+3などの計算式が書いてあるテキストファイルを読みこんで1行目に読み込んだ式、2行目に計算結果を表示したいのですが、
どうしていいのかわかりません。

どなたかご教授いただけませんでしょうか。

Re: テキストファイルの計算式を読み込無方法

Posted: 2017年6月07日(水) 14:23
by かずま
ki さんが書きました:はじめまして。
2+3などの計算式が書いてあるテキストファイルを読みこんで1行目に読み込んだ式、2行目に計算結果を表示したいのですが、
どうしていいのかわかりません。
計算のほうは引き受けますから、まずテキストファイルを 1行読み込む部分のプログラムを提示してください。

Re: テキストファイルの計算式を読み込無方法

Posted: 2017年6月07日(水) 14:34
by ki
初学者なのでこれでいいのか不確かですが、よろしくお願いいたします。


#include <stdio.h>
#include <stdlib.h>

#define MAX_STRINGS 80

void main(void)
{
char filename[] = "data.txt";
FILE *fp;
char data[MAX_STRINGS];

/* ファイル・オープン */
if ((fp = fopen(filename, "r")) == NULL)
{
printf("ファイル「%s」のオープンに失敗しました。プログラムを終了します。\n", filename);
exit(1);
}

/* データ処理 */
while (fgets(data, MAX_STRINGS, fp) != NULL)
{
printf("%s", data);
}

/* ファイル・クローズ */
fclose(fp);

Re: テキストファイルの計算式を読み込無方法

Posted: 2017年6月07日(水) 15:14
by かずま
ソースプログラムを貼り付けるときは、codeタグを使ってほしかった。
フォーラムルールをよく読んでください。お願いします。

さて、計算部分ですが、ちょっと謎めいた書き方をしています。
これを解読して、普通の書き方に直して、返信に貼り付けてください。

コード:

#include <stdio.h>  // printf, fopen, fclose, fgets
#include <stdlib.h> // strtod, exit
#include <ctype.h>  // isspace, isdigit
#include <math.h>   // pow

#define MAX_STRINGS 80

unsigned char c;
const char *p, o[] = "+-*/^^";

int get(void) { do c = *p++; while (isspace(c)); return c; }

double expr(const char *b)
{
    double v;
    if (*b)
        for (v = expr(b+2); c == b[0] || c == b[1]; )
            c == '+' ? v += expr(b+2) :
            c == '-' ? v -= expr(b+2) :
            c == '*' ? v *= expr(b+2) :
            c == '/' ? v /= expr(b+2) : (v = pow(v, expr(b)));

    else
        get() == '.' || isdigit(c) ?  v = strtod(p-1, (char**)&p), get() :
            c == '(' ? v = expr(o), c == ')' ? get() : (c = 1) :
            c == '+' ? v = expr(b) :
            c == '-' ? v = -expr(b) :
            (v = c = 1);
    return v;
}

int calc(const char *s, double *v) { return p = s, *v = expr(o), c; }

int main(void)
{
    char filename[] = "data.txt";
    FILE *fp;
    char data[MAX_STRINGS];

    if ((fp = fopen(filename, "r")) == NULL) { /* ファイル・オープン */
        printf("ファイル「%s」のオープンに失敗しました。プログラムを終了します。\n", filename);
        exit(1);
    }

    while (fgets(data, MAX_STRINGS, fp) != NULL) { /* データ処理 */
        double val;
        printf("%s", data);
        if (calc(data, &val))
            printf("  error\n");
        else
            printf("  %.15g\n", val);
    }
    
    fclose(fp); /* ファイル・クローズ */
    return 0;
}
data.txt

コード:

2+3
1 + 2*(3-4)/5
355/113
2^3^2
4**5
実行結果

コード:

2+3
  5
1 + 2*(3-4)/5
  0.6
355/113
  3.14159292035398
2^3^2
  512
4**5
  error

Re: テキストファイルの計算式を読み込無方法

Posted: 2017年6月07日(水) 15:45
by ki
フォーラムルールの件、申し訳ございません。

しばらく考えましたが、特にfor文の中が難しくて理解できませんでした・・・

Re: テキストファイルの計算式を読み込無方法

Posted: 2017年6月07日(水) 16:18
by かずま
ki さんが書きました:しばらく考えましたが、特にfor文の中が難しくて理解できませんでした・・・

コード:

        for (v = expr(b+2); c == b[0] || c == b[1]; )
            if (c == '+')
                v += expr(b+2);
            else if (c == '-')
                v -= expr(b+2);
            else if (c == '*')
                v *= expr(b+2);
            else if (c == '/')
                v /= expr(b+2);
            else
                v = pow(v, expr(b));
これなら分かりますか?

Re: テキストファイルの計算式を読み込無方法

Posted: 2017年6月08日(木) 18:50
by かずま
三項演算子の ? : が難しいのではなく、expr(b+2) って何?
ということでしょうか?

式が "2+3" だとして、ちょっと考えてみましょう。

double expr(const char *b) が expr("+-*/^^") で呼び出されると、
b は "+-*/^^" を指すので、b+2 は "*/^^" を指します。
expr("*/^^") で呼び出されると、次は、expr("^^") で呼び出します。

expr("^^") で呼び出されると、次は、expr("") で呼び出します。
expr("") で呼び出されると、for文に行かず、else に行って、
get() で式から 1文字読み出し、それが数字だったら、strtod() で
値に変換し、v に入れます。v は 2 です。次の get() で後続の
演算子 '+' を c に入れて、expr からリターンします。

expr("^^") の for文に戻りますが、c が '^' ではないので戻ります。
expr("*/^^") の for文に戻りますが、c が '*', '/' ではないので戻ります。

expr("++*/^^") の for文に戻りますが、c が '+' なので、その + の
第二項である expr("*/^^") の値 3 を取得して、最初の値に足します。
v は 5 になります。

c には文字列の末尾の '\0' が入っていて、これで正常終了です。

納得していただけますか?
面白いと思いませんか?