逻辑运算符&&和||的有趣理解

 最近在看到Sponge老兄的博客中看到一篇文章( 链接地址),觉的写的不错,拿来仔细研究一下,发现了自己还是基础不牢,特地写下来以警醒自己。

关于&&和||,我们都不陌生,&&是逻辑与, ||是逻辑或。他们有这些运算性质:

 

A

B

A && B

A || B

0

0

0

0

0

1

0

1

1

0

0

11

1

1

1

1

特别是,这两个运算符千万要和”&”以及“|”,这两个位运算符区别开来,(提示:另外,需要注意的是,尽管&&和||是短路操作符,但是“按位与/或”(&和|)却不是短路操作!)

这里,暂时只说&&和||。 

除了这些基本的性质之外,额外需要注意的是,在C语言中,这两个运算符有如下的性质:

·  && 的 优先级高于 ||。

让我们看如下代码:

#inlcude <stdio.h>
int main(){
        int a, b;
        a = 1 || 1 && 0;
        b = (1 || 1) && 0;
        printf("%d\n",a);
        printf("%d\n", b);
}


这段代码的输出是什么呢?大家可以自己验证下,答案是a=1; b=0。

这两个运算符都是短路(short circuit)操作符。什么 是短路操作符呢?我们注意到,对于&&操作符来说,如果它的左操作数为false,则整个表达式一定为false,我们不需要再计算其右 表达式,而C语言中确实也是这么做的。对于||情况也是一样的,如果其左操作数为true,则整个表达式一定为true,而不用计算其右表达式。这两个操 作符只有在当左操作数不能决定整个表达式的值的时候才会计算右操作数。

如下面代码: 

#include <stdio.h>
int func(); //计算一些事情并返回一个值
int main(){
        0 && func(); //func()不会被计算
        1 || func(); //func()不会被计算
        1 && func(); //func()会被计算
        0 || func(); //func()会被计算
}


下面是我们研究的重点,文中提到一个面试题目如下:

函数声明如下:

int func(int i, int N);


其中,i<=N, 功能输出i递增到N再递减到i的整数,每行输出一个数。比如func(1, 5)的输出是:

1
2
3
4
5
4
3
2
1

要求:

      1. 函数中只能有一个语句,即1个分号。

      2. 不能使用do while until goto for if关键字,不能使用?:和逗号操作符。

      3. 唯一能使用的库函数为printf。

题目要求不能使用for等关键字,而且只有一个语句,那我们怎么才能实现一个循环递减和递增的数字序列呢?我们可以想到使用(递归),那么条件判断呢?这时,就可以利用&&和||的第二个性质来达到目的:

文中也给出了一个答案,如下:

#include <stdio.h>
int func(int i, int N){
        return
        (i == N) && printf("%d\n",i) || printf("%d\n", i ) && func(i+1, N) && printf("%d\n", i);
}


 

如果到这里,你发现好像掌握&&和||的东西了,我说很可能还不够,这个答案还是要再研究下,吃透才能掌握这些要点。

我们把这个程序写个函数测试如下:

#include <stdio.h>
int func(int i, int N)
{
        return (i == N) && printf("%d\n",i) || printf("%d\n", i ) && func(i+1, N) && printf("%d\n", i);

}

int main()
{
    func(1,5);
    return 0;
}


 

确实打印的是:

1
2
3
4
5
4
3
2
1


 

但是,这些个数字到底是哪个printf函数打印出来的呢?这样,你可以给这些printf函数改造下,如下:

return (i == N) && printf("[%d]\n",i) || printf("(%d)\n", i ) && func(i+1, N) && printf("{%d}\n", i);

这样,你重新运行下你的函数,发现打印如下:

(1)
(2)
(3)
(4)
[5]
{4}
{3}
{2}
{1}


 

再次分析该return语句,根据&&优先级大于||的规则,可以这样简化:

A&&B||C&&D&&E

首先根据优先级,分解为如下两块:(A&&B)||(C&&D&&E)

先算(A&&B),如果A为零,B就不会再计算(根据短路原则,(C&&D&&E)块类同)。

这样,当i小于N是,第一个printf(即B)就不会执行,然后就会执行第二块((C&&D&&E)),

在第二块中,首先执行C,便开始了打印数字1,然后判断D,因为这个是个递归,所以又要执行以下第二次func函数了,然后再次执行C,打印2,3,4,当i等于N的时候,就执行了B,然后再一次调用回来就行了。如下图演示了执行顺序:

附:printf函数的返回值。

scanf()和printf()的返回值是这样定义的:
正常情况下:返回成功输入输出的变量个数
异常情况下:返回0
只需要把scanf赋值给一个变量就行了,例如:

a=scanf("%d",&b);

例如下程序:

#include <stdio.h> 
int main() 
{     
     int i=43; 
     printf("%d",printf("%d",printf("%d",i)));
      return 0; 
}

 

打印结果是:4321.

 

【总结】:涉及到的知识点:

1.       &&|| 语法及性质。

2.       printf函数返回值。

3.       递归




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值