### C语言关键字浅析系列 ###
### ISO/ANSI C 关键字 ###
while在英文中常被翻译为“在……的时候,当……时”,私以为在C语言的while里,应当为“当……的时候,一直……”
因为这样说,才符合while表示循环的身份,while循环结构也是C语言很常见和很重要的一种语法
while的作用是:
表示一种入口条件循环——while循环结构。
1、while的使用
如果你已经有C程序的编程经验,那可能while已经是你的老熟人了,如果你正在学循环结构,不妨也一起回顾一下while的格式:
int i = 0;
while (i < 10) /* while关键字后跟小括号,括号内是逻辑表达式,只要逻辑表达式成立,就循环地执行while后的语句 */
i++; /* 这是一条循环体的语句,这段代码的效果是i从0开始一直自增1,i=10的时候循环结束 */
int i = 0, sum = 0;
while (i < 10) /* 如果循环体是复合语句,需要加大括号 */
{ /* 这段代码的效果是,sum保存的是0到9的和 */
sum += i;
i++;
}
2、谈谈逻辑表达式
和if-else的逻辑表达式类似,效果都是看看是否成立,成立的标准是看表达式的值是不是非零或者true,反之不成立是0和false
作为一种入口条件循环,while关键字后的逻辑表达式只要成立,就会执行循环体,然后返回再看逻辑表达式是否成立,以此循环
所以你可能注意到了,如果逻辑表达式一直成立呢?这就是我们常说的死循环:
while (1)
{
/* 这种死循环很常见,并非人为疏忽造成的bug,而是利用死循环的特性写的程序,如多线程编程中常用这种死循环 */
/* 提示:如果逻辑表达式是整数常量,记住,只有0表示false,非零常量都表示true,3,1024,-1 ,-10等等 */
/* 不过习惯上就写while (1)就行,写while (1024)的话其他同事看着不知道你这是什么名堂 */
}
while (true)
{
/* true是bool常量,当然也表示成立,java转过来的程序员对这种写法应该更倍感亲切,因为java的死循环喜欢这样写 */
}
int i = 0;
int j = 1, sum = 0;
while (i < 10)
{
sum += j;
j++;
/* 整个循环体中忘记了对循环条件做处理导致的死循环,这种bug在使用while结构且循环体比较长的时候可能发生 */
}
有一种常见的while循环的应用,叫做读循环,它是指循环地输入一些数据然后处理,一遍一遍地执行这样的操作:
int a, b, flag;
flag = scanf("%d%d", &a, &b); /* 输入两个整数 */
while (flag == 1)
{
printf("Summary is %d\n", a + b); /* 打印两个数的和 */
flag = scanf("%d%d", &a, &b); /* 再输入两个数,循环上述步骤 */
}
/* 顺便提醒一句,编程需要谨慎认真,专心致志,==运算符一定要与=运算符区分好,下面这种是常见错误 */
while (flag = 1) /* 这相当于把flag赋值为1了,而不是逻辑表达式 */
{
/* 好的编译器在这里会报错 */
}
这只是读循环的一个小demo,一般输入语句存在于while之前和循环体的最后,不过在C语言的风格中,还有一种更简练的写法:
int a, b; /* flag直接省了 */
while (scanf("%d%d", &a, &b)) /* 这样用scanf是因为它被成功调用时会返回一个1,这里索性把==运算符也省了 */
{
printf("Summary is %d\n", a + b); /* 打印两个数的和 */
}
ACMer或者参加过程序设计大赛、算法比赛和认证的人可能对上面这种很大神的操作很熟悉,那是对付OJ系统上的输入类的题的一种技巧
3、while的应用
说到while的常见使用,我首先能想起的是人性化输入纠错(自己安的名字):
char sex;
scanf("%c", &sex); /* 输入性别,只能是字符m或f */
while (sex != 'm' && sex != 'f') /* 只要输入的不是m和f,就重来 */
{
printf("Wrong character, input again:\n");
scanf("%c", &sex);
}
/* 另外常见的还有必须输入正数,必须输入数字,必须输入字母,必须是某几种枚举,为的是保证输入数据符合后面的程序处理 */
还有一种很常见应用就是与指针的配合了,比如链表的遍历:
cur = head->next; /* p指向带头结点的链表的第一个结点 */
while (cur) /* 这里其实应该写为cur != NULL */
{
printf("%d\t", cur->value);
cur = cur->next;
}
/*
因为在一个链表中,尾结点的next指针一般是NULL的,而NULL可以作为不成立的逻辑表达式,与false和0效果一样
所以上述程序的效果就是,cur指针按序指向每个结点,当遍历完最后一个结点后,cur=cur->next=NULL
回到while头的循环条件判断时则会不成立,由此跳出了循环,所以最后一条语句一定要有,否则会死循环
*/
当然,多线程中也常见while,而且是死循环的while(死循环一般很少用do-while循环和for循环):
/* 常规操作:while(1) */
while (1) /* 报时器 */
{
Sleep(1000); /* 线程休眠1s */
char* time;
getSystemTime(time);
printf("Current time : %s\n"); /* 打印当前时间 */
}
/* 非主流操作:for(;;) */
for(;;)
{
Sleep(1000); /* 线程休眠1s */
char* time;
getSystemTime(time);
printf("Current time : %s\n"); /* 打印当前时间 */
}
/* 魔鬼般的操作:do-while */
do{
Sleep(1000); /* 线程休眠1s */
char* time;
getSystemTime(time);
printf("Current time : %s\n"); /* 打印当前时间 */
}
while (1)
——参考《C Primer Plus第五版》
相关文章: