C语言 为什么这段代码的最后一次迭代不能正常工作?

ttcibm8c  于 2023-10-15  发布在  其他
关注(0)|答案(4)|浏览(126)

我正在写一个程序,打印前50个斐波那契数字,从1和2开始。数字必须用逗号分隔,后面跟一个空格,除了最后一个数字,它应该以一个新行结束。
我试过的代码:

int main(void)
{
    int fib[50];
    fib[0] = 1;
    fib[1] = 2;
    int i;

    for (i = 0; i < 50; i++)
    {
        if (i == 0)
        {
            printf("%d ,", fib[0]);
        }
        else if (i == 1)
        {
            printf("%d ,", fib[1]);
        }
        else if (i == 49)
        {
            fib[i] = fib[i-1] + fib[i-2];
            printf("%d", fib[i]);
        }
        else 
        {
            fib[i] = fib[i-1] + fib[i-2];
            printf("%d ,", fib[i]);
        }
    }
    printf("\n");
    return (0);
}

我得到的结果是:

h5qlskok

h5qlskok1#

您的代码中存在多个问题:

  • 你必须包含<stdio.h>才能正确使用printf。您可能忘记了问题代码中的#include行,但正如所发布的那样,该代码具有未定义的行为。
  • 在绝大多数当前系统上,int类型不够大,无法容纳最大为49的斐波那契数。您应该使用long long intunsigned long long int类型,它们保证可以处理最大为263-1的数字(分别为264-1)。
  • 格式字符串"%d ,"不正确:空格应该出现在**逗号之后,而不是之前。
  • 发布的输出与代码不一致:有些数字大于231-1。下面是我用你的代码得到的输出:

但是请注意,有符号整数溢出的行为是未定义的,因此其他行为是可能的,尽管不太可能。

  • 不需要数组,你可以只使用3个变量并循环它们。
  • 这是更容易使一个特殊的情况下的前2个数字和输出,和一个空格之前的每一个下一个数字。
  • 是否要打印以1, 20, 1或甚至1, 1开头的Fibonacci sequence是一个约定问题。意大利数学家Fibonacci在他的时代(公元1202年)使用1, 2,因为他在他的Liber Abaci中讨论了兔子的数量增长。事实上,斐波那契在欧洲引入了以10为基数的符号,并从他成长的阿拉伯世界引入了zero的概念。手稿图片中的数字使用Indo-Arabic numerals的变体显示序列号。在现代,更传统的是从0, 1开始序列,并将其命名为 F0F1

以下是修改后的版本:

#include <stdio.h>

int main(void) {
    unsigned long long a = 1, b = 2;

    printf("%llu, %llu", a, b);

    for (int i = 2; i < 50; ++i) {
        unsigned long long c = a + b;
        printf(", %llu", c);
        a = b;
        b = c;
    }
    printf("\n");
    return 0;
}
bfhwhh0e

bfhwhh0e2#

我只能假设你遇到了int溢出。int值的范围有限(特定于平台)。试试long long。你也可以把这里的逻辑简化一点。例如,您可以在循环之前打印前两个值;在此之后,逻辑是规则的并且不需要if(s)。比如

int i;
long long fib[50];
fib[0] = 1;
fib[1] = 2;

printf("%lld, %lld", fib[0], fib[1]);
for (i = 2; i < 50; i++)
{
    fib[i] = fib[i-1] + fib[i-2];
    printf(", %lld", fib[i]);
}
printf("\n");
7uzetpgm

7uzetpgm3#

除了整数溢出的注意事项之外,您还可以通过使用分隔符并在第一次迭代后更改它来以简洁的方式处理逗号,而不是测试是否在最后一次迭代中。
如果你只是输出斐波那契数,也没有必要存储一个数组。相反,我们可以只跟踪两个数字,并在每次迭代中更新它们。(0, 1) -> (1, 1) -> (1, 2) -> (2, 3) -> ...如果我们遵循这个算法,每次迭代的第一个数字是下一个斐波那契数:0 -> 1 -> 1 -> 2 -> ...

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint64_t a = 0, b = 1;
    const char *sep = "";

    for (int i = 0; i < 50; ++i) {
        printf("%s%lu", sep, a);
        sep = ", ";
        uint64_t c = a;
        a = b;
        b += c;
    }

    printf("\n");
}

其输出:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049
ebdffaop

ebdffaop4#

'long long'占用更多的字节来存储值,可以避免这种情况下的溢出。

相关问题