分⽀和循环
选择结构程序设计
1. if语句
1.1 if
if 语句的语法形式如下:
if ( 表达式 )
语句
表达式成⽴(为真),则语句执⾏,表达式不成⽴(为假),则语句不执⾏
,在C语⾔中,0为假,⾮0表⽰真,也就是表达式的结果如果是0,则语句不执⾏,表达式的结果如果不是0,则语句执⾏。
1.2 else
if ( 表达式 )
语句1
else
语句2
练习:输⼊⼀个年龄,>=18岁就输出:成年,否则就输出:未成年
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age>=18)
printf("成年\n");
else
printf("未成年\n");
return 0;
}
1.3 分⽀中包含多条语句
默认情况下,if和else的后边只能跟一条语句。如果使用多条语句可以用{}括起来else 后也可以跟上⼤括号。(单条语句也可以加大括号)
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age >= 18) //if 后使⽤{} 控制多条语句这个块也叫:
//程序块,或者复合语句
{
printf("成年了\n");
printf("可以谈恋爱了\n");
}
else //else 后使⽤{}控制多条语句这个块也叫:
//程序块,或者复合语句
{
printf("未成年\n");
printf("不可以早恋哦\n");
}
return 0;
}
1.4 嵌套if
if else 语句中,else可以与另⼀个if语句连⽤,构成多重判断。
⽐如:要求输⼊⼀个整数,判断输⼊的整数是0,还是正数或者负数。请看如下代码:
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num == 0)
printf("输⼊的数字是0\n");
else
{
if(num > 0)
printf("输⼊的数字是正数\n");
else
printf("输⼊的数字是负数\n");
}
return 0;
}
//方法二
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num == 0)
printf("输⼊的数字是0\n");
else if (num > 0)
printf("输⼊的数字是正数\n");
else
printf("输⼊的数字是负数\n");
return 0;
}
//方法三
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if (num >= 0)
{
if(num == 0)
printf("输⼊的数字是0\n");
else
printf("输⼊的数字是正数\n");
}
else
{
printf("输⼊的数字是负数\n");
}
return 0;
}
练习:输⼊⼀个⼈的年龄
如果年龄<18岁,打印"少年"
如果年龄在18岁⾄44岁打印"⻘年"
如果年龄在45岁⾄59岁打印"中⽼年"
如果年龄在60岁⾄89岁打印"⽼年"
如果90岁及以上打印"⽼寿星"
//方法一
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age<18)
printf("少年\n");
else //age>=18
{
if(age<=44)//18~44
printf("⻘年\n");
else //>44
{
if(age<=59) //45~59
printf("中⽼年\n");
else //>59
{
if(age<=89)
printf("⽼年\n");
else //>89
printf("⽼寿星\n");
}
}
}
return 0;
}
//方法二
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age<18)
printf("少年\n");
else if(age<=44)// 18~44
printf("⻘年\n");
else if(age<=59) // 45~59
printf("中⽼年\n");
else if(age<=89)
printf("⽼年\n");
else //>89
printf("老寿星\n");
return 0;
}
1.5 悬空else问题
如果有多个if和else,可以记住这样⼀条规则,else总是跟最接近的if匹配。
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
什么都不输出,因为else与第二个if匹配,而第一个if (a == 1 )不成立所以嵌套的if else没有机会执行
代码应该改成以下好理解一些:
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
{
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
}
return 0;
}
或者如果我们希望else确实和第⼀个if匹配,可以这样修改代码:
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
{
if(b == 2)
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
用if语句实现选择结构的总结
一.If语句的三种基本形式
(1)if(表达式) 语句
(2)if(表达式) 语句1
else 语句2
(3)if (表达式1) 语句1
else if (表达式2)语句2
else if (表达式3)语句3
…
else if(表达式m)语句m
else语句n
二.选择结构的嵌套
例如:
输入三个数a,b,c,要求按由小到大的顺序输出。
if a>b 将a和b对换
(a是a、b中的小者)
if a>c 将a和c对换
(a是a、c中的小者,是三者中最小者)
if b>c 将b和c对换
(b是b、c中的小者,是三者中次小者)
#include <stdio.h>
int main()
{
float a,b,c,t;
scanf("%f,%f,%f",&a,&b,&c);
if(a>b)
{t=a;a=b;b=t;}
if(a>c)
{t=a;a=q;c=t;}
if(b>c)
{t=b;b=c;c=t;}
printf("%5.2f,%5.2f,%5.2f\n",a,b,c);
}
2. 关系操作符
关系表达式
- 用关系运算符将两个常量、变量或表达式(可以是算术表达式、关系表达式,逻辑表达式,赋值表达式)接起来的式子,称关系表达式。
关系表达式里运用的运算符叫关系运算符
主要有:>大于 <小于 >= 大于等于 <=小于等于 ==等于 !=不等于
关系表达式通常返回0或1表示真假
C语言中0表示假,非0表示真 3>5表示真返回值为1
多个关系运算符不宜使用比如a>b>c
#include <stdio.h>
int main()
{
int a = 3;
int b = 7;
int c = 4;
if (a< b < c)
{
printf("hehe\n");//hehe
//因为a==3 <b==7为真,所以1,又因为1<4,又为真所以为真打印出呵呵
}
return 0;
}
多个关系运算符不宜使用比如a>b>c
应该为&&符号来写的
i < j && j < k
程序员喜欢将变量写在等号的右边。
if (3 == x)
举例:⽐如:我们输⼊⼀个年龄,如果年龄在18岁~36岁之间,我们输出⻘年。
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age>=18 && age<=36)
//错误写法:if(18<=age<=36)
{
printf("⻘年\n");
}
return 0;
}
3. 条件操作符(三目操作符)
- 条件运算符是C语言中唯一的一个三目运算符
- 优先级仅高于赋值运算符,低于关系运算符和算术运算符。结合性为右结合。
- 条件运算符的结合方向为“自右至左”
- 使用场合:若在if语句中,当被判别的表达式的值为“真”或“假”时,都执行一条赋值语句且向同一个变量赋值时,可以用一个条件运算符来处理。
形式:
表达式1 ? 表达式2 : 表达式3
条件操作符的计算逻辑:1.若表达式1为真,表达式2计算为整个表达式的结果;2.若表达式1为假,表达式3计算计算的结果是整个表达式的结果。(也就是说判断表达式表达式1,若为真则执行表达式表达式2,假则执行表达式表达式3)
if (a>5)
b=3;
else
b=-3;
等价于
b=a>5?3:-3;
练习:求两个数中较大值
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int m = a>b ? a : b;
printf("%d\n", m);
return 0;
}
4. 逻辑操作符:&& ,|| , !和逻辑表达式
一.逻辑运算符
!:逻辑取反运算符(改变单个表达式的真假)。
&&:逻辑与(两侧的表达式都为真,则为真,否则为假)。
||:逻辑或(两侧⾄少有⼀个表达式为真,则为真,否则为假)。
C语言中,非0表示真,0表示假
1. 逻辑取反运算符
a | !a |
---|---|
非0 | 0 |
0 | 1 |
我们有⼀个变量叫 flag ,如果flag为假,要做⼀个什么事情,就可以这样写代码:
#include <stdio.h>
int main()
{
int flag = 0;
if(!flag)
{
printf("do something\n");
}
return 0;
}
//如果 flag 为真, !flag 就是假,如果 flag 为假, !flag 就是真
//所以上⾯的代码的意思就是 flag 为假,执⾏if语句中的代码。
//也就是如果输入为非零的数比如8,8为真,所以!flag为假,所以不进入if循环,什么都不输出
//如果输入为0,0为假,所以!flag为真,所以进入if循环输出do something
2. 逻辑与运算符
a | b | a&&b |
---|---|---|
非0 | 非0 | 1 |
非0 | 0 | 0 |
0 | 非0 | 0 |
0 | 0 | 0 |
&&
逻辑与运算符,也是并且的意思, && 是⼀个双⽬操作符,使⽤的⽅式是 a&&b
.两侧的表达式都为真,则为真,否则为假
⽐如:如果我们说⽉份是3⽉到5⽉,是春天
#include <stdio.h>
int main()
{
int month = 0;
scanf("%d", &month);
if(month >= 3 && month <= 5)
//表达的意思就是month既要⼤于等于3,⼜要⼩于等于5,必须同时满⾜。
{
printf("春季\n");
}
return 0;
}
3. 逻辑或运算符
||
逻辑或运算符,也就是或者的意思, || 也是⼀个双⽬操作符,使⽤的⽅式是 a || b
,两侧⾄少有⼀个表达式为真,则为真,否则为假
⽐如:我们说⼀年中⽉份是12⽉或者1⽉或者2⽉是冬天
#include <stdio.h>
int main()
{
int month = 0;
scanf("%d", &month);
if(month == 12 || month==1 || month == 2)
{
printf("冬季\n");
}
return 0;
}
4. 练习:闰年的判断
输⼊⼀个年份year,判断year是否是闰年
闰年判断的规则:
- 能被4整除并且不能被100整除是闰年
- 能被400整除是闰年
#include <stdio.h>
//代码二
int main()
{
int year = 0;
scanf("%d", &year);
if((year%4==0 && year%100!=0) || (year%400==0))
{
printf("是闰年\n");
}
return 0;
}
#include <stdio.h>
//代码1
int main()
{
int year = 0;
scanf("%d", &year);
if(year%4==0 && year%100!=0)
printf("是闰年\n");
else if(year%400==0)
printf("是闰年\n");
return 0;
}
5. 短路
-
C语⾔逻辑运算符还有⼀个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。
-
如果左边的表达式满⾜逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路”。
-
if(month >= 3 && month <= 5)
表达式中&&的左操作数是 month >= 3 ,右操作数是 month <= 5 ,当左操作数 month >= 3 的结果是0的时候,即使不判断 month <= 5 ,整个表达式的结果也是0(不是春季)
所以,对于&&操作符来说,左边操作数的结果是0的时候,右边操作数就不再执⾏。
-
if(month == 12 || month==1 || month == 2)
如果month= =12,则不⽤再判断month是否等于1或者2,整个表达式的结果也是1(是冬季)。
所以, || 操作符的左操作数的结果不为0时,就⽆需执⾏右操作数。
像这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进⾏计算的运算称为短路求值。
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
//先使用a++为0,且是&&运算符,所以i=0为假,与运算中有一个为假则为假所以后面都不看了,a++后a=1
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);//1234
return 0;
#include <stdio.h>
int main()
{
int i = 0,a=1,b=2,c =3,d=4;
i = a++ && ++b && d++;
//a++后a=2,i=1,i为真可以继续算。++b后b=3,a++ && ++b 为1&&3,1和3均为真所以i为真为1。
//再继续看d++,d=5;1&&4其中1为真4为真所以i为真为1
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);//12335
return 0;
#include <stdio.h>
int main()
{
int i = 0,a=1,b=2,c =3,d=4;
i = a++||++b||d++;
//a=2,a++后i的值为1为真,所以后面不用算了因为||有一个为真则真
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);//2234
return 0;
}
二.逻辑表达式
三.总结
逻辑运算符还有⼀个特点:它总是先对左侧的表达式求值,再对右边的表达式求值
如果左边的表达式满⾜逻辑运算符的条件,就不再对右边的表达式求值。
在逻辑表达式的求解中,并不是所有的逻辑运算符都要被执行。
(1)a&&b&&c
只有ā为真时,才需要判断b的值
只有a和b都为真时,才需要判断c的值。
(2)a||b||c
只要a为真,就不必判断b和c的值
只有a为假,才判断b。
a和b都为假才判断c。
5. switch语句
switch语句语句是⼀种特殊形式的if…else结构。⽤于判断条件有多个结果的情况。
switch (expression) {
case value1: statement
case value2: statement
default: statement
}
1. 根据表达式不同的值,执行相应的case分支,如果找不到对应的值就执行default分支。
2.switch后的表达式必须是整形表达式(字符也是整型)不能是变量(所以也可以switch(ch))
3.case后的值,必须是整型常量表达式(所以也可以case ‘a’ 或者case ‘b’)
if(n%3 == 0)
printf(“整除,余数为0\n”);
else if(n%3 == 1)
printf(“余数是1\n”);
else
printf(“余数是2\n”);
等价于
switch(n%3)
{
case 0:
printf(“整除,余数为0\n”);
break;
case 1:
printf(“余数是1\n”);
break;
case 2:
printf(“余数是2\n”);
break;
}
注意:
1. case和后边的数字之间必须有空格
2.每一个case语句中的代码执⾏完成后,需要加上break,才能跳出这个switch语句
3.break不是每个case语句都能有
练习:1. 输⼊1~5,输出的是“⼯作⽇”;
2. 输⼊6~7,输出“休息⽇”
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch(day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("⼯作⽇\n");
break;
case 6:
case 7:
printf("休息⽇\n");
break;
default://不是1~7的值就用default
printf("输⼊错误\n");
break;
}
return 0;
}
循环
6. while循环
while语句用来实现“当型”
循环结构*
执⾏判断表达式,表达式的值为0,循环直接结束;表达式的值不为0,则执⾏循环语句,语句执⾏完后再继续判断,是否进⾏下⼀次判断。
while(表达式)
语句; //如果循环体想包含更多的语句,可以加上⼤括号
- 执行过程:当表达式为非0值时,执行while语句中的内嵌语句。其特点是:先判断表达式,后执行语句。
- 注意:
- 循环体如果包含一个以上的语句,应该用花括弧括起来,以复合语句形式出现。
- 在循环体中应有使循环趋向于结束的语句。如果无此语句,则i的值始终不改变,循环永不结束。
if和while的对比
if(表达式)
语句;
while(表达式)
语句; //如果循环体想包含更多的语句,可以加上⼤括号
//代码1
#include <stdio.h>
int main()
{
int n = 10;
if(n > 10)
printf("hehe\n"); //if后边条件满⾜,打印⼀次hehe
return 0;
}
//代码2
#include <stdio.h>
int main()
{
int n = 10;
while(n > 10)
printf("hehe\n"); //while后边的条件满⾜,死循环的打印hehe
return 0;
}
while语句的执⾏流程
练习:在屏幕上打印1~10的值
//i=1,i为循环变量,然后打印i,然后给i,+1
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
printf("%d ", i);//打印加个空格好看一些。输出:1 2 3 4 5 6 7 8 9 10
i++;
//或者i = i+1;
}
return 0;
}
或者
#include <stdio.h>
int main()
{
int i = 0;
while(i<10)
{
i = i+1;
//或者i++
printf("%d ", i);
}
return 0;
}
练习:逆序打出数字
例如:1234 输出:4 3 2 1
//题⽬解析
//1. 要想得到n的最低位,可以使⽤n%10的运算,得到的余数就是最低位,如:1234%10得到4
//2. 要想去掉n的最低位,找出倒数第⼆位,则使⽤ n=n/10 操作就可以去掉最低位的,如:n=1234/10得到123,123相较于1234就去掉了最低位,123%10就得到倒数第⼆位3。
//3. 循环1和2两个步骤,在n变成0之前,就能到所有的位。
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d",&n);
while(n)//或者(n!=0)
{
printf("%d ",n%10);//有个空格好看点
n=n/10;
//本题比如输入1234先1234%10为4打印出来,然后1234/10=123,循环n=123不等于0,然后就进入循环,123%10为3打印出来,然后123/10=12,n=12不等于0,所以又进入循环12%10为2打印出来,然后12/10=1,n=1不等于0所以又进入循环,1%10为1打印出来然后1/10=0,n=0为假后进不去循环了。所以就打印出 4 3 2 1
}
return 0;
}
7. do-while循环
do
语句;
while(表达式);
while和for都先判断后循环,do while是先循环后判断。
do while的循环体至少循环一次
在屏幕上打印1~10的值
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ", i);
i = i + 1;
}while(i<=10);
return 0;
}
输⼊⼀个正整数,计算这个整数是⼏位数?
例如:
输⼊:1234输出:4
输⼊:12输出:2
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int cnt = 0;
do
{
cnt++;//因为一个正整数至少是一位数,所以必须输出一位。比如123先至少知道有一位数所以一上来先加加然后弄出个一位数下面n/10去掉3。然后n=12,不等于0可以入循环,然后又cnt++又数量加1位数,然后n/10去掉2。然后n=1,不等于0还可以入循环又加一位数,后又去掉一位数1/10,最后剩下0就进不去循环了就可以打印数的数了。总的;来说就是加一位减一位这样的方式来数,也就是先统计然后去掉一位数的方法
//剩下1cunt++又数量+1,n/10去掉1。这样就算出数量1+1+1=3
n = n / 10;
} while (n);
printf("%d\n", cnt);
return 0;
}
8. for循环
for(表达式1; 表达式2; 表达式3)
语句;//如果循环体想包含更多的语句,可以加上⼤括号
表达式1⽤于循环变量的初始化
表达式2⽤于循环结束条件的判断
表达式3⽤于循环变量的调整
⾸先执⾏ 表达式1 初始化循环变量,接下来就是执⾏ 表达式2 的判断部分, 表达式2 的结果如果 = = 0,则循环结束; 表达式2 的结果如果!=0则执⾏循环语句,循环语句执⾏完后,再去执⾏表 达式3 ,调整循环变量,然后再去 表达式2 的地⽅执⾏判断, 表达式2 的结果是否为0,决定循环是否继续。
for循环的初始化部分只被执行一次
说明:
- for语句的一般形式中的“表达式1”可以省略,此时应在for语句之前给循环变量赋初值。注意省略表达式1时,其后的分号不能省略。如
int i=1;
for( ; i<=100; i++) sum=sum+i;
执行时,跳过“求解表达式1”这一步,其他不变。 - 如果表达式2省略,即不判断循环条件,循环无终止地进行下去。也就是认为表达式2始终为真。
例如:for(i=1; ;i++) sum=sum+i;
表达式1是一个赋值表达式,表达式2空缺。它相当于:
i=1;
while(1)
{sum=sum+1; i++;} - 表达式3也可以省略,但此时程序设计者应另外设法保证循环能正常结束。如:
for(i=1;i<=100;)
{ sum=sum+i; i++;}
在上面的for语句中只有表达式1和表达式2,而没有表达式3。但是i++的操作不放在for语句的表达式3的位置处,而作为循环体的一部分,效果是一样的,都能使循环正常结束。 - 可以省略表达式1和表达式3,只有表达式2,即只给循环条件。如:
for(;i<=100;) while(i<=100) {sum=sum+i; 相当于 { sum=sum+i;
i++;} i++;}
在这种情况下,完全等同于while语句。可见for语句比while语句功能强,除了可以给出循环条件外,还可以对循环变量赋初值,使循环变量自动增值等。 - 3个表达式都可省略,如:
for( ; ; ) 语句
相当于
while(1) 语句
即不设初值,不判断条件(认为表达式2为真值),循环变量不增值。无终止地执行循环体。 - 表达式1可以是设置循环变量初值的赋值表达式,也可以是与循环变量无关的其他表达式。如:
for (sum=0;i<=100;i++)
sum=sum+i;
表达式3也可以是与循环控制无关的任意表达式。 - 表达式1和表达式3可以是一个简单的表达式,也可以是逗号表达式,即包含一个以上的简单表达式,中间用逗号间隔。如:
for(sum=0, i=1; i<=100; i++)sum=sum+i;或
for(i=0, j=100; i<=j; i++, j–) k=k+i+j;- 表达式1和表达式3都是逗号表达式,各包含两
个赋值表达式,即同时设两个初值,使两个变量
增值. - 在逗号表达式内按自左至右顺序求解,整个逗号表达式的值为其中最右边的表达式的值。如:
for(i=1;i<=100;i++,i++) sum=sum+i;
相当于
for(i=1;i<=100;i=i+2) sum=sum+i;
- 表达式1和表达式3都是逗号表达式,各包含两
- 表达式2一般是关系表达式(如i<=100)或逻辑表达式 (如a<b && x<y),但也可以是数值表达式或字符表达式,只要其值为非零,就执行循环体。
与while语句类似
#include <stdio.h>
int main()
{
int i = 1;//循环变量的初始化
while(i<=10)//循环结束条件的判断
{
printf("%d ", i);
i = i+1;//循环变量的调整
}
return 0;
}
练习:在屏幕上打印1~10的值
#include <stdio.h>
int main()
{
int i = 0;
for(i=1; i<=10; i++)
{
printf("%d ", i);
}
return 0;
}
练习计算1~100之间3的倍数的数字之和
#include <stdio.h>
int main()
{
int i = 0;
int sum = 0;
for(i=1; i<=100; i++)//1~100
{
//printf("%d ", i)
//判断i是否是3的倍数
if(i % 3 == 0)
sum += i;//等于sum = sum + i
}
printf("%d\n", sum);
return 0;
}
//⼩⼩的优化
//如果能直接产⽣3的倍数的数字就省去了多余的循环和判断
#include <stdio.h>
int main()
{
int i = 0;
int sum = 0;
for(i=3; i<=100; i+=3)
{
sum += i;
}
printf("%d\n", sum);
return 0;
}
9. 循环的嵌套
三种循环 while , do while , for ,这三种循环往往会嵌套在⼀起
练习
找出100~200之间的素数,并打印在屏幕上。
注:素数⼜称质数,只能被1和本⾝整除的数字。
#include <stdio.h>
int main()
{
int i = 0;
int count = 0;
for(i=100; i<=200; i++)//循环产⽣100~200的数字
{
//判断i是否为素数
int j = 0;
int flag = 1;//假设i是素数
for(j=2; j<=i-1; j++) //循环产⽣2~i-1之间的数字 。 这里也可以改为for(j=2; j<i; j++)
//如果2~i-1之间有数字能整除i,则i不是素数
//如果都不能整除,则i是素数。
//比如数字5=i,先弄出 2 3 4 看有数字可以整除5吗,发现不可以整除则说明i为数字5是素数。
{
if(i % j == 0)//2~i-1之间有数字能整除i
{
flag = 0;//i不是素数
break;
}
}
if(flag == 1)
{
count++;//素数数量计算
printf("%d ", i);
}
}
printf("\ncount=%d\n",count);
return 0;
}
10.几种循环的比较
- 四种循环都可以用来处理同一问题,一般情况下它们可以互相代替。但一般不提倡用goto型循环。
- 在while循环和do-while循环中,只在while后面的括号内指定循环条件,因此为了使循环能正常结束,应在循环体中包含使循环趋于结束的语句(如i++,或i=i+1等)。
- for循环可以在表达式3中包含使循环趋于结束的操作,甚至可以将循环体中的操作全部放到表达式3中。因此for语句的功能更强,凡用while循环能完成的,用for循环都能实现。
- 用while和do-while循环时,循环变量初始化的操作应在while和do-while语句之前完成。
而for语句可以在表达式1中实现循环变量的初始化。 - while循环、do-while循环和for循环,可以用break语句跳出循环,用continue语句结束
11. break和continue语句
break 的作⽤是⽤于永久的终⽌循环
continue 的作⽤是跳过本次循环中 continue 后边的代码,在for和while循环中有所差异的
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
break;
//后面终止了5以后不打印break用于终止整个循环
printf("%d ", i);//1 2 3 4
i = i+1;
}
return 0;
}
```c
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
continue;
//当i等于5后,就执⾏continue,直接跳过continue的代码,去循环的判断的地⽅
//因为这⾥跳过了i = i+1,所以i⼀直为5,程序陷⼊和死循环
printf("%d ", i);
i = i+1;
}
return 0;
}
#include <stdio.h>
int main()
{
int i = 1;
for(i=1; i<=10; i++)
{
if(i == 5)
continue;//这⾥continue跳过了后边的打印,来到了i++的调整部分
printf("%d ", i);//1 2 3 4 6 7 8 9 10 11
}
return 0;
}
12. goto语句
goto 语句可以实现在同⼀个函数内跳转到设置好的标号处。
在多层循环的代码中,如果想快速跳出使⽤ goto 就⾮常的⽅便了。
#include <stdio.h>
int main()
{
printf("hehe\n");
if(1)
goto end;
printf("haha\n");
end:
printf("end\n");
return 0;
//打印:hehe
// end
// -
//直接跳过了haha
}
#include <stdio.h>
int main()
{
again:
printf("hehe\n");//死循环打印hehe
goto again;
return 0;
}
#include <stdio.h>
int main()
{
printf("hehe\n");
goto next;
printf("haha\n");
next:
printf("跳过了haha的打印\n");
return 0;
}
for(…)
{
for(…)
{
for(…)
{
if(disaster)
goto error;
}
}
}
error:
//…
本来 for 循环想提前退出得使⽤ break ,⼀个 break 只能跳出⼀层 for 循环,如果3层循环嵌套就得使⽤3个 break 才能跳出循环,所以在这种情况下我们使⽤ goto 语句就会更加的快捷。
13. 例题:关机程序
//方法一
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char input[20] = { 0 };
system("shutdown -s -t 60");//运用这个函数要加库函数头#include<stdlib.h>
again:
printf("请注意,你的电脑在一分钟内关机,如果输入:你是美女,就取消关机\n");
scanf("%s", input);//因为输入你是美女是一段字符串所以要用%s,并且把输入信息放在input数组中
//判断input中存放的是否是“你是美女”
//两个字符串比较相等的时候不是使用==,而是使用strcmp函数,这个函数要加函数头#include<string.h>
if (strcmp("你是美女",input) == 0)
{
system("shutdown -a");//取消关机指令
}
else
{
goto again;//输入不正确就返回跳转到上面的again又执行again以下的语句
}
return 0;
}
//方法二
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char input[20] = { 0 };
system("shutdown -s -t 60");//运用这个函数要加库函数头#include<stdlib.h>
while (1)
{
printf("请注意,你的电脑在一分钟内关机,如果输入:你是美女,就取消关机\n");
scanf("%s", input);//因为输入你是美女是一段字符串所以要用%s,并且把输入信息放在input数组中
//判断input中存放的是否是“你是美女”
//两个字符串比较相等的时候不是使用==,而是使用strcmp函数,这个函数要加函数头#include<string.h>
if (strcmp("你是美女", input) == 0)
{
system("shutdown -a");//取消关机指令
break;//执行完就break这样才能跳出循环不然就一直为真进入循环
}
}
return 0;
}
14. 猜数字游戏
游戏要求:
- 电脑⾃动⽣成1~100的随机数
- 玩家猜数字,猜数字的过程中,根据猜测数据的⼤⼩给出⼤了或⼩了的反馈,直到猜对,游戏结束
1. 随机数生成
1. rand
C语⾔提供了⼀个函数叫rand,这函数是可以⽣成随机数的,函数原型如下所⽰:
int rand (void);
rand函数的使⽤需要包含⼀个头⽂件是:stdlib.h
rand函数会返回⼀个伪随机数,这个随机数的范围是0~RAND_MAX之间,这个RAND_MAX的⼤⼩是依赖编译器上实现的,但是⼤部分编译器上是32767。你会发现第一次和第二次很多次生成的随机数都一样的。
测试⼀下rand函数,这⾥多调⽤⼏次,产⽣5个随机数:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
//发现不管多少次运行,运行出来都是下面5个数
//41
//18467
//6334
//26500
//19169
//我们可以看到虽然⼀次运⾏中产⽣的5个数字是相对随机的,但是下⼀次运⾏程序⽣成的结果和上⼀次⼀模⼀样,这就说明有点问题。
}
rand函数⽣成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法⽣成的随机数。⽽**rand函数是对⼀个叫“种⼦”的基准值进⾏运算⽣成的随机数。**之所以前⾯每次运⾏程序产⽣的随机数序列是⼀样的,那是因为rand函数⽣成随机数的默认种⼦是1。如果要生成不同的随机数,就要让种⼦是变化的。
2. srand
C语⾔中⼜提供了⼀个函数叫srand,⽤来初始化随机数的⽣成器的,srand的原型如下:
void srand (unsigned int seed);
程序中在调⽤rand函数之前先调⽤srand函数,通过srand函数的参数seed来设置rand函数⽣成随机数的时候的种⼦,只要种⼦在变化,每次⽣成的随机数序列也就变化起来了。那也就是说给srand的种⼦是如果是随机的,rand就能⽣成随机数;在⽣成随机数的时候⼜需要⼀个随机数,这就⽭盾了。
3. time
在程序中我们⼀般是使⽤程序运行的时间作为种⼦的,因为时间时刻在发⽣变化的。在C语⾔中有⼀个函数叫time,就可以获得这个时间,time函数原型如下:
time_t time (time_t* timer);
time函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的差值,单位是秒。返回的类型是time_t类型的,time_t类型本质上其实就是32位或者64位的整型类型。
time函数的参数timer如果是⾮NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
如果timer是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。
time函数的时候需要包含头⽂件:time.h
//VS2022 上time_t类型的说明
#ifndef _CRT_NO_TIME_T
#ifdef _USE_32BIT_TIME_T
typedef __time32_t time_t;
#else
typedef __time64_t time_t;
#endif
#endif
typedef long __time32_t;
typedef __int64 __time64_t;
如果只是让time函数返回时间戳,我们就可以这样写:
time(NULL);//调⽤time函数返回时间戳,这⾥没有接收返回值
那我们就可以让⽣成随机数的代码改写成如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
//使⽤time函数的返回值设置种⼦
//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换
//设置随机数的生成起点
srand((unsigned int)time(NULL));
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main()
{
//设置随机数的生成起点
srand((unsigned int)time(NULL));
for (int i = 0; i < 10; i++)
{
printf("%d\n", rand());
}
return 0;
}
srand函数是不需要频繁调用的,⼀次运⾏的程序中调⽤⼀次就够了。
4. 设置随机数的范围
如果我们要⽣成0~99之间的随机数,⽅法如下:
rand() % 100;//余数的范围是0~99
如果要⽣成1~100之间的随机数,⽅法如下:
rand()%100+1;//%100的余数是0 ~ 99,0 ~ 99的数字+1,范围是1~100
如果要⽣成100~200的随机数,⽅法如下:
100 + rand()%(200-100+1)
//余数的范围是0 ~ 100,加100后就是100~200
所以如果要⽣成a~b的随机数,⽅法如下:
a + rand()%(b-a+1)
2. 猜数字游戏实现
代码
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//void 表示函数不返回任何值
void menu()
{
printf("***********************\n");
printf("****** 1. play ******\n");
printf("****** 0. exit ******\n");
printf("***********************\n");
}
void game()
{
//游戏逻辑
//1. 生成随机数
int r = rand() % 100 + 1;//生成随机数1~100
//2. 猜数字,一般不是一次猜对所以要使用循环
int guess = 0;
while (1)//只要没猜对就一直循环猜
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess < r)//如果猜的数字小于随机数r
{
printf("猜小了\n");
}
else if (guess > r)//如果猜的数字大于随机数r
{
printf("猜大了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
//设置随机数的生成起点
//整个工程中只调用一次就可以了,所以不放入void game函数中
srand((unsigned int)time(NULL));
//一上来就要打印菜单,所以就用do-while循环比较合适
do
{
//打印菜单调用函数
menu();
//选择
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
}while (input);
return 0;
}
还可以加上猜数字的次数限制,如果5次猜不出来,就算失败
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//void 表示函数不返回任何值
void menu()
{
printf("***********************\n");
printf("****** 1. play ******\n");
printf("****** 0. exit ******\n");
printf("***********************\n");
}
void game()
{
//游戏逻辑
//1. 生成随机数
int r = rand() % 100 + 1;//生成随机数1~100
//2. 猜数字,一般不是一次猜对所以要使用循环
int guess = 0;
int count = 5;//5次机会
while (count)//count不等于0就进入循环
{
printf("还有%d次机会\n", count);
printf("请猜数字:");
scanf("%d", &guess);
if (guess < r)//如果猜的数字小于随机数r
{
printf("猜小了\n");
}
else if (guess > r)//如果猜的数字大于随机数r
{
printf("猜大了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;//记住猜对了直接break跳出game函数了不经过后面的if (count == 0)
}
count--;//猜一次count(次数减少一次)
}
//到这要么就是count已经为0了没有机会了,要么就是已经猜对了跳出来了
if (count == 0)
{
printf("用完了所有的机会,猜数字失败,正确的值是:%d\n",r);
}
}
int main()
{
int input = 0;
//设置随机数的生成起点
//整个工程中只调用一次就可以了,所以不放入void game函数中
srand((unsigned int)time(NULL));
//一上来就要打印菜单,所以就用do-while循环比较合适
do
{
//打印菜单调用函数
menu();
//选择
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
}while (input);
return 0;
}