2

while (k >= 0 && arr[k] > 0) 

安全的?

当 k 在范围内并且 arr[k] > 0 时它会循环。但我不知道这是否是编码的好习惯。我知道如果我们这样做

while (arr[k] > 0 && k >= 0) 

这将是一场灾难。

4

4 回答 4

6

&&短路是安全的。如果k小于零,则不会对其进行索引arr

这可能是不安全的,因为您的 while 循环体可能不会k正确递减,从而导致无限循环。k或者如果超出arr's bounds可能不安全。

于 2012-07-17T13:58:40.333 回答
4

您还应该关心数组大小:

while (k >= 0 && k < arr.length && arr[k] > 0) 

将是一个更安全的代码。

于 2012-07-17T14:01:00.567 回答
3

是的,这是一个很好的做法。事实上,这也是发明短路 &&算子的部分原因。运算符从左到右计算其子表达式,并在找到错误的子表达式时停止。这正是您想要的;运算符&&允许您在一行中表达这一点。

于 2012-07-17T13:58:37.187 回答
0

关于表达:

而 (k >= 0 && arr[k] > 0) { ... }

不,这不安全。

该表达式k >= 0 && arr[k] > 0在某种程度上是安全的,它确保仅arr[k]使用正索引 of (因为在这些情况下,不会评估第二个操作数&&的快捷方式值)。k < 0arr[k] > 0

请注意,不能保证索引超出范围(例如 for k >= arr.length) - 并且 arr 也可能是null。因此,您可以获得一个IndexOutOfRangeException或一个NullReferenceException- 如果未处理,您的应用程序将中断。

为避免这种情况,请使用

if (k >=0 && arr != null) 
{   
    while (k<arr.Length && arr[k] > 0) { ... k++; }
}

在上面的代码中,如果arrnull,则可以跳过循环,因为数组中没有元素。如果超出数组长度(即k>=arr.length),则arr[k] > 0不再检查(从而避免发生异常)。

我已将表达式的不变部分k >=0 && arr != null从循环表达式中取出,因为没有必要(并且运行速度会更慢)在循环的每次迭代中对其进行评估。

for循环相同:

if (k >=0 && arr != null) 
    for (; var k=0; k<arr.Length && arr[k] > 0; k++) { ... }

请注意,因为您不是从 0 开始,所以我跳过了初始化var k=0,我假设您已经在源代码的上方某处完成了初始化。


除此之外,还有一些附加信息- 如果您想了解有关逻辑运算符和副作用的一些有趣细节,请继续阅读。

C/C++/C#&中,重要的是要知道vs.&&|vs. ||:之间的区别,&|“按位”评估整个表达式,而&&如果||结果已经清楚则停止评估(如果有任何部分,逻辑and不能是true表达式是;如果表达式的任何部分是 ),则false逻辑or不能是)。falsetrue

但是,在某些情况下,您也需要“非快捷方式”版本&。假设您想要将字符串数组转换为整数数组,并且您想要转换每个可以转换的值,即使有些值不能转换为整数(其他值应保持 0) - 如下例所示:

void Main()
{
    var sArr = new string[] {"4", "2", "x", "y", "10", "11"};
    var iArr = new int[sArr.Length];
    bool bCheck = true;
    for (var i=0; i<sArr.Length; i++)
    {
        int value=0;
        // need to use & instead of && here:
        bCheck = bCheck && int.TryParse(sArr[i], out value);
        iArr[i]=value;
    };  
    if (bCheck==true) 
    {
        Console.WriteLine("All numbers are okay.");
    }
    foreach (var n in iArr) Console.Write(n.ToString() + " ");
    Console.WriteLine();
}

此代码的目的是将字符串数组中的值一一转换为 int 并将它们存储在整数数组中 - 如果元素不包含有效整数,则它存储值 0 代替。

我们在这里得到的输出是

4 2 0 0 0 0 

这不是我们所期望的,因为 10 和 11 也是有效的整数并且应该被转换,相反我们得到了它们的 0 和 0。

为了得到我们期望的结果,即

4 2 0 0 10 11 

我们需要替换&&&

bCheck = bCheck & int.TryParse(sArr[i], out value);

这里有什么区别?

如果您在&&上面的语句中使用,那么只要 bCheck 计算结果为 false,快捷方式就会完成——这通常是正确的,因为这样我们就不必再检查表达式了,因为不可能被计算为 true .

但也会发生的情况是,由于我们有快捷方式,int.TryParse不再被调用,因此值不会从函数中传递出去——循环中的所有后续调用都将评估为 0,而不管sArr[i].

这是我们在这里遇到的意外副作用,可以通过强制评估每个表达式来修复(通过使用&)。

于 2012-07-17T14:09:54.487 回答