for循环中变量增加的奇怪行为

时间:2019-11-11 17:28:16

标签: c

编辑:这不是我的代码,这是考试的一部分。

这是输出:

60 -3 //从-5到-3
59 0 //从-3到0
58 3
57 6
2

我不知道为什么在第一个循环中将“ i”变量增加两次,而在第二个循环中将变量增加三倍。

int a=61,i=-5;

for(int *p=&i;(a++,(*p)++)?(++(*p),(a--)-1):((*p)+=3,a-1);(*p)++){
    --a;
    printf("%d %d \n",a,*p);
    if(*p>3){
        a=(!(--a)&&a++)?3:2;
        break;
    }
    else continue;
}  

printf("%d\n",a);  

3 个答案:

答案 0 :(得分:1)

与这样的代码唯一有意义的事情(除了在此处向作者说不允许的单词外)是重写它。 else continue可以删除。它什么也没做。

然后我们去找野兽(a++,(*p)++)?(++(*p),(a--)-1):((*p)+=3,a-1)。这将在每个循环的开始执行,因此我们可以这样重写它:

bool cond = (a++,(*p)++)?(++(*p),(a--)-1):((*p)+=3,a-1);
for(int *p=&i; cond; (*p)++){
    cond = (a++,(*p)++)?(++(*p),(a--)-1):((*p)+=3,a-1);

    --a;
    printf("%d %d \n",a,*p);
    if(*p>3){
    a=(!(--a)&&a++)?3:2;
    break;
    }
}

现在,当它从标题中删除时,我们可以开始反汇编它了。首先,将a++提取为if语句:

a++;
if((*p)++)
    cond = (++(*p),(a--)-1)
else
    cond = ((*p)+=3,a-1);

已经看起来更加清晰了。现在,让我们摆脱那些逗号:

if((*p)++) {
    ++(*p);
    cond = (a--)-1;
}
else {
    (*p)+=3;
    cond = a-1;
}

让我们继续分离

if((*p)++) {
    (*p)++; // Does not make a difference here, but it's easier to not mix pre and post
    a--;
    cond = a;
}
else {
    (*p)+=3;
    cond = a-1;
}

就我们仅仅通过机械分解就可以得到。为了进一步发展,我们需要三思。因此,让我们继续下一个a=(!(--a)&&a++)?3:2;,我们也将对其进行简化。

--a; // Will be executed no matter what
if(!a) {
    a++; // Will only be executed if !(--a) evaluates to true
    a = 3; // But it does not matter since we are reassigning a
} else {
    a = 2;
}

这将在简化后给出此代码。

bool cond;

a++;
if((*p)++) {
    (*p)++;
    a--;
    cond = a;
} else {
    (*p)+=3;
    cond = a-1;
}

for(int *p=&i; cond; (*p)++){
    a++;
    if((*p)++) {
        (*p)++;
        a--;
        cond = a;
    } else {
        (*p)+=3;
        cond = a-1;
    }

    --a; 
    printf("%d %d \n",a,*p);
    if(!a) {
        a = 3; 
    } else {
        a = 2;
    }
}

printf("%d\n",a);  

现在实际上可以对此进行推理了,只需一步一步在纸上执行此代码就应该很容易。

答案 1 :(得分:0)

在for循环声明末尾的(*p)++语句不会在第一次迭代中执行。它只能在两个连续的迭代之间执行。

答案 2 :(得分:0)

首先,int a=61,i=-5;给出a = 61且i = −5。

然后,for的初始子句int *p=&ip设置为指向i。从这一点开始,我们可以将*p等同于i

然后计算for(a++,(*p)++)?(++(*p),(a--)-1):((*p)+=3,a-1)的控制表达式。其最高/最外面的运算符是? :。该(a++,(*p)++)的第一个操作数被求值。这会将a设置为62,并将i设置为-4。来自逗号运算符的结果是增量之前的i*p)的值,所以它是-5。

? :操作中使用-5进行选择。由于它不为零,因此将评估?:之间的操作数。那就是(++(*p),(a--)-1)。这会将i设置为-3,将a设置为61。值是a在增量减1之前,即62-1 =61。因此表达式为非零,表示循环应该继续。

程序控制流到for的主体中,其中--a递减a到60。

然后printf向我们显示a为60,而i为-3。

测试*p>3为假,因为i为-3,所以执行了continue

这将导致对for的迭代表达式求值。即(*p)++,因此i设置为-2。

然后对控制表达式求值。和以前一样,对? :的第一个操作数(a++,(*p)++)进行求值。这会将a设置为61,将i设置为-1,表达式的值为-2。

再次计算第二个操作数(++(* p),(a-)-1)。将i设置为0,将a设置为60,其值为59。

在身体内部,--a减少a至59。

printf向我们显示a为59,i为0。

再次*p>3为假,因此执行了continue

这将控制迭代表达式(*p)++,该表达式将i设置为1。

然后从? :的第一个操作数开始计算控制表达式。现在(a++,(*p)++)a设置为60,将i设置为2,表达式值为1。

计算? :的第二个操作数(++(* p),(a-)-1),将i设置为3,将a设置为59 ,表达式值为59,因此循环继续。

--a将a设置为58。

printf向我们显示a是58,而i是3。

再次*p>3为假,因此执行了continue

这将控制迭代表达式(*p)++,该表达式将i设置为4。

然后从? :的第一个操作数开始计算控制表达式。现在(a++,(*p)++)a设置为59,将i设置为5,表达式值为4。

求值? :的第二个操作数(++(* p),(a-)-1),将i设置为6,将a设置为58 ,表达式值为58,因此循环继续。

--a将a设置为57。

printf显示a是57,i是6。

现在*p>3是正确的,因此if内部的语句将被执行。

这些以a=(!(--a)&&a++)?3:2;开头。在这里--aa设置为56并求出该值。然后!对其进行逻辑反转,生成0。这将导致&&生成0,而不计算其第二个操作数。因此? :的第一个操作数为0,这导致? :的第三个操作数被求值。该操作数为2,因此是分配给a的值。

最后的printf向我们显示了a的当前值2。