前言
本章学习分支语句和循环语句 C语言是结构化的程序设计语言 结构有以下三种:顺序、选择、循环 语句:C语言中由一个分号;隔开的为一个语句 如 int i = 0;
分支语句(选择结构)
if语句
语法结构: ①
if(表达式)
语句;
表达式结果为真,则执行语句;为假,不执行
C语言中0为假,非0值为真
如:
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("未成年");
}
return 0;
}
②
if(表达式)
语句1;
else(表达式)
语句2;
如:
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("未成年");
}
else
{
printf("成年");
}
return 0;
}
③(多分支)
if(表达式1)
语句1;
else if(表达式2)
语句2;
:
:
else
语句n;
如:
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("少年");
}
else if(18<=age&&age<30)
{
printf("青年");
}
else if(30<=age&&age<50)
{
printf("中年");
}
else if (50 <= age && age < 80)
{
printf("老年");
}
else
{
printf("老不死");
}
return 0;
}
int age=10;
if(18<=age<30)
printf("中年");
其判断逻辑为:先判断18<=age,即18<=10为假,结果为0 再判断0<30为真,结果为1,则显示中年,而10岁明显不是中年,则错误 正确写法:if(18<=age&&age<30) "&&“为逻辑操作符,意为"且”,同时满足才为真. ②if条件判断的错误写法2
int a= 1;
if (a = 2)
{
printf("hehe");
}
return 0;
=:赋值操作符 ==:关系操作符,测试"相等" 上述例子应改为if(a==2) 小技巧:写成if(2==a),这样若少写一个=,即if(2=a),则编译器会报错(变量不可赋值给常量) ③执行多条语句应用代码块{}括起来 if语句只能控制后面一条语句,若想控制多条语句,则用{}
int age = 10;
if (age > 18)
printf("成年");
printf("可以谈恋爱");
return 0;
显示:可以谈恋爱
④悬空else
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
else匹配原则:与距离最近的未匹配的if进行匹配 规范写法:
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
练习:
- 判断一个数是否为奇数
- 输出1-100之间的奇数
- 判断一个数是否为奇数
int main()
{
int n = 0;
scanf("%d", &n);
if (0 == n % 2)
{
printf("不是奇数");
}
else
{
printf("是奇数");
}
return 0;
}
- 输出1-100之间的奇数
int main()
{
int i = 1;
while (i <= 100)
{
if (1 == i % 2)
{
printf("%d ", i);
}
i++;
}
return 0;
}
siwtch语句
switch语句也是分支语句,常用于多分支的情况.比if…else if…else更优\更简便 语法结构:
switch (整型表达式)
{
case 整型常量表达式:
语句;
}
switch常与break搭配使用,达到分支效果 如:
int main()
{
int day = 0;
scanf("%d",&day);
switch(day)
{
case 1:
prtinf("星期一\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;
default:
printf("输入错误");
}
}
说明:case为入口,break为出口.若无break,则会一直往下运行. default:若case整型常量表达式均不满足,则执行default中的语句.default位置可在任意case语句的位置(习惯放在最后)
是否添加break由我们所想达到的效果决定. 上述例子,若我们想在输入1,2,3,4,5后,显示"工作日";输入6,7,显示"休息日". 则代码为:
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:
printf("输入错误");
}
}
建议不要漏break和default,养成良好的编程习惯
include <stdio.h>
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch (n)
{
case 1:
n++;
case 2:
m++;
n++;
break;
}
case 4:
m++;
break;
default:
break;
}
printf("m = %d, n = %d\n", m, n);
return 0;
}
break只跳出一层所在的switch语句
循环语句
while语句
语法结构:
while (表达式)
{
语句;
}
先来看下if和while的关系:
if (1)
{
printf("hello");
}
return 0;
而将if改为while后:
while (1)
{
printf("hello");
}
return 0;
区别: 若判断条件为真,if语句只执行一次语句,而while语句会一直执行
int main()
{
int i = 1;
while(i<=10)
{
if (5==i)
break;
printf("%d ",i);
i++;
}
return 0;
}
总结: 循环中遇到break,则终止后面所有的循环,直接结束循环. while中的break作用是永久终止循环
int main()
{
int i = 1;
while(i<=10)
{
if (5==i)
continue;
printf("%d ",i);
i++;
}
return 0;
}
总结:continue终止本次循环,即continue后面的代码不会执行,直接跳到while的判断部分,进行下一次循环的入口判断.
getchar()函数
getchar()函数: ①从缓冲区读取一个字符,返回类型为整型(字符型char本质是ASCII值,为整型) ②使用要包含头文件stdio.h ③getchar()函数不仅可以从输入设备获得一个可显示的字符,而且可以获得屏幕上无法显示的字符,如控制字符回车换行,空格等. 注意:1.因为getchar返回类型为整型,所以创建存放字符的变量的类型为整型,如int ch; 2.gecharr()读取失败会返回EOF(end of file:文件结束标志),值为-1(整型) 直接上代码:
int main()
{
int ch = 0;
char password[20] = {0};
printf("请输入密码>:");
scanf("%s",password);
printf("确认密码(Y/N)>:");
ch = getchar();
if(ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}
运行程序:在键盘输入密码123456,并敲下回车键,结果为确认失败.
程序分析: ①scanf函数读取123456,并不会读取\n,后存到password数组. ②因为缓冲区余下\n,所以getchar函数会直接读取\n,存到ch变量,不会等待键盘输入. ③\n==‘Y’,为假,则"确认失败". 解决方法:缓冲区余下\n,导致不暂停(等待输入),则用getchar();清理缓冲区.
int main()
{
int ch = 0;
char password[20] = {0};
printf("请输入密码>:");
scanf("%s",password);
getchar();
printf("确认密码(Y/N)>:");
ch = getchar();
if(ch == 'Y')
{
printf("确认成功\n");
}
else
{
printf("确认失败\n");
}
return 0;
}
次方法不可取,应用范围有限: 当输入为:12345 abc(中间有空格),仍为"确认失败". 程序分析: ①缓冲区为12345 abc\n. ②scanf函数遇到空格会停止.(不读取空格) ③getchar函数读取空格后,缓冲区还剩下abc\n. ④下一个getchar函数读取a,a=='Y’为假,则"确认失败".
优化方法:上述方法只用了一次getchar,无法保证读取的字符一定是\n.优化思路:用循环和空语句取走scanf读取字符后留在缓冲区的字符.
int main()
{
int ch = 0;
char password[20] = {0};
printf("请输入密码>:");
scanf("%s",password);
while((ch = getchar()) != '\n')
{
;
}
printf("确认密码(Y/N)>:");
ch = getchar();
……
}
程序分析:getchar读取余下的字符,若ch!=’\n’,什么都不做,只是取走,再回到判断部分,直到遇到\n,\n!=’\n’为假,跳出循环.此时\n已被取走,缓冲区清理完毕.
for语句
语法结构:
for(表达式1; 表达式2; 表达式3)
循环语句;
表达式1:初始化部分
表达式2:条件判断部分
表达式3:调整部分
和while语句相比: ①for语句三个部分集中,便于更改,优于while语句 ②当使用continue时,while语句需要判断continue和调整语句的相对位置来决定是否执行调整语句;而for语句,则一定会执行调整语句.
int main()
{
int i = 0;
for(i=1;i<=10;i++)
{
if(5==i)
{
continue;
}
printf("%d",i);
}
}
- for语句的建议:
①不可在for循环体内改变循环变量
int main()
{
int i = 0;
for(i=1;i<=10;i++)
{
if(i = 5)
printf("%d",i);
}
return 0;
}
②建议初始化部分和条件判断部分采取"前闭后开"写法. 如for( i = 0;i < 10; i++),指明0到9,10个元素.
- for语句的变形:
变形①:省略初始化,条件判断,调整三部分
for (; ; )
{
printf("haha");
return 0;
}
语法上可以省略,但当省略条件判断部分,那判断部分恒为真,进入死循环.
变形②:初始化,条件判断,调整三部分可以是一条语句,也可多条.
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{
printf("hehe\n");
}
return 0;
变形③:省略初始化部分
int main()
{
int i = 0;
int j = 0;
for( ; i < 10 ; i++)
{
for( ; j<10 ; j++)
{
printf("hello\n");
}
}
}
程序分析: ①i=0且i<10进入内层循环,从j=0到j=10打印了10次hello后跳出内层循环. ②i++后i=1且i<10,但此时j=10(没有初始化),则后续i一直自增但不会再打印.
下面为关于for的一道面试题:判断循环的次数
int main()
{
int i = 0;
int k = 0;
for(i = 0 , k = 0 ; k = 0 ; i++ , k++)
{
k++;
}
return 0;
}
0次,k=0为赋值语句,为假,不执行.
do while语句
语法结构:
do
{
循环语句;
}while(表达式)
do…while语句至少执行一次,使用场景有限,少用.
实例:
int main()
{
int i=1;
do{
printf("%d",i);
i++;
}while(i<=10);
return 0;
}
在do…while语句中使用continue,continue会跳过后面的语句来到while的判断部分(类似在while语句中),需要根据continue和调整部分的相对位置来决定是否执行.
练习: 1.计算n的阶乘 2.计算1!+2!+3!+……+10! 3.再一个有序数组中查找具体的某个数字n。编写int binsearch(intx,intv[],int n);功能:再v[ 0 ]<=v[1]<=v[2]<=…<=v[n-1]的数组中查找x 4.编写代码,演示多个字符从两端移动,向中间汇聚 5.编写代码实现,模拟用户登录情景,并且只能登录三次。(值允许输入三次密码,如果密码正确则提示成功,如果三次均输入错误,则退出程序)
1.计算n的阶乘
#include<stdio.h>
int main()
{
int n, i, ret = 0;
scanf("%d", &n);
ret = 1;
i = 1;
do
{
ret *= i;
i++;
} while (i <= n);
printf("%d", ret);
return 0;
}
2.计算1!+2!+3!+……+10!
#include<stdio.h>
int main()
{
int n, i = 0;
int sum = 0;
int ret = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
ret *= i;
sum += ret;
}
printf("%d", sum);
return 0;
}
3.在一个有序数组中查找具体的某个数字n. 普通的方法:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
if (k == arr[i])
{
printf("找到了,他的下标为%d", i);
break;
}
}
if (i == sz)
{
printf("找不到\n");
}
return 0;
}
分析:显然逐一查找效率很低,当从1-10000中找到9999则要花费很长时间.面对有序数组(可由冒泡排序得到),我们可以用二分查找法(折半查找法)
二分查找法:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int left = 0;
int right = sz - 1;
while (left<=right)
{
int mid = (left + right) / 2;
if (k > arr[mid])
{
left = mid - 1;
}
else if (k < arr[mid])
{
right = mid - 1;
}
else
{
printf("找到了,他的下标为%d\n", mid);
break;
}
}
if (left > right)
{
printf("找不到\n");
}
return 0;
}
4.编写代码,演示多个字符从两端移动,向中间汇聚
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<Windows.h>
int main()
{
char arr1[] = "i am a handsome boy";
char arr2[] = "###################";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
left++;
right--;
Sleep(1000);
system("cls");
}
printf("%s\n", arr2);
return 0;
}
Sleep()函数: 让屏幕休息一段时间,如Sleep(1000),可让屏幕休息1000ms,即1s.其头文件为Windows.h system()函数: 执行系统命令,如system(“cls”); 为执行系统命令中的一个函数,其作用为清空屏幕,其头文件为stdlib.h
5.编写代码实现,模拟用户登录情景,并且只能登录三次。
#include<stdio.h>
int main()
{
char arr[] = "123456";
char password[21] = "";
int i = 0;
printf("请输入密码:\n");
for (i = 0; i < 3; i++)
{
scanf("%s", password);
if (0 == strcmp(arr, password))
{
break;
}
else
{
printf("密码错误,请重新输入:\n");
}
}
if (3 == i)
{
printf("输入次数用尽");
}
else
{
printf("登陆成功");
}
return 0;
}
注意:
if (password == arr)
这是错误写法.passwor和arr都是数组的数组名,表示数组的地址,这里比较的是两个数组的地址,显然是不相同的。 比较两个字符串应该使用strcmp()函数:
goto语句
语法结构:
C语言提供goto和标记跳转的标号,来改变程序流向,转到执行语句标号所标识的语句. goto语句用途:终止程序在某些深度嵌套的结构的处理过 程,例如一次跳出两层或多层循环.而break只能从某层循环跳到上一层循环.但goto不可跨函数跳转. 使用例子:
int main()
{
again:
printf("hello\n");
goto again;
return 0;
}
下面是有趣的使用goto的关机程序: 提示: 程序运行开始倒计时,若在1min内,输入"我是猪",则取消关机; 否则,嘿嘿嘿~
shutdown -s -60 系统在60秒后关机 代码为:system(“shutdown -s -t 60”); shutdown -a 取消关机 代码为:system(“shutdown -a”); 两者得包含在头文件stdlib.h里
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char input[20] = { 0 };
system("shutdown -s -t 60");
again:
printf("关机程序已开始,若输入:我是猪,将取消关机,请输入:\n");
scanf("%s", input);
if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
printf("成功取消关机");
}
else
{
printf("输入有误,请重新输入");
goto again;
}
return 0;
}
以Release的形式生成的.exe程序可以发给别人,也可以将该程序放进计算机自动启动的程序中。
|