C语言再学习 -- 循环语句
C语言有三种循环结构:while、for和do while。下面依次讲解
一、while循环
1、while介绍
while(逻辑表达式) //布尔值为1 真
{
反复执行的语句
}
只要逻辑表达式结果为真就反复不停执行大括号里的语句,直到逻辑表达式结果为假循环结束
只要把逻辑表达式写成1则循环成为死循环,while(1)
while循环里可以使用break和continue;
break 关键字很重要,表示终止本层循环。现在这个例子只有一层循环,当代码执行到break 时,循环便终止。
如果把 break 换成 continue 会是什么样子呢? continue 表示终止本次(本轮) 循环。当代码执行到 continue 时,本轮循环终止,进入下一轮循环。while( 1)也有写成 while(true) 或者 while(1==1) 或者 while((bool) 1)等形式的,效果一样。
还需注意:任何非零值都是真.比如,while (-1) == while (true)
2、while复合语句
复合语句是使用花括号组织起来的两个或更过的语句,它也被称为一个代码块。
例如:
/*程序1*/
index = 0;
while (index++ < 10)sam = 10 *index +2;
printf ("sam = %d\n", sam);
/*程序2*/
index = 0;
while (index++ < 10)
{sam = 10 *index +2;printf ("sam = %d\n", sam);
}
说明:在没有花括号的情况下,while循环语句的范围是从while到下一个分号。
3、技巧
A、假如你想要跳过输入直到第一个不为空格或者数字的字符,你可以使用这样的循环:
while (scanf ("%d", &num) == 1) {....}
只要scanf()输入一个整数,它就返回1,循环就会继续。
B、while ((ch = getchar ()) != '\n') {....}
只要输入不为换行符'\n',它就返回1,循环就会继续。
C、while循环内只执行一次的语句
int i = 0;
while (1)
{
if (0 == i)
{只执行一次该语句};
i == 1;
}
4、空语句
while ((ch = getchar ()) != EOF && ch != '\n')
;
while语句之后的单独一个分号称为空语句,它就是应用于目前这个场合,也就是语法要求这个地方出现一条语句但又无需执行任何任务的时候,这个分号独占一行,这是为了防止读者错误地以为接下来的语句也是循环的一部分。
二、do while循环
1、do while介绍
do{
} while(为真的逻辑);
do while为退出条件循环,判断条件在执行循环之后进行检查,这样就可以保证循环体中的语句至少被执行一次。
2、do while复合语句
例如:
do scanf ("%d", &num);
while (num != 20); /*注意while后面有分号 ;*/
3、do while的常规用法
- //限制输入,必须输入0到10的数,否则重新输入。
- #include"stdio.h"
- int main()
- {
- int num;
- do
- {
- printf("请输入0到10的整数:"); //先进行输入提示
- scanf("%d",&num); //从键盘读取一个数
- getchar();
- }while (num > 10 || num < 0); //如果这个数不再0~10内,也就是小于0或者大于10,重新输入
- printf("输入正确,输入的数为:%d\n", num); //输入正确则跳出循环并给出提示,\n表示换行
- }
4、do {}while(0)的用法
linux内核和其他一些开源的代码中,经常会遇到这样的代码:
do{... }while(0) |
这样的代码一看就不是一个循环,do..while表面上在这里一点意义都没有,那么为什么要这么用呢?
实际上,do{...}while(0)的作用远大于美化你的代码,while(0)的好处在于,在编译的时候,编译器基本都会为你做好优化,把这部分内容去掉,最终编译的结果不会因为这个do while而导致运行效率上的差异。。查了些资料,总结起来这样写主要有以下几点好处:
1、辅助定义复杂的宏,避免引用的时候出错:
举例来说,假设你需要定义这样一个宏:
#define DO_SOMETHING()\foo1();\foo2(); |
这个宏的本意是,当调用DO_SOMETHING()时,函数foo1()和foo2()都会被调用。但是如果你在调用的时候这写:
if(a>0)DO_SOMETHING(); |
因为宏在预处理的时候会直接被展开,你实际上写的代码是这个样子的:
if(a>0)foo1(); foo2(); |
这就出现了问题,因为无论a是否大于0,foo2()都会被执行,导致程序出错。
那么仅仅使用{}将foo1()和foo2()包起来行么?
我们在写代码的时候都习惯在语句右面加上分号,如果在宏中使用{},代码里就相当于这样写了:“{...};”,展开后就是这个样子:
if(a>0) {foo1();foo2(); }; |
注意if{};后面的";",如果if后面还有else等语句则编译不会通过。所以,很多人才采用了do{...}while(0);
#define DO_SOMETHING() \do{ \foo1();\foo2();\}while(0)\ ...if(a>0)DO_SOMETHING();... |
这样,宏被展开后,才会保留初始的语义。GCC提供了Statement-Expressions用以替代do{...}while(0); 所以你也可以这样定义宏:
#define DO_SOMETHING() ({\foo1(); \foo2(); \ }) |
http://www.spongeliu.com/
2、避免使用goto对程序流进行统一的控制:
有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法:
int foo() {somestruct* ptr = malloc(...);dosomething...;if(error){goto END;}dosomething...;if(error){goto END;}dosomething...;END:free(ptr);return 0;} |
由于goto不符合软件工程的结构化,而且有可能使得代码难懂,所以很多人都不倡导使用,那这个时候就可以用do{}while(0)来进行统一的管理:
int foo() {somestruct* ptr = malloc(...);do{dosomething...;if(error){break;}dosomething...;if(error){break;}dosomething...;}while(0);free(ptr);return 0;} |
这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。
3、避免空宏引起的warning
内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏:
#define EMPTYMICRO do{}while(0) |
4、定义一个单独的函数块来实现复杂的操作:
当你的功能很复杂,变量很多你又不愿意增加一个函数的时候,使用do{}while(0);,将你的代码写在里面,里面可以定义变量而不用考虑变量名会同函数之前或者之后的重复。
5、do {}while(0)的简化
#define st(x) do { x } while (__LINE__ == -1)
1, __LINE__ 是个宏,它代表当前代码在源文件的行号,它是大于0的,所以__LINE__ == -1 等同于0,化简为:
#define st(x) do { x } while (0)
2,do {} while (0)通常用于宏中, 为的是避免如下情况:
#define st(x) x
那么我们在调用 if (0) st(a = b; b = c;) 时会被解释成
if(0)
a = b;
b = c;
可见 if 只对a = b;起作用。
for (n = 0; n < 10; n+)printf ("%d %d\n", n, 2 * n + 1);
for (n = 2, m = 0; m < 1000; n *=2)m +=n;
#define SIZE 10
for (int n = 0; n < SIZE; n++)printf ("hello world\n");
长循环在最内层,效率高
for (col=0; col<5; col++ )
{for (row=0; row<100; row++){sum = sum + a[row][col];}
}
长循环在最外层,效率低
for (row=0; row<100; row++)
{for ( col=0; col<5; col++ ){sum = sum + a[row][col];}
}
C、建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法。半开半闭区间写法和闭区间写法虽然功能是相同,但相比之下,半开半闭区间写法写法更加直观。
for (n = 0; n < 10; n++)
{…n = 8;//不可,很可能违背了你的原意…
}
E、循环要尽可能的短,要使代码清晰,一目了然。
*****
*********
*************
*********
*****
*
#include <stdio.h>
int main()
{int i=0,j=0,k=0;for(i=0;i<=3;i++){for(j=0;j<=5-2*i;j++){printf(" ");}for(k=0;k<=4*i;k++){printf("*");}printf("\n");}for(i=0;i<=2;i++){for(j=0;j<=2*i+1;j++){printf(" ");}for(k=0;k<=8-4*i;k++){printf("*");}printf("\n");}return 0;
}
2、请简述以下两个 for 循环的优缺点
// 第一个
for (i=0; i<N; i++)
{
if (condition)
DoSomething();
else
DoOtherthing();
}
// 第二个
if (condition)
{
for (i=0; i<N; i++)
DoSomething();
}
else
{
for (i=0; i<N; i++)
DoOtherthing();
}
优缺点:效率高但程序不简洁
int a[10];
闭区间写法:for (n = 0; n <= 9; n++)
半开半闭区间写法和闭区间写法虽然功能是相同,但考虑到边界计算,例如我们要在C语言中定义一个拥有 10 个元素的数组,那么 0 就是数组下标的第一个 “入界点”(指处于数组下标范围以内的点,包括边界点),而 10 就是数组下标中的第一个“出界点”(指不在数组下标范围以内的点,不含边界点)。因此写成半开半闭区间的写法更加直观。
for (n = 0; n < 10; n++)
{
…
n = 8;//不可,很可能违背了你的原意
…
}
4、循环要尽可能的短,要使代码清晰,一目了然。
如果你写的一个循环的代码超过一显示屏,那会让读代码的人发狂的。解决的办法由两个:第一,重新设计这个循环,确认是否这些操作都必须放在这个循环里;第二,将这些代码改写成一个子函数, 循环中只调用这个子函数即可。 一般来说循环内的代码不要超过 20行。
国外有研究数据表明,当循环嵌套超过 3 层,程序员对循环的理解能力会极大的降低。如果你的循环嵌套超过 3 层,建议你重新设计循环或是将循环内的代码改写成一个字函数。
C语言再学习 -- 循环语句相关推荐
- C语言再学习--关键字
如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/53021879 C语言一共有32个关键字,如下表所示: 关键字 说明 auto ...
- C语言再学习 -- 详解C++/C 面试题 2
(经典)C语言测试:想成为嵌入式程序员应知道的0x10个基本问题. 参看:嵌入式程序员面试问题集锦 1.用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define ...
- C语言再学习 -- 详解C++/C 面试题 1
参看:<高质量C++ C编程指南>.林锐 对这篇文章记忆犹新,因为之前找工作面试的时候,遇到过一家公司就是用的这套面试题.现在就结合考查的知识点和我总结完 C 语言再学习后的深入理解,来详 ...
- 【C语言进阶深度学习记录】七 C语言中的循环语句
文章目录 1 循环语句分析 1.1 do...while循环 1.2 while循环 1.3 for循环 1.4 三种循环语句使用对比 2 break和continue的区别 3 总结 1 循环语句分 ...
- C语言再学习 -- 再论数组和指针
之前有总结指针数组,但是现在看来总结的太简单了.好多重要的知识点都是一带而过的.本想在后面添加后来想想算了,还是再写一篇文章来详细介绍数组和指针这对冤家吧. 之前总结的,参看:C语言再学习 -- 数组 ...
- C语言再学习 -- 时间函数
在软件设计中经常会用到关于时间的处理,用来计算语句.函数的执行时间,这时就需要精确到毫秒甚至是微妙的时间.我们首先来介绍一下,时间单位: 时间单位还有:秒(s).毫秒(ms).微秒 (μs).纳秒(n ...
- C语言再学习 -- 关键字volatile
上周确实事情挺多的,年会.公司聚餐,一到过年就有忙不完的事分心.还好C语言再学习总结的已经差不多了,年前也不展开别的了,接下来这十几天.总结几篇典型的面试题吧. 言归正传,接下来看看关键字 volat ...
- C语言再学习 -- 关键字const
const 关键字其实我们并不陌生,之前有讲过const修饰数组和指针.现在来详细介绍这个关键字. 参看:[C/C++和指针]著名的<const的思考> 一.const 介绍 1.cons ...
- C语言再学习 -- 关键字typedef
参看:C语言再学习 -- 结构和其他数据形式 参看:C语言再学习 -- 关键字struct(转) 参看:常见typedef 用法 参看:关于typedef的用法总结 一.typedef 介绍 type ...
最新文章
- 什么是分布式系统!以及分布式系统架构的优缺点!
- 一年的第几周怎么算_部编版一年级下册第7课《怎么都快乐》图文讲解+知识点梳理...
- [Linux].netrc或者_netrc使用可以
- 普中stm32开发板tftlcd显示图片_STM32实例TFTLCD介绍
- Android官方开发文档Training系列课程中文版:创建自定义View之View的绘制
- matlab拟合二元函数图,求助大神。。matlab拟合二元函数,求解系数。函数形式已知...
- 计算机图形学实验报告百度云盘,计算机图形学实验报告(一).doc
- google earth pro 安装后启动时报错:google 地球无法连接到登录服务器(错误代码:c000000c)
- Spring5开发新功能
- Beamer Introduction
- 数据中台在企业数字化转型中的践行(上篇)
- 红帽的PAAS平台openshift
- 打包时错误 Entry name ‘classes.dex‘ collided 的解决办法
- 照片OCD问题,滑动窗口分类器,上限分析
- 利用脚手架创建vue项目时报这个错误,哪位大神帮忙解答一下,实在是找到解决办法了。万分感谢
- 点下确认的那一刻,我的大脑在发生些什么?
- 「数字货币监管」听证会重磅来袭,无形之笼悄然降临?
- AD模数转换模块diy(AD9236/12位/80MSPS)
- 【VisionMaster】二次开发之第三方库的使用
- 我参加了资金盘培训,get了这些“知识点”