【问题标题】:Putting a composite statement in the condition of a for loop将复合语句置于 for 循环的条件中
【发布时间】:2013-12-06 15:54:13
【问题描述】:

我有一个人为的例子来演示对特定功能的请求 - 我想知道是否有人有一个聪明的技巧来做到这一点。

以下是一个经常遇到的问题:

“打印一系列数字;在它们之间打印一个空格,并在末尾打印一个回车符(但没有空格)。

显而易见的解决方案是将最后一个(或第一个)语句作为特例。我正在考虑如何让这个更高效/更紧凑。

蛮力:

for(ii=0; ii<4; ii++) {
  printf("%d", ii);
  if(ii<3) printf(" "); else printf("\n");
}

请注意,这涉及对一个条件的两次评估。

展开:

for(ii=0; ii<3; ii++) {
  printf("%d ", ii):
}
printf("%d\n", ii);

利用ii 将在我们离开循环时最后一次递增这一事实。

我想要的功能

ii = 0;
while(1) {
  printf("%d", ii);
  ii++;
  if(ii<3) printf(" "); 
  else {printf("\n"); break;}
}

我想知道是否可以在for 语句中进行这项工作。我稍微修改了一下,发现以下工作(令我惊讶的是......它确实需要括号,并且在 ?:, 运算符之间非常难以阅读 - 请参阅 http://codepad.org/wFa2YwCg):

for(ii=0; (ii<3)?(printf("%d ",ii),1):(printf("%d\n",ii),0);ii++);

我实际上是将 for 循环的 evaluate this condition 部分转换为 execute this statement for most of the loop, and this other one for the last pass 语句。

我想知道是否有更好的方法来做到这一点 - 既高效又可读?

【问题讨论】:

  • 如果你只是展开它,为了说明打印的额外ii,你可以这样做:for(ii=0; ii&lt;2; ii++),所以它打印0 1 2而不是3

标签: c for-loop


【解决方案1】:

[这个问题在很多方面都应该被关闭,因为它是基于意见的。]

这个问题经常出现。我总是选择将迭代部分中的指令最小化的解决方案。

{ /*don't pollute the outer scope with ii*/
    int ii;
    for (ii = 0; ii < 3; ++ii/*I've always preferred this to ii++*/) {
        printf("%d ", ii);
    }
    printf("%d\n", ii);
}

三元组,if 语句等。 只是混淆事物。在我看来。

【讨论】:

  • 这是我的“展开”版本的代码。我特别要求在for 循环中使用一个构造,该构造在最后一次迭代中执行不同的操作。我意识到这可能是一个“我们能不能把本可以做得好的事情做得不好”类型的问题——但我很好奇是否有我遗漏的技巧。
  • @Floris:事实上,除了我对整个事情进行范围之外,这在很大程度上是不同的。我向你保证,你不会错过任何其他技巧:你不能再缩短 printf
  • 我喜欢使用大括号来创建ii 的本地实例。我不是在征求“意见”——我是在要求一个非常具体的构造,它将特定功能放入 for 循环条件中。 “高效”是客观的——每次循环迭代只评估一个条件;我想你可以争辩说“可读”有点主观,但我目前的“解决方案”显然没有通过可读性测试......
【解决方案2】:

对于这种情况,我使用了以下类型的构造。它效率不高(每次迭代仍然有一个条件),但我喜欢它,因为它会产生一个 printf

char *sep = " ";
for(ii=0; ii<4; ii++) {
  if ( ii == 3 )
    sep = "\n";
  printf( "%d%s", ii, sep );
}

【讨论】:

  • 这更接近我想要的。它仍然涉及对两个 if 语句的评估。
  • 如果我要使用它,我会使用char sep=' '; 等。但我不知道如何将它塞进for 条件中。
  • @Bathsheba - 你很宽宏大量。
  • @Floris 它确实反映了这个主题基于意见的性质
【解决方案3】:

“蛮力”和三元条件解具有相同的复杂性,但第二个“可读性”较差。

你可以做一个简单的方法打印:

 void print() {
    int i = 0;
    for(i=0; i != size - 1; ++i) {
      printf("%i ",i);
    }
    printf("%i\n", i);
 }

我认为它也高效且可读。
通过这种方式,您可以减少 cyclomatic complexity 的算法。

【讨论】:

  • 你写的真的等同于我的“展开”代码(但你有一个!=,我使用&lt;条件)。我知道这行得通 - 我希望有别的东西。
  • @Floris 事实上是我更喜欢的方式,一个没有条件(=> 没有圈复杂度)的简单 cicle 用“大小”概括 cicle。
  • @TonyHopkinson 你能扩展你的评论吗?我不明白。
  • @TonyHopkinson 我仍然对您的评论感到困惑。请参阅codepad.org/O988cB0p - 如果 size==1,这可以正常工作。我想如果 size==0 它会失败。但这不是我的问题。
  • 你知道我在我的回答中做了不必要的测试。你没有因此发表评论。 :(
【解决方案4】:

为了可读性和性能,我认为可以使用以下代码:

for (ii = 0;; ii++)
{
    printf("%d", ii);
    (ii < 3) ? (putchar(' ')) : ({ putchar('\n'); break; });
}

其实上面的代码和你上一个代码差不多。它是可读的,并且在每个增量中仍然有一个条件评估。

【讨论】:

  • 我同意这是我最后一个(密集和“一次写入,从不读取”)版本的“更易读”版本。我喜欢以for 开头的方式仍然宣布“这是一个将在某个时候终止的循环” - 但您必须阅读到最后才能弄清楚它是如何终止的。我喜欢它足以给它投票 - 不足以接受它作为答案。
【解决方案5】:
int numberoftimes = 4

if numberoftimes > 1
{
  for(ii=0; ii<numberoftimes - 1; ii++) 
  {
    printf("%d ", ii);
  }
}
printf("%d\n", numberoftimes - 1);

要么在循环中每次都测试,要么先测试一次......

【讨论】:

  • 我认为这不需要额外的测试。如果条件在第一次迭代中失败,内部循环将不会执行。
  • 很好看的@Floris,很高兴看到我们中的一个人还醒着。 :)
【解决方案6】:

这是一种需要单独初始化传递的方法,但它的for 循环稍微干净一些。数组 sepsarray 包含您想要的分隔符(在此示例中,逗号以便您可以看到它们)。 sepsarray 的最后一个元素后跟一个终止循环的'\0'

#include <stdio.h>

#define MAXNUM 5
  //print up to this 

void main() {
  char sepsarray[256] = {0}; //256=arbitrary max size
  int i;
  char *seps=sepsarray;

  for(i=0;i<MAXNUM;++i) sepsarray[i]=',';   //fill in the separators
  sepsarray[i]='\n';    //the last separator

  for(i=0; printf("%d%c",i,*seps++),*seps; i++) /* pretend to do nothing */ ;
}

输出:

0,1,2,3,4,5

几乎没有 IOCCC 材料,但是嘿... :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    • 2014-08-30
    • 2022-11-26
    相关资源
    最近更新 更多