3.11、关于循环的那些不得不知的东西

By | 2016年1月10日

在前面的文章中,我们已经简单的谈到了c语言中的三种循环语句,要想熟练的使用它们,你还需要经过一些练习。

当然,在循环中或许还有一些容易被你忽视的小问题,这里我们就将他们单独拿出来进行讨论

循环嵌套

在3.7中,我们已经尝试过将while循环嵌套起来,来完成一些复杂的任务

当然,你可以将不同的循环结构嵌套起来,如在while循环中使用for循环

嵌套的方法和前面一样,因此我们就不给出代码了(请自行尝试)

但是我们却有一个前面没有谈到的问题,那就是效率

有时候,我们可能会写出类似于下面这样的代码

for(foo=0;foo=1000;foo++)
   for(bar=0;bar<5;bar++)
{
    //do somethfoong
}


for(bar=0;bar<5;bar++)
     for(foo=0;foo<1000;foo++)
{
    //do somethfoong
}

初看这两个代码似乎没有什么区别,然而请注意,这两个代码的内层循环和外层循环的循环次数是不同的

前者执行的是1000*5次循环,后者执行的是5*1000次循环

因而前者在执行时从内层循环切换到外层循环的次数要多一些

因此有些资料上说,后者(即5*1000)速度更快一些,然而是这样吗?

经多方查证,这个说法是不一定正确的!

因为通常来说,CPU执行循环切换时只是进行了一个跳转指令

而现在的cpu大多拥有加速的cache来存放将要执行的指令和数据

在循环切换时,可能会切换到cache外面(cache比较小,不可能储存所有内容),cpu便只能从低速的RAM上读取数据了

这样cache的优势便无法发挥出来,因此效率比较低

然而这种东西在计算机上似乎都能找到反例。编译我们写的代码的编译器也不是傻子(毕竟人们花费了大量时间研究优化),它会优化我们所编写的代码

其中很常用的一个“黑科技”便是“循环展开”

循环展开是指,对于一些循环次数编译时便能确定的循环(通常是次数较少的循环)在生成代码时编译器会将循环展开

比如类似于

for(int foo = 5; foo &gt; 0; foo--)
printf("hi\n");

这样的循环,编译后会变为

printf("hi\n");
printf("hi\n");
printf("hi\n");
printf("hi\n");
printf("hi\n");

于是循环便成为了简单的重复,没有了循环,执行效率更高(显然的。这样产生的目标文件会稍大,是典型的“以空间换时间”)

这种情况下,上面所说的1000*5循环或许比5*1000更快

所以纠结种效率是没有意义的,大家在书写嵌套循环的时候还是怎么舒服,怎么写清晰就怎么写吧

循环内的变量声明

很多人喜欢在循环内声明变量,而且这在有些时候很方便

但是值得注意的是变量的“有效范围”,即作用域。

例如在c99标准中添加了在for的第一个表达式中添加变量定义的写法

for(int foo=0;…)

这里定义的变量foo仅能在此循环内使用,在循环外面是无法访问这个变量的

发表评论

电子邮件地址不会被公开。 必填项已用*标注