在C ++ for循环之前从未见过

时间:2012-07-31 11:19:36

标签: c# c++ for-loop

我正在将C ++算法转换为C#。 我遇到了这个循环:

for (u = b.size(), v = b.back(); u--; v = p[v]) 
b[u] = v;

它在C ++中没有错误,但在C#中没有错误(不能将int转换为bool)。 我真的无法弄清楚这个循环,条件在哪里?

有人可以解释一下吗?

PS。只是为了检查,使VECTOR适应LIST     b.back() 相当于     B [b.Count-1] ?

12 个答案:

答案 0 :(得分:318)

for循环的条件位于中间 - 两个分号;之间。

在C ++中,几乎可以将任何表达式作为条件:任何计算结果为零的都意味着false;非零意味着true

在您的情况下,条件为u--:当您转换为C#时,只需添加!= 0

for (u = b.size(), v = b.back(); u-- != 0; v = p[v]) 
    b[u] = v; //                     ^^^^ HERE

答案 1 :(得分:165)

很多准确的答案,但我认为值得写出等效的while循环。

for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;

相当于:

u = b.size();
v = b.back();
while(u--) {
   b[u] = v;
   v = p[v];
}

在转换为C#时,您可能会考虑重构为while()格式。在我看来,它更清晰,不是新程序员的陷阱,同样有效。

正如其他人指出的那样 - 但要完成我的回答 - 要使其在C#中运行,您需要将while(u--)更改为while(u-- != 0)

...或while(u-- >0)以防万一你开始消极。 (好的,b.size()永远不会是否定的 - 但考虑一个普遍的情况,也许其他东西初始化了你。)

或者,为了使它更清晰:

u = b.size();
v = b.back();
while(u>0) {
   u--;
   b[u] = v;
   v = p[v];
}

最好是明确而不是简洁。

答案 2 :(得分:65)

条件为u--;,因为它位于 for 指令的第二个位置。

如果u--;的值与0不同,则将其解释为true(即隐式转换为布尔值true)。相反,如果其值为0,则将其转换为false

这是very bad code

更新:我在这个blog post中讨论了“for”循环的写法。其建议可归纳为以下几段:

  

for循环是实用的,可读的(一旦习惯了)和   简洁的构造,但你需要很好地使用它。因为它不常见   语法,以过于富有想象力的方式使用它并不是一个好主意。

     

for循环的所有部分都应该简短易读。变量名称   应该选择使其易于理解。

这个例子显然违反了这些建议。

答案 3 :(得分:23)

这将是你的循环的C#形式。

// back fetches the last element of vector in c++.
for (u = b.size(), v = b.back(); (u--) != 0; v = p[v]) 
{      
  b[u] = v;      
}

只需替换size()和back()的等效项。

它的作用是反转列表并存储在数组中。 但是在C#中我们直接为此设置了系统定义的函数。所以你也不需要写这个循环。

b = b.Reverse().ToArray();

答案 4 :(得分:14)

条件是u--的结果,它是u在递减之前的值。

在C和C ++中,int 可以通过隐式执行!= 0比较来转换为bool(0是false,其他一切都是{{1 }})。

trueb.back()时容器中的最后一个元素,b[b.size() - 1]

答案 5 :(得分:14)

u = b.size(), v = b.back()

是初始化。

u--

是条件。

v = p[v]

是迭代

答案 6 :(得分:11)

在C中,“布尔”上下文中的所有非零都是true,例如循环结束条件或条件语句。在C#中,您必须明确地进行检查:u-- != 0

答案 7 :(得分:6)

正如其他人所说,C ++隐式转换为布尔值的事实意味着条件为u--,如果值为非零,则为真。

值得补充的是,你在问“有条件的地方”时有一个错误的假设。在C ++和C#(以及其他类似的语法语言)中,您可以使用空条件。在这种情况下,它总是计算为true,因此循环会一直持续,或者直到某个其他条件退出(通过returnbreakthrow)。

for(int i = 0; ; ++i)
  doThisForever(i);

实际上,for语句的任何部分都可以省略,在这种情况下它只是没有执行。

通常,for(A; B; C){D}for(A; B; C)D;会变为:

{A}
loopBack:
if(!(B))
  goto escapeLoop;
{D}
{C}
goto loopBack;
escapeLoop:

A,B,C或D中的任何一个或多个都可以省略。

因此,有些人赞成for(;;)无限循环。我这样做是因为虽然while(true)更受欢迎,但我将其视为“直到真相结束才真实”,与我的阅读for(;;)相比,这听起来有点像世界末日。“

这是一个品味问题,但因为我不是世界上唯一喜欢for(;;)的人,所以值得知道这意味着什么。

答案 8 :(得分:4)

所有答案都是正确的: -

for循环可以多种方式使用,如下所示:

Single Statement inside For Loop
Multiple Statements inside For Loop
No Statement inside For Loop
Semicolon at the end of For Loop
Multiple Initialization Statement inside For
Missing Initialization in For Loop
Missing Increment/Decrement Statement
Infinite For Loop
Condition with no Conditional Operator.

答案 9 :(得分:4)

for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;

在上面的代码中,uv初始化为b.size()b.back()

每次检查条件时,它也会执行递减语句,即u--

for变为u时,0循环将退出。

答案 10 :(得分:3)

C#中遇到的错误清除了疑点。 for循环搜索

  

FALSE

终止条件。而且我们知道,

  

(BOOL)FALSE =(int)0

但C#不能像C ++那样自行处理。所以你要搜索的条件是

  

û -

但你必须明确地将C#中的条件赋予

  

u--!= 0

  

你 - > 0

但仍然试图避免这种编码实践。

  

while循环

上面回答的是

中最简化的版本之一
  

for循环。

答案 11 :(得分:3)

如果你已经习惯了C / C ++,那么这段代码就不那么难读了,虽然它非常简洁而且不是很好的代码。因此,让我解释一下Cistic比其他任何东西都要多的部分。首先,C for循环的一般语法如下所示:

for (<initialization> ; <condition>; <increment>)
{
    <code...>
}

初始化代码运行一次。然后在每个循环之前测试条件,最后在每个循环之后调用增量。因此,在您的示例中,您会发现条件为u--

为什么u--在C而不是C#中作为一个条件?因为C隐含地转换了很多东西而且会引起麻烦。对于数字,任何非零的都是真,零是假。所以它会从b.size() - 1倒计数到0.在条件中有副作用有点烦人,最好将它放在for循环的增量部分,尽管很多C代码这样做。如果我正在写它,我会更喜欢这样做:

for (u = b.size() - 1, v = b.back(); u>=0; --u) 
{
    b[u] = v;
    v = p[v]
}

原因是,至少对我而言,它更清楚。 for循环的每个部分都是它的工作,没有别的。在原始代码中,条件是修改变量。增量部分正在做一些应该在代码块等中的东西。

逗号运算符也可能会引发循环。在C中,就编译器而言,x=1,y=2之类似于一个语句,并且适用于初始化代码。它只是评估每个部分并返回最后一个部分的值。例如:

std::cout << "(1,2)=" << (1,2) << std::endl;

会打印出2。