【问题标题】:Whats possible in a for loop在 for 循环中有什么可能
【发布时间】:2011-09-06 21:40:36
【问题描述】:

所以今天我去面试了,其中一个问题是以下(C#上下文)。

//Print the output for the following code:
for (int i = 10, j = 0; j <= 10; j++, i--)
{
    if (i > j)
        Console.WriteLine(j.ToString());
}

我以前从未见过这样的结构,我问过我的同事,我工作场所的 5 人中有 4 人也不知道(也许更多的是对我们的反思,但我离题了)。使用一些基本逻辑,我能够正确回答问题,但这些知识从根本上改变了我对如何构建 for 循环的理解。

所以我想我的问题可以归结为这个。

  1. 是否所有基于 C 语法的语言都实现了此功能? IE:C、C++、Java、javascript等
  2. 这个语法从何而来?
  3. 是否还有其他“不为人知”的结构可供 for 循环使用?
  4. 考虑到阅读的难度,编写上述代码是否被认为是不好的做法?
  5. 在现实世界中是否存在需要这种结构的良好示例?

【问题讨论】:

  • 我今年 15 岁,有时我会在自己的项目中使用它:D 对我来说,您的同事也不知道这听起来很奇怪。
  • @Coline:是否应该使用它还有一个问题......
  • 你能做到j.ToString()吗?我认为由于j 是一个原始方法,因此您无法访问不存在的方法。我想 C# 是不同的。

标签: c# java c loops for-loop


【解决方案1】:
for (statement1; statement2; statement3)
{
     /* body */
}

(1) 首先执行statement1

(2) 下一个statement2 被执行。

(3) 如果statement2 的评估为真,则执行主体

(4) 然后statement3被执行。

(5) 从步骤 (2) 开始重复

          |                  +<-----------------+
          |                  |                  ^
          V                  V                  |
 for (  (s1); -------->(s2 true? | false?);    (s3) )
 {                           |       |          ^
                             |       |          |
                             |       |          |
                             V       |          |
                          (body)-----|--------->+
 }                                   |
                                     |
                                     V
                                 (come out)

您显示的结构与上面的正常结构相同。 statement n 可以是任何语句。在您的示例中,您在statement1statement3 中用comma operators 分隔。您可以用逗号分隔任意数量的语句。

通常for 循环与statement1 一起使用并进行初始化,因为它只执行一次。 statement2 用于循环终止条件检查,因为该语句的评估值用于决定是否进入breakout的主体。 statement3 用于更新循环终止变量,因为它在主体之后执行。但通常它们可以以任何方式使用。

首先statement1i=10, j=0; 这会初始化变量。 statement2 中的下一个是 j &lt;= 10,如果为真,则执行正文。执行主体后,将执行statement3,即i--,j++。该循环将迭代11010。但会打印5 次,因为在某一时刻ij 将变得相同,if (i &gt; j) 将评估为 false。

编辑 这是一个可能用于检查回文字符串的示例,但不是很实用,但只是一个示例使用。

  int i, j, n, flag;
  char str[128];

  printf ("\nEnter string: ");
  scanf ("%s", &str);
  n = strlen (str);


for (flag=1, i=n-1, j=0; j<n/2; j++, i--)
{
  if (str[i] != str[j])
  {
    flag = 0;
    break;
  }
}

if (flag)
 printf ("\n\"%s\" is a palindrome");
else
 printf ("\n\"%s\" is not a palindrome");

我们应该始终尝试编写易于阅读且不会造成混淆的代码。这有助于代码编写者以及阅读代码的其他人。

【讨论】:

  • @Martijn,我会帮助你,因为我同意你在“nice ascii”部分的看法。
  • 谢谢你,但最好知道投反对票的原因,然后我会纠正它。
  • 除了 ASCII 有什么好的吗?我认为提问者的主要问题是语句中的逗号分隔语法,我试图在“nice ascii”之后的第 1 段中说明这一点
  • 凤凰你知道ascii-flow吗?它将帮助您绘制ascii-chart...(PS:不要投票给我我在阅读答案后投票。我完全阅读了它)
  • 是的,看过这个网站,很有趣。但是我已经养成了手动绘图的习惯。对于复杂的图表,不要使用 ASCII。 (是的,我知道 SO 文化并且我坚持它。)
【解决方案2】:
  1. Java 和 C# 都使用相同的语法
  2. 语法可能源于 C/C++,它是 Java 和 C# 的“根”
  3. 是的,您的 for 循环还可以有零初始化程序和结束条件。
  4. 这是否是不好的做法实际上取决于它的使用方式。您可以使用这种技术创建非常神秘的代码,但是,这并不意味着如果使用得当,它是完全可以接受的。
  5. 我怀疑!

【讨论】:

  • 秒杀我!我发现令人惊讶的代码的唯一部分是您可以分隔最后以逗号递增的参数。初始逗号语法是变量初始化 iirc 的标准。
  • 4.嗯?尽管对马克西姆和他的同事们应有的尊重,但他们是无知的。既然他们已经看到了,他们就不会再费力地去理解它了,那么这是否意味着它不再是不好的做法了?我知道使用即使你知道它们也难以阅读的结构有点不好,但我不认为 for 循环中的逗号是其中之一。在我看来,宁愿避免这种情况也不愿让你的同事学习这种语言似乎是错误的。
  • 您的#4 充其量是模棱两可的。 特定的代码 可以被认为是不好的,因为它的用法,而不是语法。通常,使用多个变量是非常可接受且易于理解的(在适当的情况下)。
  • Wiz 提出了一个很好的观点——在这种情况下,在循环中只使用一个变量(比如j)并将另一个定义为int i = 10 - j 会更清楚。所以,好吧,那个代码有点繁琐,可能我把“像上面这样的代码”误解为“任何有逗号的代码”,即对 Maxim 来说是新的东西,而不是“变量之间的这种特殊关系"。
【解决方案3】:

在 C 和 Java for 循环中,您可以指定无限(或零)个逗号分隔的初始化程序(相同数据类型)和循环结束操作。

初始化部分实际上只是一个 java 语句; java变量定义如果是同一类型,可以分组,即:

int i = 0;
int j = 0;

相当于:

int i = 0, j = 0;

你可以在循环结束部分做你喜欢的事——用逗号分隔的任意数量的语句。

从java 5开始,还有foreach语法,例如:

List<String> list;
for (String element : list) {
    // do something with the variable element
}

该语法适用于 Iterable 类型,其中包括数组和集合。

【讨论】:

  • 我想我应该指出,带有逗号的多重初始化语法与原始问题中看到的逗号运算符无关。我花了一段时间才意识到你在回答问题的哪些部分:)。
【解决方案4】:
  1. Java 支持这种结构。 在 C 等其他语言中,您可以使用任何表达式而不是条件子句。 该子句不必相关,可以使用不同的变量。

    for({declaration-clause}; {condition-clause}; {expression-clause})
    
  2. 语法只是 C 中声明和表达式符号的扩展。

    int i = 10, j = 0; // a declaration
    j++, i--; // an expression.
    
  3. 不胜枚举。

  4. 如果您无法确定代码的含义,这可能是一种不好的做法。在你的情况下,即使你不会那样写,你也能弄清楚。
  5. 永远不会需要一个 for 循环您总是可以用一个 while 循环替换它,所以,不。

【讨论】:

    【解决方案5】:

    根据我的经验和研究,这种类型的“条件构造”在图像处理中非常常见,比如说(真的,比如说)您需要比较(比如说)相反方向的两个图像之间的像素。甚至还可以在 opp 方向遍历邻居。另一个例子,在这种类型的“条件构造”下,当您需要将 32 位 bmp 转换为 24 位时,反之亦然。 (只是增量会有点差异,例如 i=i+4, j=j+3)。

    【讨论】:

      【解决方案6】:

      针对 5,一个常见的用法是这样的(在 C 中):

      for (size_t pos = 0, end = strlen(something); pos < end; ++pos) {
          if isspace((unsigned)(something[pos])) {
              puts("contains whitespace");
              break;
          }
      }
      

      代替:

      for (size_t pos = 0; pos < strlen(something); ++pos) { ... }
      

      strlen 可以是相对于循环而言代价高昂的任何操作,因此提升它是有意义的。对于strlen,特别是也许,优化器可以自动完成,但一般来说,如果编译器不知道调用做了什么,并且你把它放在循环条件中,它必须评估它每次都是因为它不知道会不会改变。

      当然,你也可以这样写:

      const size_t end = strlen(something);
      for (size_t pos = 0; pos < end; ++pos) { ... }
      

      因此,对于在 for 语句中定义额外变量当然没有严格的要求,并且可以说,无论如何将 end 设置为 const (或 final )有一个微小的优势,但通过定义 pos 和 @987654328 你会失去这些优势@ 一起。不过,有些人更喜欢将“循环变量”(在这种情况下包括“循环常量”)全部定义在 for 语句中,因为它们“属于”它。

      另外,在有人指出之前,在我的 C 示例中,您根本不需要索引:

      for (const char *ptr = something; *ptr; ++ptr) { 
          if isspace((unsigned)*ptr) { ... }
      }
      

      但我们可以假装我们有一个任务,我们将使用计算出的端点进行迭代......

      【讨论】:

        【解决方案7】:

        在 C# 上下文中(我的回答只会考虑),没有像 C++ 和 C 中那样的 逗号运算符,因此从技术上讲,逗号运算符对于 C# 来说是不正确的。

        但 C# for 语句仍被设计为允许人们已经从 C++ 中知道的构造。

        具体规则可在C# 语言规范中的The for statement 部分找到。我们看到for (;;) 语句中的第三个也是最后一个“组件”被定义为statement-expression-list,并且定义了一个statement-expression-list,以递归方式,作为由字符,(逗号)分隔的语句表达式列表。

        这就解释了j++, i-- 部分。

        我们还看到for (;;) 中的第一部分可以是local-variable-declarationstatement-expression-list。第一个也可以包含逗号。声明 int i = 10, j = 0; 也允许作为独立声明(即不在 for 内),并且必须解释为 local-variable-declaration

        【讨论】:

          【解决方案8】:

          输出是: 0 9 8 7 6


          1. 几乎基于 C 语法的语言都实现了此功能。
          2. 此语法源自 c。
          3. 一个部分,两个部分,三个部分,都可能消失。没有任何部分,循环可以正常工作。
          4. 这是一种不好的做法。
          5. 我不知道。

          【讨论】:

          • 认为您的 &lt;&gt; 混淆了 - 输出为 0 1 2 3 4 :)
          猜你喜欢
          • 2019-08-20
          • 2023-03-07
          • 2019-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多