目录
算法的概念及其描述方法
算法的概念
1.程序设计中的算法仅指计算机算法,即计算机能够执行的算法
(1)数据结构是计算机存储,组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合
(2)算法是对操作或行为(即操作步骤)的描述
①数值算法:主要用于解决数值求解问题
②非数值算法:逻辑推理问题,如人工智能的问题回答
2.算法的正确性
(1)有穷性:在合理时间内完成
(2)确定性:每个步骤都是确定的,不允许有歧义
(3)有效性:每个步骤都能有效执行
(4)允许无输入或多个输入
(5)必须有一个或多个输出
算法的描述方法
1.自然语言描述
2.流程图描述
3.NS结构流程图描述
4.伪码描述
伪码是指介于自然语言和计算机语言之间的一种代码,书写无固定格式和规范,比较灵活
养成先画流程图,再编写代码的好习惯
关系运算符和关系表达式
顺序结构
1.主要由表达式语句组成,表达式语句由表达式后接一个(;)构成
(1)输入数据
(2)对数据进行计算和处理
(3)输出运算结果
分支控制结构
关系运算符
运算符 | 对应的数学运算符 | 含义 | 优先级 |
< | < | 小于 | 高 |
> | > | 大于 | 高 |
<= | ≤ | 小于或等于 | 高 |
>= | ≥ | 大于或等于 | 高 |
== | = | 等于 | 低 |
!= | ≠ | 不等于 | 低 |
注意:
(1)一个关系运算符之间不能插入等号
(2)=和==的含义不一样,并且最好不要用于字符串的比较
关系表达式
用关系运算符将两个操作数连接起来组成的表达式,称为关系表达式
用非0值表示“真”,用0值表示“假”
分支语句
语法结构
单分支
if (表达式)
语句;
双分支
if (表达式)
语句1;
else
语句2;
多分支
if (表达式1)
语句1;
else if (表达式2)
语句2;
else
语句3;
细节讲解
复合语句
int main()
{
int age = 20;
if (age >= 18)
printf("成年\n");
else
printf("未成年\n");
printf("未成年不能谈恋爱\n");
return 0;
}
运行结果:
成年
未成年不能谈恋爱
思考:为什么第三句话依旧会被打印出来?
因为else只能够影响下一句,不能影响第二句,想要else控制多条语句,应该使用{},构成复合语句
int main()
{
int age = 20;
if (age >= 18)
printf("成年\n");
else
{
printf("未成年\n");
printf("未成年不能谈恋爱\n");
}
return 0;
}
if else 的“就近原则”
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或else if配对形成一组 ,可以理解为“就近原则”
逻辑运算符左结合带来的错误
int main()
{
int age = 60;
if (age < 18)
printf("少年\n");
else if (18 <= age <= 26)
printf("青年\n");
return 0;
}
运行结果:
青年
思考:为什么不在范围内仍然输出“青年”?
逻辑运算符,左结合,先18<=60,为真,变为1,之后变成1<=26,同样为真,所以会进行输出,
应当使用逻辑与(&&)
int main()
{
int age = 60;
if (age < 18)
printf("少年\n");
else if (age >= 18 && age <= 26)
printf("青年\n");
return 0;
}
良好的书写习惯
int main()
{
int a = 3;
if (a = 5)//应为a==5,这样就会进行打印,但现在这种情况会进行打印,因为进行的是赋值运算,永远为真
//由于容易漏写=,所以在进行书写时,推荐写为5==m,这样如果漏写系统无法运行
{
printf("1");
}
return 0;
}
条件运算符和条件表达式
条件运算符是C语言中惟一的一个三元运算符
由条件运算符及其相应的操作构成的表达式,称为条件表达式,它的一般形式如下:
表达式1?表达式2:表达式3
其含义是:若表达式1的值非0,则该表达式的值是表达式2的值,否则是表达式3的值
例如:
#include<stdio.h>
int main()
{
int a, b, max;
printf("请输入a,b的值:");
scanf("%d,%d", &a, &b);
max = a > b ? a : b;
printf("max=%d\n", max);
return 0;
}
请输入a,b的值:1,2↙
max=2
注意: 使用条件表达式进行赋值时,变量要在最外面,不可以放在条件表达式里面
用于多分支选择的switch语句
语法结构
switch(整型表达式)
{
语句项(写为case x):
}
整形常量表达式,即使是对n赋值为整型,但因为n是变量,同样不能使用,用字母也可以,因为用字母的话会转换为字母的ASCII码值
注意:
(1)常量与case中间至少一个空格,常量的后面是冒号,常量的类型与switch内括号内表达式的类型一致
(2)每个case后的常量只起到一个语句标号的作用,所以case后常量的值必须互不相同
(3)case语句下可以写if else语句,但if else语句内部不可以写case语句,如下:
if(...)
{
case 1:
...
}
else
{
case 1:
...
}
细节讲解
break的使用
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期1\n");
case 2:
printf("星期2\n");
case 3:
printf("星期3\n");
case 4:
printf("星期4\n");
case 5:
printf("星期5\n");
case 6:
printf("星期6\n");
case 7:
printf("星期7\n");
}
运行结果:
2↙
星期2
星期3
星期4
星期6
星期7
思考 :为什么会多打印这么多?
识别某一项之后,会直接跳转到这一项,但不是只执行这一项,会将这一项后面的所有项一起执行
break用来跳出这个switch,但不会跳出外部或其他switch,只能跳出自己所在的switch
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:
printf("星期1\n");
break;
case 2:
printf("星期2\n");
break;
case 3:
printf("星期3\n");
break;
case 4:
printf("星期4\n");
break;
case 5:
printf("星期5\n");
break;
case 6:
printf("星期6\n");
break;
case 7:
printf("星期7\n");
break;
}
return 0;
}
default的使用
int main()
{
int day;
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;
}
在用户输入的过程中,不免会输入错误,若输入错误,则会导致程序无反应,此时使用的default,其含义为:当用户输入不在设置的选项中时,默认跳转到该选项,default不一定必须放在最后,放到语句项的哪个位置都可以,但输入习惯一般会放在最后
逻辑运算符和逻辑表达式
逻辑运算符
逻辑运算符 | 类型 | 含义 | 优先级 | 结合性 |
! | 单目 | 逻辑非 | 最高 | 从右往左 |
&& | 双目 | 逻辑与 | 较高 | 从左往右 |
|| | 双目 | 逻辑或 | 较低 | 从左往右 |
用逻辑运算符连接操作数组成的表达式称为逻辑表达式
逻辑运算的真假值
A的取值 | B的取值 | !A(求反运算) | A&&B(逻辑与) | A||B(逻辑或) |
非0 | 非0 | 0 | 1 | 1 |
非0 | 0 | 0 | 0 | 1 |
0 | 非0 | 1 | 0 | 1 |
0 | 0 | 1 | 0 | 0 |
逻辑与的运算
仅当两个操作数都为真时,运算结果才为真;只要有一个为假,运算结果就为假
逻辑或的运算
两个操作数中只要有一个为真,运算结果就为真;仅当两个数据操作数都为假,运算结果才为假
逻辑非的运算
若操作数的值为真,则逻辑非运算的结果为假;反之,则为真
常用运算符的优先性和结合性
优先级顺序 | 运算符种类 | 附加说明 | 结合方向 |
1 | 一元运算符 | 逻辑非! 求相反数- ++ -- sizeof类型强转转换等 | 右→左 |
2 | 算术运算符 | * / % 高于 + - | 左→右 |
3 | 关系运算符 | < <= > >= 高于 || | 左→右 |
4 | 逻辑运算符 | 除逻辑非之外,&&高于|| | 左→右 |
5 | 赋值运算符 | = += -= *= /= %= | 右→左 |
注意: 运算符&&和||都具有“短路”特性,也就是说,若含有&&和||的表达式的值可由先计算的左操作数的值单独推导出来,那么将不在计算右操作数的值
例如:a>1&&b++>2;若前面为真,后面的需要被计算;若前面为假,则直接返回假,不再进行后面的计算
对于非法字符的检查和处理
引例:
int main()
{
int a, b, max;
printf("请输入a,b:");
scanf("%d,%d", &a, &b);
max = a > b ? a : b;
printf("max=%d", max);
return 0;
}
运算结果:
①请输入a,b:3.2,1↙
max=3//但不代表读取成功,不同编译器或不同计算机的随机数不同,
//本台计算机随机数为-858993460,导致出现了3
②请输入a,b:1,3.2↙
max=3
③请输入a,b:q↙
max=-858993460
①输入的第一个数据是3.2,scanf语句只读入整数部分到变量a中,后面的圆点被视为非法字符号导致输入结束,因此b中的值仍未随机值,由于这个随机值大于3, 所以最后打印的最大值就是这个值
②输入的第一个数据是1,第二个数据是3.2,读取到3就导致结束,会将3赋值给b
③由于输入非法字符‘q’,所以直接读取结束,输出随机值
改进方法:如果scanf()调用成功(能正常读入输入数据),则返回值为已成功读入的数据项数,通常非法字符的输入会导致数据不能成功读入;使用函数fflush()来清除输入缓冲区中的内容,可能会带来可移植性问题
int main()
{
int a, b, max,ret;
printf("请输入a,b:");
ret=scanf("%d,%d", &a, &b); //记录scanf()的返回值
if (ret != 2) //根据返回值,判断输入数据个数或者格式是否错误
{
printf("输入错误!\n");
fflush(stdin); //清除缓冲区种的错误数据
}
else //可以正确读入数据后的操作
{
max = a > b ? a : b;
printf("max=%d", max);
}
return 0;
}
请输入a,b:1.2
输入错误!请输入a,b:1 3
输入错误!请输入a,b:3.2,1
输入错误!请输入a,b:q
输入错误!请输入a,b:1,3.2
max=3请输入a,b:1,2,q
max=2//由于在读取停止前已经读取了两个数据,所以不会报错