为什么while循环中的条件语句会导致程序永远有选择地暂停?

时间:2014-09-12 00:14:54

标签: c if-statement while-loop boolean-logic cs50

我试图通过使用“贪婪算法”来确定偿还变更所需的最小硬币数量。如果用户只输入一个常数整数的倍数,我在下面编写的程序正在按预期工作。然而,当谈到处理多个硬币时,程序只会暂停。

我认为问题出在我的CountGreed函数的条件语句while循环中。我试过找到答案,但我遇到的任何事情似乎都没有给我提供任何见解,可以指导我理解我的逻辑是什么。

我知道这是微不足道的,并且在循环中通过条件语句重复,然后将我带到所述问题。如果用户输入,0.25,0.10,0.05和0.01的倍数运行良好。例如,1.00,1.25,0.20但不是0.30,1.13,0.26等

#include "cs50.h" // Contains declaration for GetFloat()
#include <stdio.h>
#include <math.h>

float PromptChange(void); // Returns customer change in dollars
int ConvertToCents(float); // Returns a conversion from dollars to cents
int CountGreed(int); // Returns the minimum number of coins for which change can be made

int main (void)
{
    float Dollars = PromptChange();
    int Cents = ConvertToCents(Dollars);
    int CoinCount = CountGreed(Cents);
    printf("The minimum number of coins required to give back change is %i.\n", CoinCount);
    return 0;
}

float PromptChange(void)
{
    float Dollars;
    do {
        printf ("Owed change: $");
        Dollars = GetFloat ();
    } while (Dollars < 0);
    return Dollars;
}

int ConvertToCents(float Dollars)
{
    float Cents = Dollars * 100;
    int IntCents = (int)roundf(Cents);
    return IntCents;
}

int CountGreed(int IntCents)
{
    const int Quarter = 25, Dime = 10, Nickel = 5, Penny = 1;
    int SubCoinCount = 0;
    int CoinCount = 0;
    int Remainder = 0;
    while (IntCents) {
        if (IntCents >= Quarter) {
            SubCoinCount = IntCents / Quarter;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Quarter;
            IntCents = Remainder;
        } else if (IntCents < Quarter && IntCents >= Dime) {
            SubCoinCount = IntCents / Dime;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Dime;
            IntCents = Remainder;
        } else if (IntCents < Dime && IntCents >= Nickel) {
            SubCoinCount = IntCents / Nickel;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Nickel;
            IntCents = Remainder;
        } else if (IntCents < Nickel && IntCents >= Penny) {
            SubCoinCount = IntCents / Nickel;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Dime;
            IntCents = Remainder;
        }
    }
    return CoinCount;
}

我粘贴了整个main.c文件,以便可以清楚地看到整个程序的流程,尽管问题在于循环。我在多个编译器上尝试过这个,只是为了确保它是我的错。

2 个答案:

答案 0 :(得分:0)

此:

else if (IntCents < Nickel && IntCents >= Penny) {
    SubCoinCount = IntCents / Nickel;
    CoinCount += SubCoinCount;
    Remainder += IntCents % Dime;
    IntCents = Remainder;
}

应该是这样的:

else if (IntCents < Nickel && IntCents >= Penny) {
    SubCoinCount = IntCents / Penny;   // <--- Change to Penny, or just remove
    CoinCount += SubCoinCount;
    Remainder += IntCents % Penny;     // <--- Change to Penny
    IntCents = Remainder;
}

除了硬币的面额外,你的四个if个案是完全相同的,这意味着他们会被迫加入一个单独的职能部门。这样做是一种很好的方法,可以避免在一个或几个案例中出现这样的错误,因为你只会写一次。

我也怀疑:

Remainder += IntCents % Dime;

应该是:

Remainder = IntCents % Dime;

否则Remainder会无休止地增加,IntCents永远不会变为零。在这种情况下,Remainder实际上变得不必要,您可以将结果直接分配给IntCents

但完全这样做的方法比较简单。这是一个建议的替代方案,供您细读:

#include <stdio.h>

//  This cries out to be its own function

int coin_count(int cents, int denomination, int * remainder)
{
    *remainder = cents % denomination;
    return cents / denomination;
}

//  Better way

int CountGreed(int IntCents)
{
    static const int Quarter = 25, Dime = 10, Nickel = 5, Penny = 1;
    int CoinCount = 0;

    while ( IntCents > 0 ) {
        if ( IntCents >= Quarter ) {
            CoinCount += coin_count(IntCents, Quarter, &IntCents);
        } else if ( IntCents >= Dime ) {
            CoinCount += coin_count(IntCents, Dime, &IntCents);
        } else if ( IntCents >= Nickel ) {
            CoinCount += coin_count(IntCents, Nickel, &IntCents);
        } else if ( IntCents >= Penny ) {
            CoinCount += coin_count(IntCents, Penny, &IntCents);
        }
    }

    return CoinCount;
}

//  Even better way

int CountGreed2(int IntCents)
{
    static const int coins[4] = {25, 10, 5, 1};
    int CoinCount = 0;

    for ( int i = 0; i < 4; ++i ) {
        if ( IntCents >= coins[i] ) {
            CoinCount += coin_count(IntCents, coins[i], &IntCents);
        }
    }

    return CoinCount;
}

int main(void) {
    printf("Coins for $1.25 (should be 5): (%d)\n", CountGreed(125));
    printf("Coins for $1.00 (should be 4): (%d)\n", CountGreed(100));
    printf("Coins for $0.96 (should be 6): (%d)\n", CountGreed(96));

    printf("Coins for $1.25 (should be 5): (%d)\n", CountGreed2(125));
    printf("Coins for $1.00 (should be 4): (%d)\n", CountGreed2(100));
    printf("Coins for $0.96 (should be 6): (%d)\n", CountGreed2(96));

    return 0; 
}

输出:

paul@local:~/Documents/src/sandbox$ ./coins
Coins for $1.25 (should be 5): (5)
Coins for $1.00 (should be 4): (4)
Coins for $0.96 (should be 6): (6)
Coins for $1.25 (should be 5): (5)
Coins for $1.00 (should be 4): (4)
Coins for $0.96 (should be 6): (6)
paul@local:~/Documents/src/sandbox$ 

CountGreed2()中对单独功能的需求不太明显,因为您只需要编写一次,但口味会有所不同。

答案 1 :(得分:0)

#include "cs50.h" // Contains declaration for GetFloat()
#include <stdio.h>
#include <math.h>

float PromptChange(void); // Returns customer change in dollars
int ConvertToCents(float); // Returns a conversion from dollars to cents
int CountGreed(int); // Returns the minimum number of coins for which change can be made

int main (void)
{
    float Dollars = PromptChange();
    int Cents = ConvertToCents(Dollars);
    int CoinCount = CountGreed(Cents);
    printf("The minimum number of coins required to give back change is %d.\n",
           CoinCount);
    return 0;
}

float PromptChange(void)
{
    float Dollars;
    do {
        printf ("Owed change: $");
        Dollars = GetFloat ();
    } while (Dollars < 0);

    return Dollars;
}

// the original function ConvertToCents() 
// will usually return an incorrect value
// typically off by 1
// This is because float values often cannot exactly represent
// the desired value
int ConvertToCents(float Dollars)
{
    float Cents = Dollars * 100.0f; // note all values should be float
    int IntCents = floor(Cents+.5f); // round up to whole penny

    return IntCents;
}

int CountGreed(int IntCents)
{
    const int Quarter = 25, Dime = 10, Nickel = 5, Penny = 1;
    int CoinCount = 0;
    int Remainder = IntCents; // get working value

    // note following using integer divides
    CoinCount = Remainder / Quarter; // max quarters
    Remainder = Remainder % Quarter; // update working value

    CoinCount += Remainder / Dime;   // max dimes
    Remainder = Remainder % Dime;    // update working value

    CoinCount += Remainder / Nickle; // max nickles
    Remainder = Remainder % Nickle;  // update working value

    CoinCount += Remainder;          // final pennys

    return CoinCount;
}