如何为找零的最低硬币固定“非无效功能的末端”?

时间:2019-05-25 06:30:20

标签: c recursion

问题是,假设找回的硬币数量为25c,10c,5c和1c,则找到找零给定金额的硬币的最小数量。

我用C实现了递归的解决方案,但是不知何故它不断抛出“错误:控件可能到达非void函数的结尾”。我是C语言的新手,所以我不太清楚发生了什么。 任何帮助是极大的赞赏!这是我的代码:

#include <cs50.h>
#include <stdio.h>
#include <math.h> 

int processChange(float change){
 int centsChange = round(change*100);
 int arr[4] = {25,10,5,1};

  for(int i=0;i<4;i++){
    int numCoins =0;
    int remainder = centsChange%arr[i];
    if(remainder==0){
        numCoins = (centsChange - remainder)/arr[i];
        return numCoins;
    }


    if(centsChange ==1){return 1;}//base case
    if(centsChange>=arr[i]){
       numCoins = (centsChange - remainder)/arr[i]+ processChange(remainder/100);
        return numCoins;
    }


   } 
}

 int main(){
   float change;
    do
    {
        change = get_float("Enter the changed owed\n");
    }while (change<0);

   printf("Minimum number of coins returned is %d\n", processChange(change));

}

1 个答案:

答案 0 :(得分:3)

forprocessChange循环中的代码执行以下操作:

  • 如果remainder为零,请进行计算并返回。
  • 如果centsChange为1,则返回。
  • 如果centsChange至少为arr[i],请进行计算并返回。
  • 否则,请到达for循环的结尾并继续进行迭代。

据编译器所知,i的值将达到4,并且控制将离开for循环。那时,控制将流到该函数的末尾,那里没有return语句。因此,编译器警告您控件将到达非空函数的末尾。 (“非无效函数”是返回类型不是void的函数。processChange的返回类型是int。)

解决此问题的一种方法是在函数末尾插入return语句。

另一种方法是针对这种情况禁用编译器警告,您可以使用-Wno-return-type命令行开关对GCC和Clang进行此操作。

我们可以看到控件实际上无法离开for语句,因为当i为3时,arr[i]为1,因此centsChange % arr[i]必然产生零,并对其进行赋值到remainder,导致代码流入上述第一种情况。使用GCC和Clang,您可以通过在函数的最后一条语句中插入__builtin_unreachable();来通知编译器。这告诉编译器,程序中各种情况的组合都无法在逻辑上达到代码中的这一点。 (当控件不是正确的位置时使用此编译器功能,将破坏程序。)

请注意,由于上述原因,控制无法离开for循环这一事实意味着centsChange == 1基本情况是不必要的。 remainder == 0 必须必须满足的事实意味着它可以作为基本情况。

尽管此分析按原样讨论了代码,但是经验丰富的程序员将对代码进行重组,因此上述解决方案都不是必需的。有时,各种复杂性会促使我们使用代码,而编译器无法推断出执行中从未达到某个特定点,但我们知道确实如此,在这种情况下可以使用上述变通方法。但是,这不是其中之一。该代码非常简单,可以进行重组,从而使控制流对于编译器而言更加简单和明显。