我对我遇到的递归C函数的行为感到困惑.下面是代码片段:

#include <stdio.h>

int sum_up_to_n(int n, int curr_sum) {
    if (n == 0) {
        return curr_sum;
    }
    sum_up_to_n(n - 1, n + curr_sum);
}

int main() {
    printf("%d", sum_up_to_n(3, 0));
    return 0;
}

尽管在sum_up_to_n函数中如果case失败时没有return语句,但它似乎产生了正确的输出,没有任何错误.有人能解释一下为什么会发生这种行为吗?缺少的返回语句不应该导致错误吗?或者至少编译器应该警告.我希望能深入了解这个代码的功能.

推荐答案

下面的操作可能会"起作用"1,但这仅仅是因为可用于未定义行为的选项之一是一个看起来起作用的函数.它不会在某个时候随机地"工作",你会感到沮丧.

int sum_up_to_n(int n, int curr_sum) {
    if (n == 0) {
        return curr_sum;
    }
    sum_up_to_n(n - 1, n + curr_sum);
}

但还有希望!如果我在启用警告的情况下编译它,我们可以看到编译器发现了这个bug.

$ cat test.c
int sum_up_to_n(int n, int curr_sum) {
    if (n == 0) {
        return curr_sum;
    }
    sum_up_to_n(n - 1, n + curr_sum);
}

$ gcc -c  -Wall -Wextra -Wpedantic test.c
test.c: In function ‘sum_up_to_n’:
test.c:6:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

可以忽略(但不应该).如果我告诉编译器处理as个警告错误,它们就不能再被忽略了.

$ gcc -c  -Wall -Wextra -Wpedantic test.c -Werror
test.c: In function ‘sum_up_to_n’:
test.c:6:1: error: control reaches end of non-void function [-Werror=return-type]
 }
 ^
cc1: all warnings being treated as errors

在启用警告的情况下编译将帮助您捕获代码中的许多其他潜在问题.请记住,如果你收到了一长串警告或错误来解决第一个first,然后重新编译.随后的问题可能已经从第一个问题中级联下来,"修复"随后的问题可能没有必要,甚至可能 有害.


[1]这里的"工作"是指"不能检测到故障"."

C++相关问答推荐

使用sd-设备列举设备导致seg错误

如何将匿名VLA分配给指针?

C中的ATONE会扰乱SEN/CLUTE GMS应用程序中的其他字符串

使用单个字节内的位字段

在C中使用动态内存分配找到最小的负数

为什么内核使用扩展到前后相同的宏定义?

模拟shell并运行.sh文件

非常大的数组的大小

CSAPP微型shell 实验室:卡在sigprocmask

Sizeof(&Q;字符串&Q;)的正确输出是什么?

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

For循环中的变量行为不符合预期.[C17]

当b是无符号字符时,int a=(b<;<;2)>;>;2;和int a=b&;0x3F;之间有什么区别?

C将数组传递给函数以修改数组

为什么这个分配做得不好呢?

在C中,为什么这个带有递增整数的main函数从不因溢出而崩溃?

共享内存未授予父进程权限

如何用用户输入的多个字符串填充数组?

为什么需要struct in_addr

当循环变量在溢出时未定义时,可以进行哪些优化?