c语言log_C语言入门——第三周笔记

6e0a266b7a527432ca35c36d137382a2.png
我在哪?红色?黑暗?
终于,我睁开了眼睛。宇智波?难道我到了火影忍者中?那我现在是谁呢?
——《火影之雪殇》

逻辑类型与运算

逻辑类型

bool

  • #include<stdbool.h>
  • 之后就可以使用bool和true、false
#include 

(这个bool不是真正的源生类型,你首先要包含一个源文件,这个源文件叫<stdbool.h>,有了这个头文件后,才能使用bool,ture和false。但是能我们并没有真正的布尔量的类型,实际上他们仍然是整数,所以当我们输入输出的时候,也没有一个特殊的方式去输出那个bool量,我们仍然用%d。)

逻辑运算

  • 逻辑运算是对逻辑量进行的运算,结果只有0或1
  • 逻辑量是关系运算或逻辑运算的结果

5e61b137f9084c404a23b2b4cc939c71.png
  • 如果要表达数学中的区间,如:x∈(4,6)或x∈[4,6],应该如何写C的表达式?

像4<x<6这样的式子,不是C能正确计算的式子,因为4<x的结果是一个逻辑值(0或1),0或1肯定小于6,所以我们得到的永远都是1.

那我们应该怎么写呢?

x∈(4,6)→x>4&&x<6 x∈[4,6]→x>=4&&x<=6

  • 如何判断一个字符c是否是大写字母?

c>='A'&&c<='Z'

理解一下下面的语句

  • age>20&&age<30; 年龄在20到30之间。
  • index<0||index>99; index不在0到99之间。
  • !age<20; 虽然逻辑运算符是低于比较运算符的,可是呢,这个“!”是单目运算符,我们又有另一条通道,单目运算符的优先级大于双目运算符的优先级。所以呢,这个就是“!”和age先结合在一起,如果age是0,!age就会变成1,如果age不是0,那!age就会变成0,再去和20作比较。因为!age的结果不是0就是1,所以!age<20永远是正确的了。

优先级

  • !>&&>||
  • !done&&(count > MAX)

eb51f9f1adfdc7e83a03b85178703bc6.png
if

学过逻辑运算符后,我们可以改为

if

但是面对下面这个代码

if

这个时候你还能不能写成上面的那种形式呢?能吗?

短路

  • 逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果了,就不会做右边的计算
  • a==6&&b==1
  • a==6&&b+=1

如果说a==6已经是不成立的,但对于这个&&来说需要两边都成立,所以,如果a==6不成立,那么b==1就不会去判断,这是一个好事情,可以提高我们运算的速度;但是如果你在右边是有赋值的,是要产生一些结果的,如a==6&&b+=1,那么,右边的计算就不会做了。它不会把两边的运算都做完了再来做&&的运算,它一定是先做左边,发现不用做了,右边就不会做了。所以对于&&,左边是false时就不做右边了;对于||,左边是true时就不做右边了,这件事情叫做短路。

我们来试下这件事情

#include 

我们发现,a>0是false,所以右边的就不会做了,所以最后的结果是-1

1352fe3b2e70ea98ad8a0b38e00dd799.png

所以,我们以后不要把赋值,包括复合赋值组合写进表达式,如果你记住了这条,你就不会写出上面那样的代码来,这样短路对我们来说就没有什么意义,就是不会起作用的事情。

我们还有一种运算符叫条件运算符。

  • count=( count>20)?count-10:count+10;

问号前面是条件,问号后面一直到冒号是条件满足时的值,冒号后面是条件不满足时的值。

想表达的意思也就跟下面代码一样

if 

表面上看,你把if else语句写成上面的条件运算符后看起来很简单,但是呢,在复杂的情况下会给你带来很大的麻烦。

  • 条件运算符的优先级高于赋值运算符,但是低于其他运算符。

我们来理解下下面几个语句。

  1. m<n ? x : a+5 如果m小于n的话,结果就是x,否则的话是a+5
  2. a++ >=1 && b-- > 2 ? a : b 如果a++的结果≥1并且b--的结果大于2的话,结果是a否则是b
  3. x=3 * a >5 ? 5 :20 如果x=3*a>5的话,结果是5,否则为20

这里我们把赋值运算组合在表达式里,更加增加了表达式的复杂性。所以,我们不想要这种表达,它使得别人理解我们的程序变得更困难了。

最后,我们还有一种非常有意思的运算叫做逗号,逗号在C语言里面是一个运算符。

逗号用来连接两个表达式,并以其右边的表达式的值作为它的结果。

我们来看一下它是什么意思。

#include 

我们说过“逗号”的优先级是所有的运算符中最低的,低过“=”,所以,你看当我们编译的时候,它会说这个“5+6”没有用到。

d06cf491df3eeceaf36b227041f305ff.png

为什么会这么理解?是因为3+4被赋给了i,“i=3+4”是一个表达式,赋值(=)的优先级比逗号来的还要高,所以“i=3+4”会先算。算完以后才会去算5+6,但5+6没有交给任何人,所以这个表达式的结果没有用到。所以这个时候,我们一定要看到i的结果,那i是7。

如果现在我在3+4,5+6加一个括号,变为

#include 

这个时候,3+4没有被用到

46ce0f41931106e7ef80eaa1d6706069.png

因为这个时候“3+4,5+6”这是一个表达式,这时候,有优先级,因为括号提升了它的优先级,此时,逗号右边的5+6赋给了i,所以结果为11。

你可能会问,这种逗号表达式有什么用?

主要是在for当中使用。

如: for( i=0,j=10; i<j;i++,j--)......这个表达式里,分号把他们分成了3个区域,每一块区域是一个表达式。如果你想要在表达式进行多个运算时,就可以用“逗号”了。目前来说,逗号表达式就这一个用处。

下面我们来用比较a,b,c 的大小,来感受下if else(嵌套的if else)规范的用法。

c99cd49fba4214758185aa0a1dc01f7c.png

e2b8e6dc934437c7e47839bbcdf1d441.png

当然,if else的写法很多,但是,如果不按规范的写法,不仅给别人造成误读,自己在编写时也会把自己绕晕。所以,一定要规范!!!更何况,现在的编译器,每到一个括号,后面都会补上另一个括号。

综上:在if或else后面总是用{};即使只有一条语句的时候。且else总与最近的if相匹配。

我们下面看一个分段函数,f(x)=-1,当x<0时;f(x)=0,当x=0时;f(x)=2x,当x>0时;

根据这个函数,我们能写出这样的一个代码

if 

这个代码看上去不是包含的关系,不是里面外面,而是一层一层连下来的。

0279f4d6c0c79087f5eab5ddae4e3c51.png
这是它的流程图

这其实是一个级联的if-else if。

结构就是:

if

这里我们习惯把所有的else都对齐,最后会孤立一个“else”。

综上:一个判断且就能对应一个结果,不需要做二次判断,我们就可以选择级联的if-else if。如果有可能做多次判断,才能确定结果,我们用嵌套的if else

我们再来看一下这段代码

switch

switch-case:里的大括号的内容是平级的,或者说他们都在一个大的房子里,里面的case并没有把他们给单独分开,它会按照一定顺序读取,直到遇到break才会跳出大括号。

比如,下面这个代码

switch

如果我们输入“1”呢?

ca9259d926009c221028e10ee4e1041e.png

如果我们输入“3”呢?

b0e2e61b56008bd8c5c764ab14e1f588.png

所以,switch语句可以看作是一种基于计算的跳转,计算控制表达式的值后,程序会跳转到相匹配的case(分支标号)处。分支标号只是说明switch内部位置的路标在执行完分支中的最后一条语句后,如果后面没有break,就会顺序执行到下面的case里去,直到遇到一个break,或者switch结束为止。

switch-case的结构

switch  (控制表达式){
case 常量:
   语句
   ……
case 常量:
   语句
   ……
default:
   语句
   ……
}
  • 控制表达式只能是整数型的结果,也就意味着定义的时候,必须定义为int。
  • 常量可以是常数,也可以是常数计算的表达式

讲了这么多,我们发现编程不就是输入和输出吗?那么编程难在哪?难在想问题,难在怎么把问题变成程序,怎么处理编程中遇到的细微的小的情况。

现在假设我们要算log以2为底x的对数。我们可以写出这样的代码

int 

f809f936e1130760b4c75881abbbd25c.png

运行后我们发现这里是1。其实因为x一直在除2,所以最终x的结果为1,那么,如何让这个x值为我们原先输入的x的值呢?

这里就又有一个小套路了。我们可以这样

int 

340b185a0adde5f9b2f32fe09a3ce256.png

我们再来看一段代码

int count =100;
while (count >=0 ){
   count --;
   printf("%dn",count);
}
printf("发射!n");

我们现在有3个问题

  • 这个循环需要执行多少次?
  • 循环停下来的时候,有没有输出最后的0?
  • 循环结束后,count的值是多少?

小套路:如果要模拟运行一个很大次数的循环,可以模拟较少的循环次数,然后作出推断。

计算平均数

#include 

其实,看了半天的代码,我们一直都在围绕着循环计算,那么现在就先暂时总结下吧,我们最先学了if语句来用于判断,接着,我们又学了if else来进行更充分的选择与输出;接着,为了能够循环进行某个计算,我们学了while循环;但是while循环是先判断后运算,那么,有先运算后判断的循环吗?答案:有。所以,我们紧接着学了do-while循环。在第二周笔记的最后,我们又介绍了for循环,它一般情况下用于计数,且循环的次数为有限次的,并且它还可以和while循环等价。(循环具体内容见第二周笔记)

前方 一片天:C语言入门——第二周笔记​zhuanlan.zhihu.com
ad0db49a514303ccc917f1a661654b91.png

现在我们来做一个猜数的游戏。这个游戏是这样的:让计算机来想一个数,然后让用户来猜,用户每输入一个数,就告诉它是大了还是小了,直到用户猜中为止,最后还要告诉用户它猜了多少次。

  • 因为需要不断重复让用户猜,所以需要用到循环
  • 在实际写出程序之前,我们可以先用文字描述程序的思路
  • 核心重点是循环的条件
  1. 计算机随机想一个数,记在变量number里;
  2. 一个负责计次数的变量count初始化为0;
  3. 让用户输入一个数字a;
  4. count递增(加一);
  5. 判断a和number的大小关系,如果a大,就输出“大”;如果a小就输出“小”;
  6. 如果a和number是不相等的(无论大还是小),程序转回到第3步;
  7. 否则,程序输出“猜中”和次数,然后结束。

这里,我们看到,循环的条件是:a和number不相等。

#include 

程序里的rand,表示能够随机取一个数。rand()%100,可以让这个随机数变小。而且,这里更适合用do-while循环,因为用户猜一个数,肯定先要运行一次算法,接着告诉用户结果。这里while后面的条件一定要是能够进行循环的条件,而不是跳出循环的条件。还有就是告诉大家一个小秘密,对于100数以内的数来猜的话,你正确的猜法,最多只用7次就能猜出来。为什么?以后我们会讲到的。

对一个整数,我们如何分解出它的各个位上的数字,然后加以计算?我们可以用%10得到它的各位,然后依次重复此操作,就能得到更多位的数;如果用/10,我们就能够去掉了它的个位数。

#include 

if语句常见的错误

  • 忘了大括号
  • if后面的分号
  • 错误使用==和=
  • 使人困惑的else

分号,代表一个语句的结束,每个分号之间的语句没有直接的关系。如果在if语句中,你忘了加大括号,那么,if后面的每一条语句都会去执行,此时也就失去了判断的作用。

if

此时的结果是

4c0d3f96891e9832e6f6ff5c2221f189.png

加上大括号后

128f7c93b280ff31c78bb914db8f937c.png

if后面如果加分号的话,就等于if判断的作用就消失,此时不论你输出哪个数,都会执行后面的语句也即大括号里的语句。

if (age >60);
{
   salary = salary*1.2;
   printf("%f",salay);
}

结果

4f4a55c69d0d7eb6cc1df6faec944751.png

其次,if语句在表示等于时一定要用“==”,而“=”我们前面就说过,它代表赋值。

有时,我们在运行代码时,会出现error或者warning,要注意区分它们,有时出现warning不代表写的错,但是运行后所算的结果不一定是我们原先想要的,所以,在我们初学计算机时一定要敬畏warning,要养成一个良好的习惯。

代码风格

c3349736d8636a18b64da650bb36db14.png
这样写,层次更加分明,并且易读!

总之,我们在写if语句时一定要注意下面2点

  1. 在if和else之后必须加上大括号形成语句块;
  2. 大括号内的语句缩进一个tab的位置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值