Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

分子と分母を文字列形式で表現するCプログラムの書き方


問題概要

実行時にユーザーが入力した2つの整数(分子と分母)を受け取り、動的メモリ割り当て(malloc・realloc)を活用しながら、その分数を小数として計算し、結果を文字列形式で表現するCプログラムを作成します。

特に、割り切れない場合に発生する循環小数(例:0.571428571428...)を「0.(571428)」のように括弧付きで表現できる点がこのプログラムのポイントです。

解決策

分子と分母を文字列形式で表現するための基本的なアプローチは以下の通りです。

  • 筆算の要領で余りを10倍しながら商を順に求め、小数部分の各桁を導出します。
  • 同じ余りが再び現れたら、そこから先が循環すると判断し、該当部分を括弧で囲んで出力します。
  • 結果の桁数は事前に分からないため、mallocで初期確保し、不足したらreallocで拡張する動的メモリ管理を行います。

入力例 −

Numerator1 = 3
Denominator1 = 2

numerator2 = 4
denominator2 = 7

出力例 −

Fractional part1: 1.5
Fractional part2: 0.(571428)

Cプログラム例

以下は、分子と分母を文字列形式で表現するCプログラムの完全なコードです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char* fractionToDecimal(int numerator, int denominator) {
    char *p;
    int psz, n, *dec, dsz, x;
    long long num, den, k, f;
    int i, repeat_at;
    int neg = 0;
    psz = dsz = 100; n = x = 0;
    p = malloc(psz * sizeof(char));
    //assert(p);
    neg = ((numerator > 0 && denominator < 0) ||
    (numerator < 0 && denominator > 0)) ? 1 : 0;
    num = numerator;
    den = denominator;
    num = (num < 0) ? -num : num;
    den = (den < 0) ? -den : den;
    k = num / den;
    f = num % den;
    if (neg && (k || f)) p[n ++] = '-';
       n += sprintf(&p[n], "%lld", k);
    if (!f) {
        p[n] = 0;
        return p;
    }
    p[n ++] = '.';
    dec = malloc(dsz * sizeof(int));
    repeat_at = -1;
    if (f < 0) f = -f;
    while (f) {
        for (i = 0; i < x; i += 2) {
            if (dec[i] == f) {
                repeat_at = i;
                goto done;
            }
        }
        if (x + 1 >= dsz) {
            dsz *= 2;
            dec = realloc(dec, dsz * sizeof(int));
        }
        dec[x ++] = f;
        f *= 10;
        k = f / den;
        dec[x ++] = k;
        f = f % den;
    }
    done:
    for (i = 0; i < x; i += 2) {
        if (n + 3 > psz) {
            psz *= 2;
            p = realloc(p, psz * sizeof(char));
        }
        if (repeat_at == i) {
            p[n ++] = '(';
        }
        p[n ++] = '0' + dec[i + 1];
    }
    if (repeat_at != -1) p[n ++] = ')';
       p[n ++] = 0;
    free(dec);
    return p;
}
int main(void){
    int n,d;
    printf("enter numerator1 and denominator1:");
    scanf("%d%d",&n,&d);
    printf("n = %d, d = %d ", n, d);
    printf("\nFractional part1: %s \n",fractionToDecimal(n, d));
    printf("enter numerator2 and denominator2:");
    scanf("%d%d",&n,&d);
    printf("\nn = %d, d = %d ", n, d);
    printf("\nFractional part2: %s\n ",fractionToDecimal(n, d));
    return 0;
}

コードのポイント

  • 符号処理: 分子と分母の符号が異なる場合は結果が負になるため、negフラグで判定し、必要に応じて先頭に「-」を付加します。
  • 整数部と小数部の分離: num / den で整数部を、num % den で余り(小数部のもと)を求めます。余りが0なら割り切れたので、その時点で文字列を完成させて返します。
  • 循環の検出: 余りの履歴をdec配列に保存し、同じ余りが出現した位置をrepeat_atに記録します。出力時にその位置へ「(」を挿入し、末尾に「)」を付けることで循環部を明示します。
  • 動的メモリ拡張: 文字列バッファpと余り配列decは、容量を超えそうになるとreallocで2倍に拡張されます。decは使用後にfreeで解放し、戻り値の文字列は呼び出し元が責任を持って解放します。

実行結果

上記のプログラムをコンパイルして実行すると、以下のような結果が得られます。

enter numerator1 and denominator1:4 5
n = 4, d = 5
Fractional part1: 0.8
enter numerator2 and denominator2:5 9

n = 5, d = 9
Fractional part2: 0.(5)

4÷5=0.8のように割り切れる場合は単純な小数として出力され、5÷9=0.5555...のように循環する場合は「0.(5)」という形式で循環部が括弧付きで表示されることが確認できます。

  1. C言語で文字列へのポインタの配列とそのアドレスを出力する方法

    まずは、C言語における「ポインタの配列」とは何かを確認しましょう。 文字列へのポインタの配列とは 各要素が、文字列の先頭アドレスを指すポインタになっている配列のことです。 宣言と初期化は次のように行います。 char *a[ ] = {"one", "two", "three"}; ここで、a[0] は文字列 one の、a[1] は two の、a[2] は three のそれぞれ先頭アドレスを指すポインタです。 イメージとしては、配列の各要素が対応する文字列の先頭番地を保持しており、その番地をたどることで文字列本体へアクセスで

  2. C++プログラムで文字列を「X」字型に表示する方法

    文字列が与えられたとき、その文字列を「X」字型のパターンとして出力するプログラムを作成します。完成イメージは以下の通りです。考え方このパターンを実現するには、3つの変数を活用します。i:行ごとに左から右へ進む位置を表す変数j:右から左へ進む位置を表す変数(len-1-i で計算)k:各行内のスペースと文字の出力位置を判定するための変数各行では、k の位置が i または j と一致した場合にのみ該当する文字を出力し、それ以外の位置にはスペースを表示します。これにより、対角線上に文字が配置された「X」字型のパターンが描かれます。アルゴリズム 関数 void print(string str, in