for 循环与while循环的等价

本文通过插入排序算法的实现,展示了for循环与while循环之间的等价转换,并深入分析了循环条件顺序对程序正确性的影响。文章指出,在进行条件与操作时,若第一个条件为假,则后续条件不必再进行判断。

在进行for循环和while循环的等价转换的时候,要注意到循环条件的顺序。下面的分析说明了这一点: 插入排序的for循环版本:  insertSort(int[] array) {   int key;   int i,j;   /*for 循环*/   for(i = 1; i < array.length; i++ )         {             key = array[i];             for(j = i; j > 0 && key < array[j - 1]; j--)                 array[j] = array[j - 1];             array[j] = key;         } }

下面程序片段是插入排序的while循环版本: insertSort(int[] array) {   int key;   int i,j;     /*用while循环*/    for (i = 1; i < array.length; i++) {    key = array[i];//当前的要进行插入的数值    j = i;    while( array[j -1] > key && j >0)      {        array[j] = array[j-1];     j--;      }    array[j] = key;   }  } 初看这两个程序片段的时候,似乎是等价。但是编译执行的时候,for循环的版本可以通过,而while循环的版本却报出数组越界的错误。分析了好久,也没搞明白原因。最后,对程序进行调试后才发现了其中的错误。正确的while循环应该是这样的: while( j>0 && array[j-1] > key){        array[j] = array[j-1];     j--;    } 对比两个while循环,相当的类似,其细微的区别仅在于while循环条件的顺序不一样,错误的while循环条件是:  array[j -1] > key && j >0…………1 正确的是: j>0 && array[j-1] > key……………2 这就涉及到了while循环条件表达式的执行顺序。如果当j=0时候,表达式1取出array[j-1]时,j-1=-1,数组越界了。而表达式2先对j进行判断就排除了j=0的可能性。 该错误表明了,在构造while循环的判断表达式的时候,对循环条件的考虑要周全,同时也说明了一点,在进行条件与(&&)操作时候,如果第一个条件是flase,其后的条件就不必要进行判断了。 貌似简单的一个道理,在我们编程的过程中,经常会被遗忘。
这是一个非常好的问题! 你问得没错:`list_for_each_entry_safe` 是一个 `for` 循环宏,但当我们把它“展开”成等价代码时,你看到的是一个 `while` 循环的形式。这是因为在 C 语言中,**`for` 和 `while` 是可以互相转换的**,而且宏的本质是**文本替换**,所以宏作者选择用 `for` 的结构来封装逻辑,但其展开后的等价代码也可以写成 `while`。 --- ## 一、`for` 和 `while` 的等价关系 我们先回顾一下 C 语言中 `for` 和 `while` 的等价关系: ```c for (init; condition; update) { body; } ``` 等价于: ```c { init; while (condition) { body; update; } } ``` 也就是说,`for` 循环本质上是一个结构更清晰的语法糖,它把初始化、条件判断、更新表达式集中在一起。 --- ## 二、回到 `list_for_each_entry_safe` 宏 宏定义如下: ```c #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member), \ n = list_next_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = n, n = list_next_entry(n, member)) ``` ### 宏展开后是这样的 `for` 循环: ```c for ( pos = list_first_entry(head, typeof(*pos), member), n = list_next_entry(pos, member); !list_entry_is_head(pos, head, member); pos = n, n = list_next_entry(n, member) ) { // 用户代码在此操作 pos } ``` --- ## 三、为什么可以写成 while? 因为上面的 `for` 循环可以完全等价地写成: ```c pos = list_first_entry(head, typeof(*pos), member); n = list_next_entry(pos, member); while (!list_entry_is_head(pos, head, member)) { // 用户代码在此操作 pos pos = n; n = list_next_entry(n, member); } ``` 这段代码和上面的 `for` 是完全等价的。 --- ## 四、为何宏作者选择用 `for` 而不是 `while`? 有几个原因: 1. **结构清晰**:`for` 把初始化、循环条件、更新逻辑集中在一起,便于阅读。 2. **宏封装更自然**:宏是文本替换,使用 `for` 结构可以让调用者像使用普通 `for` 一样书写代码。 3. **变量作用域控制**:有些实现中会用 `do { ... } while (0)` 或者 `{ ... }` 来包裹宏代码块,但这里选择的是 `for`,更符合逻辑。 --- ## 五、总结对比 | 写法 | 是否等价 | 特点 | |------|----------|------| | `for (...) { ... }` | ✅ 等价 | 更清晰、结构化 | | `while (...) { ... }` | ✅ 等价 | 更直观,但逻辑分散 | --- ## 六、示例代码:等价 `for` `while` 对比 ### ✅ `for` 写法: ```c struct icmp_info *pos, *n; for (pos = list_first_entry(&icmp_list, struct icmp_info, list), n = list_next_entry(pos, list); !list_entry_is_head(pos, &icmp_list, list); pos = n, n = list_next_entry(n, list)) { printk("ICMP type: %d\n", pos->type); } ``` ### ✅ `while` 写法: ```c struct icmp_info *pos, *n; pos = list_first_entry(&icmp_list, struct icmp_info, list); n = list_next_entry(pos, list); while (!list_entry_is_head(pos, &icmp_list, list)) { printk("ICMP type: %d\n", pos->type); pos = n; n = list_next_entry(n, list); } ``` --- ## 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值