为嵌套循环声明虚拟变量的更好方法是什么?

Which is the better way to declare dummy variables for nested loops?

  1. 方法 1 的优点是文件大小稍小,因为源代码中的文本字符较少:

    int i, j;
    for (i = 0; i < numRows; i++)
        for (j = 0; j < numCols; j++)
        //<some code here>
    
  2. 方式二的优点是局部变量作用域较小

    int i;
    for (i = 0; i < numRows; i++)
    {
        int j;
        for (j = 0; j < numCols; j++)
        //<some code here>
    }
    

即使在当今的现代计算机中优化的差异可以忽略不计,哪种方法被认为是 "better" 代码?


编辑以澄清此问题不是重复的:

此题基于当前的 C11 标准,该标准不允许这样的语法:

for (int i = 0; i < numRows; i++)

在 C++ 和 C99 中,这种语法是完全可以接受的,而 C11 不允许在 for 语句中声明变量。


编辑更正错误信息:

我以为我使用的是 C11,因为我最近从 CodeBlocks 下载了编译器,所以这就是为什么我说 C11 不允许在 for 语句中声明变量。但事实证明我实际上使用的是 C90,这是我问题的根源。

第二种方法是最好的方法

  1. 可以使用低内存
  2. 允许在任何其他循环中需要时再次使用同一变量

为了纯粹的紧凑性和范围的限制,我会使用:

for (size_t i = 0; i < numRows; i++) {
    for (size_t j = 0; j < numCols; j++) {
    //<some code here>
    }
}

请注意,size_t 的使用似乎是数组索引。 size_t 类型是 unsigned 整数类型,保证能够保存任何数组索引。只是风格问题,但我还建议在所有循环体周围使用大括号。这使得您不太可能因不可避免的更新和更改而破坏您的代码。

通过养成这样声明具有块作用域的循环变量的习惯,您可以强迫自己选择在代码的其他地方使用存储在循环变量中的值。

这似乎是一个品味问题,没有任何确定的答案,但我会告诉你我的看法:

以目前的计算机,保存几个字符的源代码简直微不足道。事实上,我想即使我在 1976 年在 VAX 11/780 上学习 C 时也会这么说。

我更喜欢第二个例子,因为目前的偏好是声明变量尽可能接近第一次使用。在 C++ 中,您甚至可以将循环变量的声明放在 for 语句中:

for (int i = 0; i < numRows; i++) {
   for (int j = 0; j < numCols; j++) {
      ...
   }
}

但这仍然只是个人喜好问题:相信如果变量的声明接近于使用,程序将更具可读性。

这两种方法都不是首选。

两个常见的编码指南是 (1) 确保没有变量存在的时间超过它需要的时间,以及 (2) 不要将一个变量用于不止一件事。遵循此类准则可以减少(通常但并非总是消除)以非预期方式意外使用变量,因此有助于避免细微的编程错误。

在您的第一种情况下,ij 都将继续存在,直到封闭范围结束 - 这意味着它们在循环完成后仍然存在。这最大限度地增加了后续代码(在该封闭范围内)意外重用 ij 用于另一个目的的机会(例如,当意图是使用另一个变量时)。这样的错误通常很难找到。

第二种情况也有同样的问题,除了i。不过,即使一个变量出现这样的问题也是个坏消息。

我可能会使用像

这样的结构
// unintentionally using i or j here will cause a compilation error

for (int i = 0; i < numRows; i++)
{
    // unintentionally using j here will cause a compilation error

    for (int j = 0; j < numCols; j++)
    {
       //<some code here>
    }

    // unintentionally using j here will cause a compilation error
}

// unintentionally using i or j here will cause a compilation error

(我为说明这一点而插入的注释使它更难读,但在实践中通常不需要这样的注释)。

这确保了 ij 都不存在于外循环之外。这也意味着 j 不能在外循环中意外使用。实际上,当需要输入 j 时很容易输入 i(反之亦然)——例如,它们在 QWERTY 键盘上靠得很近。 ij 在视觉上看起来也很相似,所以视觉代码检查经常会错过这样的错误。但是,使用这样的方法,编译器将检测到此类拼写错误。如果可以选择,最好让编译器找出错误,而不是让人类费力地找到错误。

当然,这并不能阻止 ij 在内部循环中的误用或互换 - 但这是指南通常鼓励使用比 [=11 更多信息的名称的原因之一=] 和 j - 滥用视觉上不同的名称更容易被普通人发现。