前言
本章学习分支语句和循环语句
C语言是结构化的程序设计语言
结构有以下三种:顺序、选择、循环
语句:C语言中由一个分号;隔开的为一个语句 如 int i = 0;
一、分支语句(选择结构)
2.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;
}
- 注意事项
-①if条件判断的错误写法1
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)//本意为判断a和2是都相等,实际将2赋值给a,条件为真,执行
{
printf("hehe");
}
return 0;
=:赋值操作符
==:关系操作符,测试"相等"
上述例子应改为if(a==2)
小技巧:写成if(2==a),这样若少写一个=,即if(2=a),则编译器会报错(变量不可赋值给常量)
③执行多条语句应用代码块{}括起来
if语句只能控制后面一条语句,若想控制多条语句,则用{}
int age = 10;
if (age > 18)
printf("成年");//10>18为假,不执行
printf("可以谈恋爱");//执行该条语句,证明该语句不受if控制
return 0;
显示:可以谈恋爱
④悬空else
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else//else看上去似和第一个if匹配,实际不是
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;
}
//int i = 1; printf("%d ",i+=2);
2.siwtch语句
switch语句也是分支语句,常用于多分支的情况.比if…else if…else更优\更简便
语法结构:
switch (整型表达式)
{
case 整型常量表达式:
语句;
}
switch常与break搭配使用,达到分支效果
如:
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;
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,养成良好的编程习惯
- switch可嵌套使用
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;
}
case 4:
m++;
break;
default:
break;
}
printf("m = %d, n = %d\n", m, n);
return 0;
}
//m=5,n=3
break只跳出一层所在的switch语句
二、循环语句
1.while语句
语法结构:
while (表达式)
{
语句;
}
先来看下if和while的关系:
if (1)
{
printf("hello");
}
return 0;
//显示 hello
而将if改为while后:
while (1)
{
printf("hello");
}
return 0;
//显示死循环的hello
区别: 若判断条件为真,if语句只执行一次语句,而while语句会一直执行
- break在while语句中的作用
如:
int main()
{
int i = 1;
while(i<=10)
{
if (5==i)//当i==5时,break跳出后面所有的循环
break; //break:永久终止循环
printf("%d ",i);
i++;
}
return 0;
}
//显示结果:1 2 3 4
总结: 循环中遇到break,则终止后面所有的循环,直接结束循环.
while中的break作用是永久终止循环
- continue在while语句中的作用
如:
int main()
{
int i = 1;
while(i<=10)
{
if (5==i)
continue; //continue跳过本次循环,不会执行后面的代码,而是回到while的判断部分
printf("%d ",i);//continue跳过本次循环,i++没有执行(i没有调整),进入死循环状态
i++;
}
return 0;
}
//显示结果:1 2 3 4 死(空)循环
总结:continue终止本次循环,即continue后面的代码不会执行,直接跳到while的判断部分,进行下一次循环的入口判断.
1.1getchar()函数
getchar()函数:
①从缓冲区读取一个字符,返回类型为整型(字符型char本质是ASCII值,为整型)
②使用要包含头文件stdio.h
③getchar()函数不仅可以从输入设备获得一个可显示的字符,而且可以获得屏幕上无法显示的字符,如控制字符回车换行,空格等.
注意:1.因为getchar返回类型为整型,所以创建存放字符的变量的类型为整型,如int ch;
2.gechar()读取失败会返回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已被取走,缓冲区清理完毕.
2.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)//当5==i,continue跳出本次循环,接着执行i++
{
continue;
}
printf("%d",i);
}
}//输出结果为1234678910
- for语句的建议:
①不可在for循环体内改变循环变量
int main()
{
int i = 0;
for(i=1;i<=10;i++)
{
if(i = 5)
printf("%d",i);
}
return 0;
} //此时程序运行结果为死循环打印5
②建议初始化部分和条件判断部分采取"前闭后开"写法.
如for( i = 0;i < 10; i++),指明0到9,10个元素.
- for语句的变形:
变形①:省略初始化,条件判断,调整三部分
for (; ; )
{
printf("haha");
return 0;
}
//死循环打印haha
语法上可以省略,但当省略条件判断部分,那判断部分恒为真,进入死循环.
变形②:初始化,条件判断,调整三部分可以是一条语句,也可多条.
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为赋值语句,为假,不执行.
3.do while语句
语法结构:
do
{
循环语句;
}while(表达式)
do…while语句至少执行一次,使用场景有限,少用.
实例:
int main()
{
int i=1;
do{
printf("%d",i);
i++;
}while(i<=10);
return 0;
}//打印1-10
在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);
//方法一:while语法
//ret = 1;
//i = 1;
//while (i <= n)
//{
// ret *= i;
// i++;
//}
//printf("%d", ret);
//方法二:for语法
// for (ret = 1, i = 1; i <= n; i++)
// {
// ret *= i;
// }
// printf("%d", ret);
//方法三:do while语法
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, j, ret = 0;
//int sum = 0;
//scanf("%d", &n);
//for (i = 1; i <= 10; i++)
//{
// ret = 1;
// for (j = 1; j <= i; j++)
// {
// ret *= j;
// }
// sum += ret;
//}
//printf("%d", sum);
//return 0;
//方法一实现了阶乘求和,但每次阶乘都得从1开始乘,效率较低
//因为n!=((n-1)!)*n,即4!=3!*4
//方法二:
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;//stelen计算字符不会把'\0'算进去
//int right = ( sizeof(arr1) / sizeof(arr[0]) )- 1;这是错误写法.arr1最后一个字符是'\0'
//int right = ( sizeof(arr1) / sizeof(arr[0]) )- 2;正确,但不推荐,容易出错
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()函数:
4.goto语句
语法结构:
C语言提供goto和标记跳转的标号,来改变程序流向,转到执行语句标号所标识的语句.
goto语句用途:终止程序在某些深度嵌套的结构的处理过
程,例如一次跳出两层或多层循环.而break只能从某层循环跳到上一层循环.但goto不可跨函数跳转.
使用例子:
int main()
{
again:
printf("hello\n");
goto again; //是代码跳到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;
}
/*
while语句写法:
while (1)
{
printf("关机程序已开始,若输入:我是伞兵,将取消关机,请输入:\n");
scanf("%s", input);
if (0 == strcmp(input, "我是伞兵"))
{
system("shutdown -a");
break;
}
else
{
printf("输入有误,请重新输入");
}
}
*/
return 0;
}
以Release的形式生成的.exe程序可以发给别人,也可以将该程序放进计算机自动启动的程序中。