目录
前言
对于计算机科学而言,一门语言应该提供3种形式的程序流:执行语句系列;如果满足某些条件就重复执行语句序列(循环);通过测试选择执行哪一个语句系列(分支)。本笔记是对分支、跳转与循环的总结。
一、分支
1.if语句:
(1)if语句被称为分支语句或选择语句。if语句的通用形式如下:if( expression)
statement
statement语句可以是一条简单语句或复合语句。如果expression的值为真,则执行statement,否则,跳过statement。
(2)if else语句:其通用形式如下:if( expression)
statement1
else
statement2
statement1,statement2语句可以是一条简单语句或复合语句。如果expression的值为真,则执行statement1,否则,执行statement2。
(3)多重选择else if:其形式如下:if( expression1)
statement1
else if( expression2)
statement2
else
statement3
由于编译器的限制范围,编译器最少支持127层套嵌。
(4)else 与 if的配对问题:看如下代码段:
if(num > 6)
if(num < 12)
printf("a");
else
printf("b");
什么时候打印'b',答案是当num>=12时。换言之,else与第二个if配对。因此,我们可以知道,else与离它最近的、没有与别的else匹配过的if配对。 如果想与第一个if配对,只需要把第二个if用花括号括起来或者增加一个空的else。即:
if(num > 6)
{
if(num < 12)
printf("a");
}
else
printf("b");
if(num > 6)
{
if(num < 12)
printf("a");
else
;
}
else
printf("b");
这里也给我们一个提示:适当的使用{}可以使代码的逻辑更加清楚。
2.switch语句:
(1)switch语句也是一种分支语句,常常用于多分支的情况。其构造如下:
(2)switch在圆括号中的测试表达式的值应该是一个整数值(包括char类型)。case必须是整数类型(包括char类型)的常量或整型常量表达式(即,表达式中只包含整型常量),不能用变量作为case标签。
(3)switch和break:break语句在其中的作用:让程序离开switch语句,跳至switch语句后面的下一条语句。如果没有break语句,就会从匹配标签开始执行到switch的末尾。break语句的实际效果是把语句列表划分为不同的部分。
(4)default子句:如果表达的值与所有的case标签的值都不匹配,如果有default:标签行,就跳转至该行,否则,程序继续执行switch后面的语句。程序并不会终止,也不会报错。每个switch语句中只能出现一条default子句。在每个 switch 语句中都放一条default子句是个好习惯,甚至可以在后边再加一个 break 。理论上来说,最后一个 case 语句的后面的break语句并不需要,但是保留这条break语句可以防止以后在添加新的case时遗漏break语句,所以我们建议这条语句最好保留
(5)switch允许嵌套使用
二、循环
1.while循环
(1)while循环的通用形式:while ( expression )
statement
statement部分可以是以分号结尾的简单语句,也可以是用花括号括起来的复合语句。如果expression为真(非零),执行statement部分一次,然后再次判断expression。在expression为假之前,循环的判断和执行一直重复进行。每一次循环都被称为一次迭代。
注意:C语言中“真”的概念很宽,一般而言,所有非零值都视为真,只有0被视为假
(2)何时终止循环:只有在对测试条件求值时,才决定是终止还是继续循环
(3)while循环又可分为不确定循环(在测试表达式为假之前,预先不知道要执行多少次循环)和计数循环(在测试表达式为假之前,预先就知道要执行多少次循环)。
(4)在创建一个重复执行固定次数的循环中涉及了3个行为:①必须初始化计算器②计算器与有限的值进行比较③每次循环时更新计算器。while的小缺点:由于风格问题,使得初始化、测试和更新三个部分很可能偏离较远,这样查找修改就不够集中和方便。我们很容易遗忘初始化或更新部分,看如下代码:
#include <stdio.h>
int main()
{
int num = 20;
int count = 1;//初始化
while(count <= num)//测试
{
printf("Be my wife!\n");//行为
count++;//更新计数
}
return 0;
}
我们可以把测试部分和更新部分放在一起,这样就可以防止不小心漏掉更新部分,看一下代码段:
while(count++ <= num)
{
printf("Be my wife!\n");
}
其实用for循环可以有效避免这些问题,下面我们来总结for循环
2.for循环
(1)for循环的形式:for( initialize;test;update)
statement
statement部分可以是以分号结尾的简单语句,也可以是用花括号括起来的复合语句。initialize表达式在执行for语句之前只执行一次;然后对test表达式求值,如果表达式为真,执行循环一次,接着对update表达式求值,并在此检查test表达式。for循环圆括号中的表达式也叫作控制表达式,它们都是完整的表达式,所以每个表达式的副作用都发生在对下一个表达式求值之前。for循环把初始化、测试和更新组合在一起。
(2)可以把for语句写成while语句:
initialize;
while(test)
{
statement;
update;
}
(3)for的灵活性:
①可以使用递减运算符来递减计算器,如:
for (sec = 5; sec > 0; sec++)
{
printf("%d seconds!\n",second);
}
②可以让计数器递增某个数,如:
for (n = 2; n < 60; n += 13)
{
printf("%d\n",n);
}
③可以用字符代替数字计数,如:
for (ch = 'a'; ch <= 'z'; ch++)
{
printf("The ASCII value for %c is %d.\n",ch, ch);
}
④除了测试迭代次数外,还可以测试其他条件
⑤可以让递增的量不是固定的量,如:
for (debt = 100.0; num * num * num <= 216; num++)
{
printf("Your debt is now $%.2f.\n",debt);
}
⑥第三个表达式update可以是任意合法表达式。无论是什么表达式,每次迭代都会更新该表达式的值,如:
for (x = 1; y <= 75; y = (++x * 5) + 50)
{
printf("%10d %10d\n", x, y);
}
⑦可以省略一个或多个表达式(但是不能省略分号),只要在循环中包含可以结束循环的语句即可,如:
for (n = 3; ans <= 25; )
{
ans *= n;
}
注意:省略第二个表达式被视为真,循环不会结束
for(; ;)
{
printf("apple\n");
}
⑧第一个表达式不一定是给变量赋值,也可以使用printf(),如:
for(printf("Keep entering numbers!\n");num != 6; )
{
scanf("%d",&num);
}
⑨循环体中的行为可以改变循环头中的表达式,如:for (n = 1; n<10000; n = n + delta),如果发现delta太小或太大,可以在循环体中改变delta的值
(3)for循环也可以有两个循环变量
#include <stdio.h>
int main()
{
int x, y;
for(x = 0,y = 0;x < 2 && y < 5; ++x, y++)
{
printf("hehe\n");
}
return 0;
}
编译并运行程序,输出如下:
hehe
hehe
(4)一些建议:
①不建议在for 循环体内修改循环变量,防止 for 循环失去控制。如:
#include <stdio.h>
int main()
{
int i;
for(i = 1; i <= 10; i++)
{
printf("%d",i);
i = 5;
}
return 0;
}
编译并运行程序,输出如下:
6666666666666666666666...
//会发现出现6的无限循环。
//可以在i= 5的后面加上i++,这样就不会无限循环,答案应该为1 3 5 9。
②建议for语句的循环控制变量的取值采用“前闭后开区间”写法,目的:增加代码的可读性。
(5)一道例题:问以下代码循环了多少次?
#include <stdio.h>
int main()
{
int i, j;
for(i = 0, j = 0; j = 0; i++, j++)
{
j++;
}
return 0;
}
答案:0次!j = 0,0为假,因此不会进入循环部分。
注意:while循环和for循环都是入口条件循环,即在循环的每一次迭代之前检查测试条件,所以有可能根本不执行循环。
3、do while循环
(1)do while是出口条件循环,即在循环的每一次迭代之后检查测试条件,这保证了至少执行循环体中的内容一次。
(2)do while循环的通用形式:do
statement
while(expression);
statement可以一条以分号结尾的简单语句或复合语句。
4.嵌套循环:
嵌套循环:一个循环内包含另一个循环。常用于按行按列显示数据。如:
#include <stdio.h>
int main()
{
const int ROWS = 6;
const int CHARS = 6;
int row;
char ch;
for(row = 0; row <ROWS; row++)
{
for(ch = ('A' + row); ch < ('A' + ROWS); ch++)
{
printf("%c",ch);
}
printf("\n");
}
return 0;
}
编译并运行代码,输出如下:
ABCDEF
BCDEF
CDEF
DEF
EF
F
第一个for循环被称为外层循环,第二个for循环被称为内层循环。
5.continue和break语句
(1)continue:
①执行该语句时,会跳过本次迭代的剩余部分,并开始下一轮迭代
②可以用作占位符,如第一个代码段比第二个代码段可读性高:
while ((ch = getchar()) != '\n')
continue;
while ((ch = getchar()) != '\n')
;
③一个对比:(代码段)
count = 0;
while (count < 10)
{
ch = getchar();
if(ch == '\n')
{
continue;
}
putchar(ch);
count++;
}
该循环读取了10个字符,不包括换行符,因为程序会跳过count++。
for(count = 0; count < 10; count++)
{
ch = getchar();
if(ch == '\n')
{
continue;
}
putchar(ch);
}
该循环读取了10个字符,包括换行符。
(2)break:
①程序执行到break语句时,会终止包含它的循环,并继续执行下一阶段。break只跳过一层循环。
②break可用于循环和switch语句,而continue只能用于循环语句
6.如何选择循环:
(1)如果循环次数已知,首选for循环
(2)如果循环次数不明确,需要通过其它条件控制循环,通常选用while语句或do while语句
(3)如果必须先进入循环,经循环体运算得到循环控制条件后,再判断是否进入下一次循环,使用do while语句最合适。
三、跳转
goto语句:
1.goto语句的作用:使程序控制跳转至相应标签语句。
2.goto语句由两部分组成:goto和标签名。其一般构成为:goto part;
part:
3.原则上,根本不用在C程序中中使用goto语句:
(1)C用复合语句或块来处理包含多条语句的if 语句
(2)C通过if else语句表达二选一更清楚
(3)C用while循环来代替goto创建不确定循环
(4)C用continue来代替goto跳转至循环末尾,并开始下一轮的迭代的功能
(5)胡乱跳转至循环的不同部分。(不要这样做!!!!)
但是,我们可以接受goto语句的一种用法,出现问题时从一组嵌套循环中跳出(break只能跳出一层循环),如:
while (funct > 0)
{
for(i = 1; i <= 100; i++)
{
for(j = 1; j <= 50; j++)
{
其它语句
if(问题)
goto help;
其它语句;
}
}
}
help:语句