条件判断
0表示假,非0表示真。条件成立为1,条件不成立为0。
布尔类型,false表示假,true表示真。
选择语句
if
根据条件判断是否选择执行,选择语句中,如果执行了一条分支后,别的分支不再进去。if语句默认后面只跟一条语句,如果需要跟多条语句,需要加 {} 。
选择语句的三种情况
单分支
if (条件判断)
{
执行语句;
}
int a = 20;
int b = 10;
if (a > b)
{
printf("a 大于 b");
}
对立分支
if (条件判断)
{
执行语句1;
}
else
{
执行语句2;
}
int a = 20;
int b = 10;
if (a > b)
{
printf("a 大于 b");
}
else
{
printf("a 小于等于 b");
}
多分支
if (条件判断)
{
执行语句1;
}
else if (条件判断) //可以写多个
{
执行语句2;
}
else //根据情况是否需要,并不是一定有else
{
}
int a = 20;
int b = 10;
if (a > b)
{
printf("a 大于 b");
}
else if (a < b)
{
printf("a 小于 b");
}
else
{
printf("a 等于 b");
}
分支语句可以嵌套使用
if (条件判断)
{
执行语句1;
if (条件判断)
{
执行语句;
}
执行语句2;
}
易错点
请问这个输出的结果是什么?
int a = 20;
int b = 10;
if (a < b)
if(b)
printf("%d\n", b);
else
printf("%d\n", a);
答案是没有输出,因为else是和第二个if匹配的,第一个if的条件不满足,不进入。if和else没有明确使用 {} ,可能会出现理解错误 ,else是和最近的if匹配的,并不是和对齐的匹配的。养成良好的代码风格(可以阅读一下电子版的《高质量 C++/C 编程》),写选择语句的时候最好加上 {} 。(注:if没加 {} 的时候只能跟一条语句,这里的if else 是一条语句,因为只会执行其中一条。)
请问这两个代码的test函数有没有区别
int test()
{
int a = 10;
if (a > 0)
{
return a;
}
return 0;
}
int main()
{
int n = test();
return 0;
}
int test()
{
int a = 10;
if (a > 0)
{
return a;
}
else
{
return 0;
}
}
int main()
{
int n = test();
return 0;
}
答案是没有区别,虽然第一个代码的return 0 没有带else,但是这两个return本质上就只会执行一个,条件满足,函数返回a就结束,代码不会执行到第二个return的地方。
请问代码输出的结果是什么。(因为板书问题,有时候不会加上 {} )
int a = 100;
if(a = 10)
printf("%d", a);
return 0;
答案是输出 10 。条件判断是一个赋值表达式,将10赋值给a,已经改变了a的值,非0为真,执行代码。如果判断两个数是否相等,并且有一个是常量的时候,可以把常量写在左边,常量具有常属性,不能修改值,编译错误,很容易发现问题。
int a = 100;
if(10 == a)
printf("%d", a);
return 0;
switch
常使用于多分支语句。
switch(整型表达式)
{
case 整型常量表达式:
执行语句;
break; //break都是根据情况是否需要加
default:
//处理不存在的情况。
break;
}
整型表达式可以有变量,整型常量表达式不能不变量,都不能出现浮点数。
case和default没有顺序要求,在哪都行,一般default会在最坏。
break的作用是执行完对应的case语句后,退出swtich选择语句。如果没有break,代码会从上往下执行,default的语句也会执行,直到遇到break,或者swtich结束。
#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;
default:
printf("输入错误\n");
break;
}
return 0;
}
break按需写。
#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:
printf("输入错误\n");
break;
}
return 0;
}
switch可以嵌套使用
switch (整型表达式)
{
case 整型常量表达式:
switch (整型表达式)
{
case 整型常量表达式:
执行语句;
}
......
}
循环语句
while
条件成立进入循环,执行循环语句,条件不成立,不进入循环。
while (条件判断) {循环语句;}
#include <stdio.h>
int main()
{
int n = 0;
while (n < 5)
{
printf("%d ", n);
n++;
}
return 0;
}
break的作用是直接退出循环。
#include <stdio.h>
int main()
{
int n = 0;
while (n < 5)
{
if (3 == n)
break;
printf("%d ", n);
n++;
}
return 0;
}
程序输出0 1 2,if条件成立,执行break,结束循环。
continue的作用是跳过本次循环后面的循环语句。
#include <stdio.h>
int main()
{
int n = 0;
while (n < 5)
{
if (3 == n)
continue;
printf("%d ", n);
n++;
}
return 0;
}
程序输出0 1 2之后进入死循环,当n的值为3的时候,if条件成立,continue跳过本次循环后面的循环语句,程序无法来到改变n的位置,n一直是3,程序死循环。
如果n++在continue之前出现
#include <stdio.h>
int main()
{
int n = 0;
while (n < 5)
{
n++;
if (3 == n)
continue;
printf("%d ", n);
}
return 0;
}
程序输出结果是1 2 4 5。
在牛客网刷题可能会遇到多组输入的情况。
int n = 0;
while (scanf("%d", &n) != EOF) { }
#include <stdio.h>
int main()
{
int n = 0;
while (scanf("%d", &n) != EOF)
{
printf("%d\n", n);
}
return 0;
}
scanf库函数的返回类型是int类型的,当scanf读取数据成功的时候,会返回读取的个数,如果读取数据失败,会返回EOF(end of file)——文件结束标志,本质是-1。按住键盘的 ctrl 加 z ,然后回车就会让scanf读取数据失败,scanf返回EOF。(注:在VS2019要ctrl 加 z 回车连续三次才会结束。)
getchar的功能是读取一个字符,读取成功就返回读取的字符,读取数据失败也会返回EOF,结束也是ctrl 加 z 然后回车。getchar的返回类型是int类型的,因为EOF(-1)是整型,所以需要int类型作为返回类型。
#include <stdio.h>
int main()
{
char password[15];
scanf("%s", password);
printf("%s\n", password);
printf("请输入 Y/N 确认密码\n");
int n = getchar();
if ('Y' == n)
printf("确认成功\n");
else if ('N' == n)
printf("确认失败\n");
else
printf("输入错误\n");
return 0;
}
这个程序在你输入密码之后,会直接确认失败,键盘输入的数据会先到缓冲区中,输入的回车也是一个字符 '\n' ,它也进入到了缓冲区,再从缓冲区提取数据到password数组中,但是不会提取字符 '\n',getchar提取字符,发现缓冲区还有数据就直接提取了,以至于我们还没有输入Y或者N就结束了。
#include <stdio.h>
int main()
{
char password[15];
scanf("%s", password);
printf("%s\n", password);
printf("请输入 Y/N 确认密码\n");
//清理缓冲区
while (getchar() != '\n')
{
;//空语句
}
int n;
n = getchar();
if ('Y' == n)
printf("确认成功\n");
else if ('N' == n)
printf("确认失败\n");
else
printf("输入错误\n");
return 0;
}
不单单用一个getchar清理 '\n' ,是因为scanf的%s的输入格式,不能提取空格和回车,如果输入为abcd空格1234回车,那么password数组只会提取abcd,而空格1234回车\n会留在缓冲区中,一个getchar不能解决问题。
for
for(单次表达式; 条件判断; 末尾循环体) {循环语句;}
for循环与while循环相比,for循环更加方便控制,for 循环将循环变量的初始化、条件判断和循环变量调整都放在了一行。
#include <stdio.h>
int main()
{
// for循环里面定义的i,出了循环销毁
for (int i = 0; i < 5; i++)
{
printf("%d ", i);
}
return 0;
}
break退出for循环的效果跟while循环一样。
#include <stdio.h>
int main()
{
for (int i = 0; i < 5; i++)
{
if (3 == i)
break;
printf("%d ", i);
}
return 0;
}
程序输出0 1 2,然后退出循环结束。
continue跳过本次循环后面的循环语句,但是不跳过循环变量调整部分
#include <stdio.h>
int main()
{
for (int i = 0; i < 5; i++)
{
if (3 == i)
continue;
printf("%d ", i);
}
return 0;
}
程序输出0 1 2 4,循环结束。
建议不要在for循环内部改变循环变量,防止循环变量无法控制。
for循环的判断条件省略了,判断条件恒为真。
易错
1.
for (; ;)
{
printf("%d ", 1);
}
程序死循环,一直打印。
2.
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
for (; i < 5; i++)
{
for (; j < 5; j++)
{
printf("%d ", j);
}
}
return 0;
}
程序输出0 1 2 3 4,都是在i为0进入第二个for循环输出的,第二次没有进入第二个for循环,是因为j第一个for出了之后,j已经是5了,条件不成立。
do while循环
do {循环语句;} while (条件判断);
先进入循环体执行循环语句,再判断条件是否进入循环。
#include <stdio.h>
int main()
{
int n = 0;
do
{
printf("%d ", n);
n++;
} while (n < 5);
return 0;
}
break退出循环
#include <stdio.h>
int main()
{
int n = 0;
do
{
if (3 == n)
break;
printf("%d ", n);
n++;
} while (n < 5);
return 0;
}
程序输出0 1 2,if条件成立,执行break,退出循环结束。
continue跳过本次循环后面的循环语句。
#include <stdio.h>
int main()
{
int n = 0;
do
{
if (3 == n)
continue;
printf("%d ", n);
n++;
} while (n < 5);
return 0;
}
程序输出0 1 2之后进入死循环,当n的值为3的时候,if条件成立,continue跳过本次循环后面的循环语句,n无法改变,一直是3,导致程序死循环。
练习
1.输入一个数(非负数),计算N的阶乘。
2.输入一个数(非负数),计算1! + 2! + ... + N!
3.打印100-200的素数。
4.一个整型数组中,有序数组1,2,3,4,5,输入一个数,使用二分算法查找下标,找到了打印下标,找不到打印找不到。
练习答案
1.
#include <stdio.h>
int main()
{
int n = 0;
int sum = 1;
printf("请输入一个数(非负数)\n");
scanf("%d", &n);
for (int i = 1; i <= n; i++)
sum *= i;
printf("%d的阶乘是%d\n", n, sum);
return 0;
}
整型最大值是0x7FFFFFFF,阶乘大于这个数存储在整型是错误的数据。
2.
#include <stdio.h>
int main()
{
int n = 0;
int factorial = 1;
int sum = 0;
printf("请输入一个数(非负数)\n");
scanf("%d", &n);
//sum先计算i的阶乘,然后add再把每个阶乘加起来
for (int i = 1; i <= n; i++)
{
factorial *= i;
sum += factorial;
}
printf("1的阶乘到%d的阶乘的和是%d\n", n, sum);
return 0;
}
3.
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
// 100-200的范围找素数
for (i = 100; i <= 200; i++)
{
// 从2开始尝试求余,每次加1
for (j = 2; j < i; j++)
{
// 如果求余等于0,证明不是素数
if (i % j == 0)
{
// 结束循环
break;
}
}
// 如果for循环没有break结束循环,最后会i等于j
if (i == j)
printf("%d ", i);
}
return 0;
}
优化:
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
// 100-200的范围找素数
// i从奇数开始,每次加2
for (i = 101; i <= 200; i += 2)
{
// 从2开始尝试求余,每次加1
// sqrt是求正平方根,因为找因数最大走到根号i
for (j = 2; j <= (int)sqrt(i); j++)
{
// 定义一个变量,求余为0改变该变量
int flag = 1
// 如果求余等于0,证明不是素数
if (i % j == 0)
{
flag = 0;
break;
}
}
// 求余没有一次为0,是素数
if (flag == 1)
printf("%d ", i);
}
return 0;
}
4.
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5 };
//sizeof(数组名)计算的整个数组的大小,除以元素的大小,得到元素的个数
int sz = sizeof(arr) / sizeof(int);
int l = 0;
int r = sz - 1;
int n = 0;
scanf("%d", &n);
while (l <= r)
{
//有序查找使用二分算法
//查找中间值最好不要两个相加再除2,如果l和r比较大,相加大于整型的最大值,导致数据错误
int mid = l + (r - l) / 2;
//中间的值比查找数大,查找数在mid的左边,需要把r的范围重新限制
if (arr[mid] > n)
r = mid - 1;
//中间的值比查找数小,查找数在mid的右边,需要把l的范围重新限制
else if (arr[mid] < n)
l = mid + 1;
//中间的值和查找值相同
else
{
printf("找到了,下标是%d\n", mid);
break;
}
}
//如果没有查到,l大于r
if (l > r)
printf("找不到\n");
return 0;
}