目录
3.5 break和continue在do while循环中的应用
一.语句的种类
C语言可以分为一下五类:
1.表达式语句
2.函数调用语句
3.控制语句(重点掌握)
4.复合语句
5.空语句
这里先介绍控制语句:
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成,C语言有九种控制语句
可分成以下三类:
1. 条件判断语句也叫分支语句:if语句、switch语句
2. 循环执行语句:do while语句、while语句、for语句
3. 转向语句:break语句、goto语句、continue语句、return语句
二.分支语句(选择)
1.if语句
if语句语法结构:
if(表达式)
语句;
或者
if(表达式)
语句1;
else
语句2;
或者//多分支的条件选择
if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
注意:如果if后面接多个语句,那么i判断要使用大括号把语句全部囊括起来,不然会报错,else和else if同理,如下:
#include <stdio.h>
int main()
{
if (表达式)
{
语句列表1;
}
else
{
语句列表2;
}
return 0;
}
下面我进行一个年龄的判断
int age = 10;
if (age < 18)
printf("青少年\n");
else if (18 <= age < 28)
printf("青年\n");
注意:这种写法是错误的,因为如果这样写的话,else if也会进行判断。
原因;程序定义了年龄为10,如果程序运行,首先判断if语句,if里面条件为真(非0),可以打印出来,但是在判断else if的时候首先判断18<=age这个条件,这个结果判断为假(0),则else if里面条件变成else if(0<28),判断为真,青年也打印了,正好相反的两个判断都输出了,导致程序出错(这里解释一下,在C语言里面0表示假,非0表示真,在判断的时候,只有表达式为真,才会输出结果)
下面演示正确写法:
int age = 10;
if (age < 18)
printf("青少年\n");
else if (age>=18&&age<28)
printf("青年\n");
注:&&这个符号的意思是并且,和集合里面的并集概念相似
下面是完整代码
#include<stdio.h>
int main()
{
int age;
printf("请输入你的年龄:");
scanf("%d", &age);
if (age < 18)
printf("青少年\n");
else if (age >= 18 && age < 28)
printf("青年\n");
else if (age >= 28 && age < 40)
printf("中年\n");
else if (age >= 40 && age < 60)
printf("壮年\n");
else if (age >= 60 && age < 100)
printf("老年\n");
else
printf("老寿星\n");
return 0;
}
当你写了这个代码:
#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 (a == 1)
{
if (b == 2)
printf("hehe\n");
else //else进行就近匹配
printf("haha\n");}
如果想打印hehe,以下是代码修改
if (a == 0)
{
if (b == 2)
printf("hehe\n");}
else
printf("haha\n");
如果想打印haha,以下是代码修改
#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;
}//此程序打印haha
2.switch语句
switch语句常常用于多分支的情况
例如:实现如下要求
输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4, 输出星期四
输入5, 输出星期五
输入6,输出星期六
输入7,输出星期日
如果写成if-else语句就太复杂了,所以引入了switch语句形式
下面通过switch语句判断星期:
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期一\n");break;
case 2:
printf("星期二\n");break;
case 3:
printf("星期三\n");break;
case 4:
printf("星期四\n");break;
case 5:
printf("星期五\n");break;
case 6:
printf("星期六\n");break;
case 7:
printf("星期日\n");break;
}
return 0;
}
注:
1.switch里面一定要是整型常量,case后面跟的也要是整型常量,在case后面添加break语句是为了防止穿透;
2.break 语句在 switch 语句中的作用是终止当前的 switch 块执行,并跳出 switch 结构。如果没有 break 语句,程序会继续执行下一个 case 块的代码,即使它不匹配当前的 switch 表达式的值,这种现象称为“穿透”。
switch (整型常量)
{
case value1:
// 执行代码块1
break; // 退出switch语句
case value2:
// 执行代码块2
break; // 退出switch语句
// ...
}
如果你希望实现穿透效果,可以省略 break 语句:
switch (整型常量)
{
case value1:
// 执行代码块1
// 没有break,代码会继续执行下一个case
case value2:
// 执行代码块2
break; // 退出switch语句
// ...
}
注:在这个例子中,如果 整型变量的值匹配 value1,那么程序会执行 case value1: 下的代码块,然后因为没有 break,会继续执行 case value2: 下的代码块,直到遇到一个 break 或者 switch 结构结束。
以下要求就是穿透效果的实现:
1. 输入1-5,输出的是“weekday”;
2. 输入6-7,输出“weekend”
我们的代码就变成这样了
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");break;
case 6:
case 7:
printf("weekend\n");break;
}
return 0;
}
如果我们输出错误,比如说输入了8

我们可以看见什么都不会输出,但是星期八在生活中是不可能的,所以我们引入了defalut字句,功能是所有case不能匹配的都走到default这里来
#include<stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");break;
case 6:
case 7:
printf("weekend\n");break;
default:
printf("选择错误\n");break;
}
return 0;
}
代码实现效果如下:

3.练习
#include <stdio.h>
int main()
{
int n = 1; // 初始化n为1
int m = 2; // 初始化m为2
switch (n)
{
case 1:
m++; // 当n为1时,m自增
// 穿透到case 2
case 2:
// case 2不需要执行任何操作
break; // 添加break以防止穿透
case 3:
{
switch (n) //switch语句允许嵌套
{
case 1:
n++; // 当嵌套switch的case 1时,n自增
// 穿透到case 2
case 2:
m++; // 当嵌套switch的case 2时,m自增
n++; // m自增后,n自增
break; // 退出嵌套switch
}
}
// 穿透到case 4
case 4:
m++; // 当n为4时,m自增
break; // 添加break以防止穿透
default:
break; // 默认情况下不需要执行任何操作
}
printf("m = %d, n = %d\n", m, n); // 输出m和n的值
return 0; // 程序结束
}
输出结果:m=5,n=3
三.循环语句
1.while循环
while语句执行的流程:

比如在屏幕上输出1~10
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
printf("%d ", i);
i = i+1;
}
return 0;
}
如果代码是这样的,那么输出为多少呢?
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;printf("%d ", i);
i++;
}return 0;
}
输出:1 2 3 4原因:当i=4时,i自增为5,进行判断后,如果i=5,则跳出这个循环,break是作用于while这个循环
把break改成continue之后,又会发生什么呢?
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;//替换breakprintf("%d ", i);
i++;
}return 0;
}输出:1 2 3 4 死循环
原因:
1.当i为5时,if条件满足,执行continue语句,跳过打印和i++,直接进行下一次循环的判断,此时i仍然是5。
2.由于continue语句导致跳过了i++,i的值在第一次循环到5时没有增加,所以在下一次循环条件检查时,i仍然是5,再次满足if条件,再次执行continue。
3.这个过程会一直重复,直到程序的某次迭代中i的值不再是5,但由于i的值没有增加,这将导致无限循环。
如果把程序改成这样:
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{i++;//将i自增移上来
if (i == 5)
continue;printf("%d ", i);
}return 0;
}输出:2 3 4 6 7 8 9 10 11
原因:在i等于5时,continue语句导致跳过了打印,但在下一次循环中,i自增到了6,并继续执行后续打印操作
while循环总结:
1.break是用于终止的永久循环
2.continue跳过本次循环后面的代码,直接去判断部分,进行下一次循环的判断
接下来举几个比较实用的代码
代码1:用来清理缓冲区
int main()
{
//EOF;//end of file//EOF的定义是数字-1
int ch = 0;
while ((ch = getchar()) != EOF)
{putchar(ch);
}//
先介绍下什么是缓冲区,缓冲区(Buffer)是一种内存区域,用于暂时存储数据。gechar函数在缓冲区是空的时候就会进行等待,直到缓冲区里面进入字符;putchar函数拿到的就是getchar函数拿到的所有字符,但是getchar函数每次只会拿一个字符。
下面我举一个例子:
#include<stdio.h>
int main()
{//假设密码是字符型的
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s",password);//数组名本身就是一个地址,所以这里不用加&
printf("请确认密码(Y/N):>");
int ret = getchar();
if('Y'== ret)
{
printf("Yes\n");}
else
{
printf("No\n");
}
return 0;
}

运行上述程序,并输入密码,为什么没有进行Y/N的判断呢,就直接输出NO了呢,这是什么原因?
其实原因很简单,在我们输入密码后,缓冲区里面实际上是abcdef\n,但是scanf函数在读取输入时,默认会在遇到空白字符(如空格、制表符\t或换行符\n)时停止读取当前字段,所以scanf函数只拿走了abcdef,缓冲区里面实际上还剩一个\n,这时候程序继续往下运行,getchar函数拿走了缓冲区里面的\n赋值给了ret,通过判断ret不等于Y,所以这时候输出了NO,如图所示:

那我们应该怎么改正这种情况,才能够让赋值给ret的getchar拿到我们输出的Y呢,是不是只要在getchar函数前面在加一个getchar拿走\n就可以了。
改进函数如下:
#include<stdio.h>
int main()
{//假设密码是字符型的
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s",password);//数组名本身就是一个地址,所以这里不用加&
getchar();//读取并拿走了\n
printf("请确认密码(Y/N):>");
int ret = getchar();
if('Y'== ret)
{
printf("Yes\n");}
else
{
printf("No\n");
}
return 0;
}
在scanf函数后面加入一个getchar,这时候这个getchar拿走的就是缓冲如里面的\n,这个时候的缓冲区其实是空的,所以程序后面的getchar就开始等待键盘输入不会直接输出,这时候输入Y(N)就会输出Yes(No),如图所示:

运行结果如下:

但是这种写法并不是完全正确的写法,仅仅只是适用于这种的特殊情况,如果我把密码改成abcdef ghijk,再次运行程序就会发现:

原因:在scanf读取我们输入的密码时,他在读取到空格时就会停止,导致密码读取不完整,由于getchar每次只能拿一个字符,这时候getchar拿走的其实空格,空格后面还有一堆字符没有拿走,导致后面的getchar拿的是ghijk\n最前面的字符g,并把g赋值给了ret,所以这时候输出了No,如图所示:

所以我们要在下一个getchar获取数据时,要把缓冲区里面的字符全部拿走,代码如下;
#include<stdio.h>
int main()
{//假设密码是字符型的
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s",password);//数组名本身就是一个地址,所以这里不用加&
int ch = 0;
while ((ch = getchar()) != '\n')
{
putchar(ch);
}//这个代码就是把剩余的部分全部拿出来给ch,一直是拿到\n才停止
printf("请确认密码(Y/N):>");
int ret = getchar();
if('Y'== ret)
{
printf("Yes\n");}
else
{
printf("No\n");
}
return 0;
}
代码运行效果如图:
2.for循环
2.1 for循环语法
for(表达式1; 表达式2; 表达式3)
循环语句;
表达式1 表达式1为初始化部分,用于初始化循环变量的。
表达式2 表达式2为条件判断部分,用于判断循环时候终止。
表达式3 表达式3为迭代部分,用于循环条件的迭代。
for循环执行流程图:

如果需要打印出1~10数字,用for循环该怎么写,代码如下:
#include <stdio.h>
int main()
{
int i = 0;
//for(i=1/*初始化*/; i<=10/*判断部分*/; i++/*调整部分*/)
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
2.2 break和continue在for循环中的使用:
如若我在for循环里面添加break和continue会发生什么呢?例如:
代码1:
#include <stdio.h>
int main()
{
int i = 0;
//for(i=1/*初始化*/; i<=10/*判断部分*/; i++/*调整部分*/)
for (i = 1; i <= 10; i++)
{
if (i == 5)
break;
printf("%d ", i);
}
return 0;
}结果:1 2 3 4
代码2:
#include <stdio.h>
int main()
{
int i = 0;
//for(i=1/*初始化*/; i<=10/*判断部分*/; i++/*调整部分*/)
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}打印结果:1 2 3 4 6 7 8 9 10
2.3 for循环的一些变体
代码1:for循环中所有条件都不写
#include <stdio.h>
int main()
{
for (;;)
{
printf("hehe\n");
}}
结果:hehe死循环,原因for循环的判断部分省略意味着这判断会恒成立
代码2:for循环中的初始条件不写
#include <stdio.h>
int main()
{
int i = 0;
for ( ; i<10; i++)
{
printf("hehe\n");
}}
结果:10个hehe,但是我建议不要这样写
代码3:嵌套for循环
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
//这里打印多少个hehe?
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("hehe\n");
}
}
return 0;
}结果:9个hehe,在for循环嵌套中,外层循环每次经过一次初始化,内层循环在有初始化条件的情况下,也会进行初始化
代码4:嵌套for循环中的初始化条件不写
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
//这里打印多少个hehe?
for (; i < 3; i++)
{
for (; j < 3; j++)
{
printf("hehe\n");
}
}
return 0;
}结果:3个hehe,原因就是在j自增的过程中,当j自增到3时,由于再次运行到关于j的for循环,由于j循环没有初始化条件,导致j并没有初始化为0,导致j的for循环不会执行,所以在打印完第一次之后,就不会执行j的第二个for循环,导致之后不再打印hehe
下面是一道笔试题:
#include <stdio.h>
int main()
{
int i = 0;
int k = 0;
for (i = 0, k = 0; k = 0; i++, k++)
k++;
return 0;
}结果:循环0次,因为不管之前赋值为几,k总被赋值为0,0为假,直接跳出for循环
3.do while循环
3.1 do while定义
do while循环是一种在 C 语言等编程语言中使用的循环结构,它至少执行一次循环体,然后根据条件判断是否继续执行循环
3.2 do while循环语法结构
do
循环语句;
while(表达式);
3.3 do while循环的执行流程图

3.4 do while的应用
例如:利用do while循环打印1~10
#include<stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ", i);
i++;
}
while (i <= 10);
return 0;
}
3.5 break和continue在do while循环中的应用
代码1:break的应用
#include<stdio.h>
int main()
{
int i = 1;
do
{
if (i == 5)
break;//直接跳出这个循环
printf("%d ", i);
i++;
}
while (i <= 10);
return 0;
}输出结果: 1 2 3 4
代码2:将代码1修改,i++往上面移动
#include<stdio.h>
int main()
{
int i = 1;
do
{i++;
if (i == 5)
break;//直接跳出这个循环,终止循环
printf("%d ", i);
}
while (i <= 10);
return 0;
}输出结果:2 3 4
代码3:continue的应用
#include<stdio.h>
int main()
{
int i = 1;
do
{
if (i == 5)
continue;
printf("%d ", i);
i++;
}
while (i <= 10);
return 0;
}输出结果:1 2 3 4死循环
代码4:将代码3修改,i++往上面移动
#include<stdio.h>
int main()
{
int i = 1;
do
{i++;
if (i == 5)
continue;
printf("%d ", i);
}
while (i <= 10);
return 0;
}输出结果:2 3 4 6 7 8 9 10 11
4.循环语句练习
1. 计算 n的阶乘。
2. 计算 1!+2!+3!+……+10!
3. 在一个有序数组中查找具体的某个数字n。(讲解二分查找)
4. 编写代码,演示多个字符从两端移动,向中间汇聚。
5. 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则 提示登录成,如果三次均输入错误,则退出程序。(建议先自己写一写)
代码1:
#include<stdio.h>
int main()
{
int i = 1;
int n = 0;
int ret = 1;//声明一个整型变量ret,初始值为1。这个变量用于存储阶乘计算的结果
scanf("%d", &n);
for (i = 1;i <= n;i++)//i从1自增到n
{
ret = ret * i;//在循环体内,将ret的当前值与i相乘,并将结果重新赋值给ret
}
printf("%d\n", ret);
return 0;
}
代码2(写法一):
//计算 1!+2!+3!+……+10!
#include<stdio.h
int main()
{
int i = 1;
int n = 0;
int ret = 1;//定义一个整形ret,用来储存每次的阶乘
int sum = 0;//定义一个整型sum,用来储存每次阶乘的总和
for (n = 1;n <= 10;n++)
{
ret = 1;//每次循环之后将ret赋值为1,如果不赋值则会导致,ret使用第二次的变量
for (i = 1;i <= n;i++)//i从1自增到n
{
ret = ret * i;//计算每次的阶乘
}
sum = sum + ret;//计算每次的阶乘的总和
}
printf("%d\n", sum);//输出的1~10阶乘之和
return 0;
}
代码2(写法2):
//计算 1!+2!+3!+……+10!
#include<stdio.h>
int main()
{
int i = 1;
int n = 0;
int ret = 1;//定义一个整形ret,用来储存每次的阶乘
int sum = 0;//定义一个整型sum,用来储存每次阶乘的总和
for (n = 1;n <= 10;n++)
{
ret = ret * n;//计算n!
sum = sum + ret;//将当前ret的值加到sum上
}
printf("%d\n", sum);//输出的1~10阶乘之和
return 0;
}
代码3(二分查找):
//在一个有序数组中查找具体的某个数字n,二分查找
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//定义一个数组1-10
int k = 7;//定义要查找的数,下标是k
int i = 0;//定义一个整型i,用于跟数组匹配表示下标
int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素的数量
int left = 0;//数组左侧下标
int right = sz - 1;//数组最后一个元素下标
while(left <= right)//当左侧下标小于右侧下标,循环继续运行
{
int mid = (left + right) //这种写法可能会溢出
int mid = left + (right - left) //计算中间元素下标,防止溢出
if (arr[mid] < k) //检查中间位置的元素是否小于要查找的元素k
{
left = mid + 1; //将left更新为mid + 1,表示从mid的下一个位置开始继续搜索
}
else if (arr[mid] > k) //查中间位置的元素是否大于要查找的元素k
{
right = mid - 1; //将right更新为mid - 1,表示搜索范围结束于mid的前一个位置
}
else
{
printf("找到了,下标是%d\n", mid);
break;
}
}
if (left > right)
{
printf("找不到\n");
}
return 0;
}
代码4:
//编写代码,演示多个字符从两端移动,向中间汇聚
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
int main()
{
char arr1[] = "welcome to bit!!!!";
char arr2[] = "##################";
int left = 0;
int right = strlen(arr1) - 1;//计算的是\0之前的元素个数
//sizeof计算的是总的元素个数包括\0
//如果使用sizeof则是sizeof(arr1)/sizeof(arr1[0])-2
while (left <= right)//开始一个while循环,只要left小于等于right,循环就会继续
{
arr2[left] = arr1[left];//将arr1中对应left下标的字符复制到arr2的left下标位置
arr2[right] = arr1[right];//将arr1中对应right下标的字符复制到arr2的right下标位置
printf("%s\n", arr2);//打印当前的arr2字符串
Sleep(1000);
//清空屏幕
system("cls");//system是一个库函数,可以执行系统命令
left++;//增加left的值,向右移动
right--;//减少right的值,向左移动
}
printf("%s\n", arr2);
return 0;
}
代码5:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//猜数字游戏
//电脑产生一个随机数(1~`100)
//猜数字
//咱们猜一个,如果猜大了,电脑会提示猜大了
//如果猜小了,电脑会提示猜小了
void menu()
{
printf("***********************\n");
printf("****** 1. play ******\n");
printf("****** 0. exit ******\n");
printf("***********************\n");
}
//0-RAND_MAX(0-32767)
void game()
{
int guess = 0;
//1.生成随机数
int ret = rand()%100+1;//生成随机数1-100
//printf("%d\n", ret);
//2.猜数字
while(1)
{
printf("请猜数字:>");
scanf("%d", &guess);
if (guess < ret)
{
printf("猜小了\n");
}
else if (guess > ret)
{
printf("猜大了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
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;
}
四.goto语句
C语言中提供了goto语句,它允许无条件地跳转到程序中的任意位置,以及用于跳转的标签。理论上,goto语句并非必需,因为在实践中,即使不使用goto语句,也能够轻松编写代码。然而,在某些特定情况下,goto语句的使用仍然是有价值的,尤其是在需要从多层嵌套的结构中提前退出程序时,goto语句提供了一种便捷的处理方式。
例如:一次跳出多层嵌套
for (...)
{
for (...)
{
for (...)
{
if (disaster)
goto error;
}
}} …
error :
if (disaster)
// 处理错误情况
下面是使用goto语句的一个例子,然后使用循环的实现方式替换goto语句:
一个关机程序
#include <stdio.h>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");
again:
printf("电脑将在1分钟内关机,如果输入:我是猪,就取消关机!\n请输入:>");
scanf("%s", input); if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
}
else
{
goto again;
}
return 0;
}
而如果不适用goto语句,则可以使用循环:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");
while (1)
{
printf("电脑将在1分钟内关机,如果输入:我是猪,就取消关机!\n请输入:>");
scanf("%s", input);
if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
break;
}
}
return 0;
}


468

被折叠的 条评论
为什么被折叠?



