分支语句与循环语句
1. 什么是语句
在c语言中语句分为以下五类:
- 表达式语句
- 函数调用语句
- 控制语句
- 复合语句
- 空语句
本章介绍的是控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它由特定的语句定义符组成,c语言有九种控制语句,可以分为以下三类:
- 条件判断语句也叫分支语句:if语句、switch语句;
- 循环执行语句:do while语句、while语句、for语句
- 转向语句:break语句、goto语句、continue语句、return语句
2. 分支语句(选择结构)
- if
- switch
1. if语句
1.1 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;
}
//结果什么都不打印
改正:
#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
else的匹配:else是和离它最近的if匹配的。
//代码1
int num = 1;
if(num==5)
{
printf("haha\n");
}
//代码2
int unm = 1;
if(5==num)
{
printf("haha\n");
}
//代码2比代码1更好,不容易出错
1.2 练习
- 判断一个数是否为奇数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d", &a);
if (a % 2 ==1)
{
printf("a是奇数");
}
else
{
printf("a不是奇数");
}
return 0;
}
- 输出1-100之间的奇数
#include<stdio.h>
//for循环
int main()
{
int i = 0;
for (i = 1;i <= 100;i++)
{
if (i % 2 ==1)
{
printf("%d ", i);
}
}
return 0;
}
//while循环
int i = 1;
while(i <= 100)
{
printf("%d ", i);
i += 2;
}
2. switch语句
switch(整型表达式)
{
语句项;
}
//语句项为case语句,如下
case 整型常量表达式:
语句;
2.1 在switch语句中的break
在switch语句中没法直接实现分支,搭配break才能实现真正的分支。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
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-5,输出weekday
- 输入6-7,输出weekend
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//没有break,程序会自动向下执行
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");
break;
}
return 0;
}
缺少break容易导致结果发生改变
int func(int a)
{
int b;
switch(a)
{
case1:b = 20;
case2:b = 30;
case3:b = 40;
default b = 0;
}
return b;
}
//没有default,fun(1)=b=0
2.2 default语句
当switch表达式的值并不匹配所有case标签的值时,这个default子句后面的语句就会执行,所以每个switch语句中只能有一个default子句,但它可以出现在语句列表的任意位置。
#include<stdio.h>
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch (n)//switch可以嵌套使用
{
case 1:
n++;
case 2:
m++;
n++;
break;//结束内层的switch,外层继续
}
case 4:
m++;
break;
default:
break;
}
printf("m = %d,n = %d\n", m, n);
return 0;
}
3. 循环语句
- while
- for
- do while
1. while语句
//while 语法结构
while(表达式)
循环语句;
1.1 while语句中的break和continue
break在while循环中的作用:
在循环中只要遇到break,就停止后期的所有循环,直接终止循环,所以,while中的break是用于永久终止循环的。
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;
printf("%d ", i);
i += 1;
}
return 0;
}
continue在while循环中的作用:
continue是用于终止本次循环的,也就是本次循环中continue后面的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i += 1;
}
return 0;
}
//这种情况再输出1 2 3 4后会直接进入死循环
改:
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
i += 1;
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
再看这几个代码:
#include<stdio.h>
//EOF-end of file-文件结束标志
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)//getchar可以读取字符
putchar(ch);//putchar可以输出字符
return 0;
}
getchar()
还可用来清理缓冲区
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:");
scanf("%s", password);//数组名本身就是地址因此不用&
printf("请确认密码(Y/N):");
int ch = getchar();
if (ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}
运行上述代码时可以发现,我们还没输入Y/N时,就自动显示确认失败了,这是因为没有清理缓冲区,当我们回车时,getchar()
自动读取了\n
,所以确认失败。
改进:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char password[20] = { 0 };
printf("请输入密码:");
scanf("%s", password);//数组名本身就是地址因此不用&
printf("请确认密码(Y/N):");
int tmp = 0;
while ((tmp = getchar() )!= '\n')//可以清理缓冲区直到读取到'\n'
{
;
}
int ch = getchar();
if (ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}
getchar()
返回的时ASCII码值(整数)。getchar()
在读取结束或失败时会返回EOF
。
//只打印数字字符,跳过其他字符
#include<stdio.h>
int main()
{
int ch = 0;
while ((ch=getchar())!=EOF)
{
if (ch < '0' || ch > '9')
continue;
putchar(ch);
}
return 0;
}
2. for循环
for(表达式1;表达式2;表达式3)
循环语句;
//表达式1为初始化部分,用于初始化循环变量。
//表达式2为条件判断部分,用于循环变量终止时使用。
//表达式3为调整部分,用于循环条件的终止。
缺少或改变哪一部分都可能导致循环改变。
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (i = 0;i < 3;i++)
{
for (j = 0;j < 3;j++)
{
printf("haha\n");
}
}
return 0;
}
当缺少初始化条件时:
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (;i < 3;i++)
{
for (;j < 3;j++)//第一次外循环结束时j的值变为3,因为没有初始化,后面的循环中保持不变
{
printf("haha\n");
}
}
return 0;
}
2.2 break和continue在for循环中
意义和在while循环中差不多,但还是有些差别。
#include<stdio.h>
int main()
{
int i = 0;
for (i = 1;i <= 10;i++)
{
if (i == 5)
break;
printf("%d ", i);
}
return 0;
}
//只打印1 2 3 4就结束循环
#include<stdio.h>
int main()
{
int i = 0;
for (i = 1;i <= 10;i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
//跳过5打印其余数字
2.3 for语句的循环控制变量
建议:
- 不可在for循环体内修改循环变量,防止for循环失去控制。
- 建议for语句的循环控制变量的取值采用"前闭后开区间"写法。
int i = 0;
//前闭后开写法
for (i = 0;i < 10;i++)
//两边都是闭区间
for (i = 0;i <= 9;i++)
2.4 一些for循环的变种
#include<stdio.h>
//使用多一个变量控制循环
int main()
{
int x = 0;
int y = 0;
for (x = 0, y = 0;x < 2 && y < 5;x++, y++)
{
printf("hehe\n");
}
return 0;
}
#include<stdio.h>
int main()
{
int i = 0;
int k = 0;
for (i = 0, k = 0;k=0;i++, k++)//条件判断部分k赋值为了0,恒为假,循环0次,若省略判断部分会死循环
{
k++;
}
return 0;
}
3. do…while()循环
循环至少执行依次,使用场景有限
do
循环语句;
while(表达式);
3.1 do…while循环中的break和continue
int main()
{
int i = 10;
do {
if (5 == i)
break;
printf("%d\n", i);
} while (i < 10);
return 0;
}
//只打印一个10就停止循环
#include<stdio.h>
int main()
{
int i = 5;
do
{
if (5 == i)
continue;
printf("%d\n", i);
} while (i < 10);
return 0;
}
//continue直接跳转到while判断部分,所以结果不打印
4. goto语句
goto最常见用法时终止程序某些深度嵌套的结构的处理过程,例如:一次跳出两层或多层循环,多层循环中break是达不到目的的,它只能从最内层循环退出到上一层循环。
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error;
}
}
...
error:
if(disaster)
//处理错误情况
//goto 语句只能在一个函数范围内跳转,不能跨函数
void test()
{
flag:
printf("hahah")
}
int main()
{
goto flag;//会报错!
return 0;
}
关机程序
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");//system()执行系统命令,需添加头文件<stdlib.h>
again:
printf("电脑将在一分钟后关机,如果输入:我是猪,可以取消关机");
scanf("%s", input);
if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
}
else
{
goto again;
}
return 0;
}
也可以使用while循环
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");
while (1)
{
printf("电脑将在1分钟后关机,如果输入:我是猪,可以取消关机");
scanf("%s", input);
if (0==strcmp(input, "我是猪"))
{
system("shutdown -a");
break;
}
}
return 0;
}
5. 综合练习
1. 计算n的阶乘
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 0;
int i = 0;
int ret = 1;
scanf("%d", &n);
for (i = 1;i <=n;i++)
{
ret *= i;
}
printf("%d", ret);
return 0;
}
2. 计算1!+2!+3!+…+n!
//方法1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 0;
int i = 0;
int ret = 1;
int sum = 0;
scanf("%d", &n);
for (i = 1;i <=n;i++)
{
ret *= i;
sum += ret;//后一个数只相当于比前一个数多乘了它本身
}
printf("%d", sum);
return 0;
}
//方法2
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 0;
int i = 0;
int j = 0;
int ret = 1;
int sum = 0;
scanf("%d", &n);
for (j = 1; j <= n; j++)
{
ret = 1;//计算n的阶乘之前把ret初始化为1
for (i = 1; i <= j; i++)
{
ret *= i;
}
sum += ret;
}
printf("%d", sum);
return 0;
}
3. 编写代码,演示多个字符从两端移动,向中间汇聚。
//while循环写法
#include<stdio.h>
#include<string.h>
#include<windows.h>//Sleep()头文件和system
int main()
{
char arr1[] = "welcome to sty";
char arr2[] = "##############";
int left = 0;
int right = strlen(arr1) - 1;//通过字符个数得数组末尾元素下标,-1是减去'\0'
printf("%s\n", arr2);
while (left <= right)
{
Sleep(1000);
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
left++;
right--;
}
return 0;
}
//for循环写法
for (left = 0, right = strlen(arr1) - 1;left < right;left++, right--)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);//间隔1s出现
system("cls");//清理屏幕
}
//保留单行,逐步显示
#include<stdio.h>
#include<string.h>
#include<windows.h>
int main()
{
char arr1[] = "welcome to sty";
char arr2[] = "##############";
int left = 0;
int right = strlen(arr1)-1;
for (left = 0, right = strlen(arr1) - 1;left < right;left++, right--)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);//休眠1秒
system("cls");//清空屏幕
}
printf("%s\n", arr2);
return 0;
}
4. 在一个有序数组中查找某个具体数字n。
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;
int right = sizeof(arr) / sizeof(arr[0])-1;
int key = 7;
int mid = 0;
while (left<=right)
{
mid = (left + right) / 2;
if (arr[mid]>key)
{
right = mid - 1;
}
else if(arr[mid]<key)
{
left = mid + 1;
}
else
{
break;
}
}
if (left <= right)
{
printf("找到了,下表是%d", mid);
}
else
{
printf("找不到了");
}
return 0;
}
//二分查找函数
int bin_search(int arr[], int left,int right,int key)
{
int mid = 0;
while (left <= right)
{
mid = (left + right) / 2;
if (arr[mid] > key)
{
right = mid - 1;
}
else if (arr[mid] < key)
{
left = mid + 1;
}
else
{
break mid;//找到目标值
}
}
return -1;//没有找到返回-1
}
5. 猜数字游戏
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void menu()
{
printf("***************************\n");
printf("**********1. play *********\n");
printf("**********0. exit *********\n");
printf("***************************\n");
}
void game()
{
int random_num = rand() % 100 + 1;//得到一个1-100之间的随机数
int guess = 0;
while (1)
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess > random_num)
{
printf("猜大了\n");
}
else if (guess < random_num)
{
printf("猜小了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//强制类型转化time的类型为与srand相同,time()为调用时间戳,需使用头文件<time.h>,srand()可以使用随机数生成器,其头文件为<stdlib.h>
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;
}
6.将三个整数从大到小输出
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int c = 0;
int tmp = 0;
scanf("%d%d%d", &a, &b, &c);
if (a < b)
{
tmp = a;
a = b;
b = tmp;
}
if (a < c)
{
tmp = a;
a = c;
c = tmp;
}
if (b < c)
{
tmp = b;
b = c;
c = tmp;
}
printf("%d %d %d\n", a, b, c);
return 0;
}
7. 打印1-100之间3的倍数
//方法1
#include<stdio.h>
int main()
{
int i= 0;
for (i = 1;i <= 100;i++)
{
if(i%3==0)
{
printf("%d ", i);
}
}
return 0;
}
//方法2
#include<stdio.h>
int main()
{
int i= 0;
for (i = 3;i <= 100;i+=3)
{
printf("%d ", i);
}
return 0;
}
8.给定两个数,求两个数的最大公约数
//方法1:辗转相除法
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
scanf("%d%d", &i, &j);
int a = 0;//假设a为余数
while (a=i % j)
{
i = j;
j = a;
}
printf("最大公约数为:%d", j);
return 0;
}
//方法2:最大公约数一定在较小数的范围内
int main()
{
int i= 0;
int j = 0;
scanf("%d%d", &i, &j);
int max = i < j ? i : j;
while (1)
{
if (i % max == 0 && j % max == 0)
{
printf("最大公约数为:%d", max);
break;
}
max--;
}
return 0;
}
//最小公倍数=i*j/最大公约数,或者最小公倍数一定是较大值的倍数,一直+1试就行
9. 打印1000年到2000年之间的闰年
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int i = 0;
int count = 0;
for (i = 1000;i <= 2000;i++)
{
if ((i % 4 == 0) && (i % 100 != 0)||(i%400==0))
{
printf("%d ", i);
count++;
}
}
printf("\ncount=%d ", count);
return 0;
}
10. 打印100-200之间的素数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (i = 100;i <= 200;i++)
{
for (j = 2;j < i;j++)//用2-i-1之间的数看能否整除
{
if (i % j == 0)
break;
}
if (i == j)
{
printf("%d ", i);
}
}
return 0;
}
//改进,若m=a*b,则a和b中一定有一个数<=sqrt(m)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
int main()
{
int i = 0;
int j = 0;
int count = 0;
for (i = 100;i <= 200;i++)//也可改成(i=101;i<=200;i+=2)直接排除偶数
{
int flag = 1;
for (j = 2;j <= sqrt(i);j++)//sqrt()为开平方根,需使用头文件<math.h>
{
if (i % j == 0)
{
flag = 0;
break;
}
}
if (flag==1)
{
printf("%d ", i);
count++;
}
}
printf("\ncount=%d", count);
return 0;
}
11. 编写程序数一下1-100出现多少个数字9
#include<stdio.h>
#include<string.h>
int main()
{
int i = 0;
int count = 0;
for (i = 1;i <= 100;i++)
{
if (i % 10 == 9)
{
count++;
}
if (i / 10 == 9)
{
count++;
}
}
printf("%d", count);
return 0;
}
12. 计算1/1-1/2+1/3-1/4+1/5-…+1/99-1/100的值,打印出结果
//方法1
#include<stdio.h>
#include<string.h>
int main()
{
int i = 0;
double sum = 0;
for (i = 1;i <= 100;i++)
{
if (i % 2 == 0)
{
sum -= 1.0 / i;
}
else
{
sum += 1.0 / i;
}
}
printf("%lf\n", sum);
return 0;
}
//方法2
int main()
{
int i = 0;
double sum = 0;
int flag = 1;
for (i = 1;i <= 100;i++)
{
sum += flag * 1.0 / i;
flag = -flag;
}
printf("%lf\n", sum);
return 0;
}
13. 求10个整数中的最大值
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int max = arr[0];//既可以求正数也可以求负数
int i = 0;
for (i = 0;i < 10;i++)
{
if (arr[i > max])
{
max = arr[i];
}
}
printf("%d\n", max);
return 0;
}
14. 打印9*9乘法口诀表
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (i = 1;i <= 9;i++)
{
for (j = 1;j <= i;j++)
{
printf("%d*%d=%-2d ", i, j, i * j);//%2d可以打印两位,%-2d可以左对齐
}
printf("\n");
}
return 0;
}
15. 模拟输入密码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int i = 0;
char password[20] = { 0 };
for (i = 0; i < 3; i++)
{
printf("请输入密码:");
scanf("%s", password);
if (strcmp(password, "777") == 0)//strcmp比较的是对应字符的ASCII大小
{
printf("密码正确\n");
break;
}
else
{
printf("密码错误\n");
}
}
if (i == 3)
{
printf("三次密码错误,退出程序");
}
return 0;
}