C 斐波那契程序中的错误

C 斐波那契程序中的错误,c,expression,fibonacci,C,Expression,Fibonacci,我试图用以下方法在C中找到第k个斐波那契数: int fibk(int k) { if(k == 1 || k== 2) return 1; int i,a = 1,b = 1; for(i=3;i<=k;i++) { b = a + (a=b); } return b; } 所以我试着: b = a + (a=b); 但该代码首先将a的值更改为b,然后简单地将其添加回自身,有效地将

我试图用以下方法在C中找到第k个斐波那契数:

int fibk(int k)
{
    if(k == 1 || k== 2)
        return 1;

    int i,a = 1,b = 1;

    for(i=3;i<=k;i++)
    {
            b = a + (a=b);
    }

    return b;
}
所以我试着:

     b = a + (a=b);
但该代码首先将
a
的值更改为
b
,然后简单地将其添加回自身,有效地将其值加倍,而不是将其添加到以前的值


为什么交换代码可以工作,但找不到下一个斐波那契数的代码?

对“a”的操作可能没有定义,所以“交换代码”实际上“不工作”。一种方法是,可以使用
tem
(临时)变量来保持
b
的值。试着这样做:

tem = a + b;
a = b;
b = tem;

回答这个问题:两个
a=a+b-(b=a)
b=a+(a=b)具有未定义的行为。C既不指定评估顺序,也不指定副作用(如变量赋值)发生的顺序,除非有明确的序列点。因此,在上述两个表达式中,右侧的赋值可能发生在访问赋值变量的值之前、之后或期间。(while案例包括在多条机器指令中完成赋值的情况,可能是因为变量太大,无法在单个指令中存储或加载。)

“未定义的行为”就是——未定义。它可能模仿你错误预期的行为;它可能只是以意想不到的顺序做事情;它可能产生无法理解的垃圾;或者它可以被编译器简单地删除,这样就不会发生任何事情。或者许多其他的可能性。而且也不能保证一个行为未定义的程序与明天编译的同一个程序的行为相同


作为一个小奖励,由于您似乎试图避免使用临时变量,这里有一个不同的fibonacci hack,没有临时变量,也没有UB:

int fibk(int n) {
  int a = 1, b = 0, i = n - 1;
  for (; i > 0; i -= 2) {
    b += a;
    a += b;
  }
  return i ? b : a;
}

因为它会展开循环,所以可能会稍微快一点。再说一次,它可能不会

b=a+(a=b)具有未定义的行为:您“同时”修改和读取
a
(在读取和写入之间没有序列点)。那么用于交换的代码如何工作呢?它没有,至少没有任何定义。不要将观察到的行为与定义的行为混淆。@RahulKejriwal它不“工作”。它可能假装在工作,但不管怎么说它坏得可怕。@RahulKejriwal,它又不“工作”。它可能对你有用。正如WhozCraig所指出的:你把观察到的行为和定义的行为混淆了。
int fibk(int n) {
  int a = 1, b = 0, i = n - 1;
  for (; i > 0; i -= 2) {
    b += a;
    a += b;
  }
  return i ? b : a;
}