【问题标题】:How do I declare several variables in a for (;;) loop in C?如何在 C 中的 for (;;) 循环中声明多个变量?
【发布时间】:2011-03-21 21:31:54
【问题描述】:

我认为可以在for 循环中声明多个变量:

for (int i = 0, char* ptr = bam; i < 10; i++) { ... }

但我刚刚发现这是不可能的。 GCC 给出以下错误:

错误: 'char' 之前的预期 unqualified-id

真的不能在for循环中声明不同类型的变量吗?

【问题讨论】:

  • 我知道 SO 某处有一个非常相关的问题,但我找不到它......
  • @msw 我真的不认为for(int i = 0, char* ptr = bam)int i; char* ptr; for(i = 0, ptr = bam) 更难阅读
  • 同意,像ptrbam 这样的名字,很难让它不那么可读
  • @msw ...它很可能是为了提问而简化的

标签: c loops for-loop declaration


【解决方案1】:

您可以(但通常不应该)使用本地结构类型。

for ( struct { int i; char* ptr; } loopy = { 0, bam };
      loopy.i < 10 && * loopy.ptr != 0;
      ++ loopy.i, ++ loopy.ptr )
    { ... }

从 C++11 开始,您可以更优雅地初始化各个部分,只要它们不依赖于局部变量:

for ( struct { int i = 0; std::string status; } loop;
      loop.status != "done"; ++ loop.i )
    { ... }

这几乎是可读的,可以真正使用。


C++17 解决了 structured bindings 的问题:

for ( auto [ i, status ] = std::tuple{ 0, ""s }; status != "done"; ++ i )

【讨论】:

  • 丑得要命,但很有效。
  • 哇;我以前从未见过。我敢肯定,如果我使用它,队友会杀了我,但我很想
  • +1:非常不拘一格。我不会这样做,但它很好地揭示了底层语言语义。
  • 当人们说,“仅仅因为你可以做这并不意味着你应该”,他们在谈论这样的事情。不过,它确实有效。
  • @Potatoswatter:有一定的风格,有点像琵琶鱼。它们真的很丑,但人们对它们很着迷。
【解决方案2】:

确实不能同时声明和初始化不同类型的声明符。但这并不特定于 for 循环。如果你这样做,你会得到一个错误:

int i = 0, char *ptr = bam;

也是。 for 循环的第一个子句可以是(C99 §6.8.5.3)“声明”或“无效表达式”。请注意,您可以这样做:

int i = 0, *j = NULL;
for(int i = 0, *j = NULL;;){}

因为i*j 都是int 类型。声明的确切语法在 §6.7

中给出

【讨论】:

    【解决方案3】:

    如果您确实需要将变量留在循环范围内,您可以编写

    { char* ptr = bam; for (int i = 0; i < 10; i++) { ... } }
    

    这有点难看,但可以。

    【讨论】:

    • 这是最好的答案...不幸的是,在编写扩展为 for (...) 的宏时它不起作用(因此宏的用户为正文添加了自己的大括号)。
    【解决方案4】:

    试试这个:

    int i;
    char* ptr;
    for (i = 0, ptr = bam; i < 10; i++) { ... }
    

    【讨论】:

      【解决方案5】:

      你也可以这样做:

      for (int i = 0; i < 10; i++) {
          static char* ptr = bam;
      }
      

      【讨论】:

        【解决方案6】:

        根据http://linuxsoftware.co.nz/cppgrammar.html#for-init-statement,您只能在for-init 语句中获得简单声明或表达式(不允许包含声明)。这意味着答案是否定的(如果我正确分析了 BNF :))

        【讨论】:

        • 链接失效了,你应该把重要的sn-p贴出来。无论如何,您是否从“cpp语法”中分析了 BNF ......对于 C 问题?
        【解决方案7】:

        我认为他们现在教给你的孩子们的语言是为了给你戴上手铐,让你的大脑腐烂,所以你只需保持安静,将乐高积木以非常有限的形式拼凑在一起,这样你就可以拼凑出平庸的作品东西。 C 语言的美妙之处在于你可以遵循规则,并且以一种聪明的方式,得到你想要的东西。这是使用额外初始化程序编写此循环的方法。这是一个工作示例,向您展示如何将扩展循环桥接到第一个循环。您使用第一个盗版它的变量,它们仍然在范围内。您使用虚拟变量使外循环运行一次。一个聪明的编译器会注意到这个事实并使用循环展开器对循环进行核对。所以对你来说,这只是好处。然后第二个数组使用第一个声明和第二个声明中的一些变量并运行到完成。这是一个微不足道的例子,只是意味着您能够理解如何做到这一点,而无需投入一些范围界定的繁重举动。因为这种技术可以在这样编写时与宏一起使用,以创建漂亮的下一代结构枚举,比如“for value in array do”,我有很多。

        #include "stdio.h"
        int
        main(int argc, char **argv)
        {
            const int max=7;
            const char *array[7] = {
            "hello","you","kids","who","don't","know","malloc\n"
            };
        
            for(int i=0,count=max,$=1;$;$=0)
            for(const char **p=array;count<max;i++)
            {
                printf("%s ",p[i]);
            }
        }
        

        这里没有任何遗漏。这种 for 循环与一次性 for 循环连接的技术已被用于嵌入调用以获取此哈希对象的枚举器,并启动枚举,以获取为键和值提取的值,以及方便地创建它们作为用户的无效指针,他只需要命名它们。然后它们被填充,并且枚举将继续,直到完成所有键和值。如果用户在迭代中中断,则 oneshot forloop 的整个级联将按照我们的意愿分崩离析,因为它们可能甚至不存在,因为它们是用编译器可以看到的简单 const ops 构建的,它们将展开循环。所以基本上它可以让你扩展语法来做这样的事情而不会受到惩罚。

        但您需要了解一点 C 语言,并且至少让您的头脑跳出这些天学校用这些玩具语言放置他们的机器人盒子。

        【讨论】:

        • 有趣的是,您的示例不起作用 - 假设您希望它实际打印任何内容。事实上,你甚至没有完全回答这个问题:如果你必须初始化 3 个不同类型的变量,你会使用 2 个“一次性”吗?呃。 Axel Gneiting 的答案非常简单,可以解决所有问题。
        • “玩具语言”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多