《C和指针》读书笔记(第五章 操作符和表达式)

操作符表达式是C语言基础中非常重要的一环,而且C语言的操作符和表达式相较于其他语言会更加丰富,所以这部分的学习尤为重要,这章的内容属于重要但难度不大的类型。按照惯例,先来一个本章内容的思维导图。

1 内容概览

在这里插入图片描述
从思维导图中可以看到,本章的内容虽然不多,但是非常琐碎,所以需要一点一点学习。

2.1 操作符

2.1.1 算术操作符

算术操作符是最长用的操作符,即:+ - * / %,其中的除法运算比较特殊,因为牵扯到能否整除的问题,所以有了额外的运算符:取余,即%,来看这样的一个例子。

#include <stdio.h> 
// 函数指针与回调函数

int main()
{
    
    
	int a1 = 10;
	double a2 = 10;
	int b = 3;
	printf("%d\n", a1 / b);
	printf("%f\n", a2 / b);
	printf("%d\n", a1 % b);
	system("pause");
	return 0;
}

打印输出如下:
在这里插入图片描述
可以看到除法运算中,当被除数和除数都是整数时,执行整除运算,其他时候会执行浮点数除法,而求余运算也是在被除数和除数都是整数时取得的余数。

2.1.2 移位操作符

移位操作符一般情况下分为左移位操作符<<和右移位操作符>>,来看下面的例子。

#include <stdio.h> 
// 函数指针与回调函数
int main()
{
    
    
	short a1 = 5;
	short a2 = -5;
	printf("%d\n", a1 << 2);
	printf("%d\n", a2 << 2);
	//printf("%d\n", a1 % b);
	system("pause");
	return 0;
}

打印输出如下:
在这里插入图片描述
书上的表达比较严谨。无符号值执行的是逻辑移位,而有符号值是逻辑移位还是算术移位与具体的编译器有关。其实在刚才的结果中也可以看到,在VS2015编译器中执行的是算术移位,所谓的算术移位是指在移位的过程中,符号位(最高位)始终保持不变,其他位会有变化,逻辑移位就很简单了,直接进行移位操作,不够的地方补零即可。负数的移位操作稍微繁琐些,具体的可以参考这篇文章。
C 语言中负数移位运算讲解

2.1.3 位操作符

位操作符在很多偏向于底层的开发任务中尤为重要,因为意味着我们可以对某数的某个二进制位进行操作。在C语言中常见的位操作符有三个,它们分别是:& | ^分别对应着位与运算,或运算,异或运算,其实异或运算也很好理解,就是所谓的相同出0,不同出1。来看个例子。

#include <stdio.h> 
// 函数指针与回调函数
int main()
{
    
    
	short a1 = 0x03;
	printf("%d\n", a1&0x02);
	printf("%d\n", a1|0x04);
	printf("%d\n", a1 ^ 0x0c);
	system("pause");
	return 0;
}

打印输出如下:
在这里插入图片描述
a1用二进制形式表示为(假设占8位内存):a1 = 0000 0011,所以与0x02(0000 0011)的与运算结果为2,或者也可以理解为最后一位的1与0进行与运算之后变为了0,而其与0x04(0000 0100)执行或运算的时候,有1出1,所以后三位全变为1,也就得到了最终的结果7,最后一个是a1与0x0C(0000 1100)进行异或运算,相同出0,不同出1,由于其低四位全都不同,因而得到了最终结果15(0000 1111)
当然书上还有这样的例子,读者可自行分析。

#include <stdio.h> 
// 函数指针与回调函数
int main()
{
    
    
	unsigned short a1 = 0x03;
	int bit_number = 1;
	//将指定的位设置为1
	a1 |= 1 << bit_number;
	printf("%d\n", a1);
	//将指定的位设置为0
	a1 &=  ~(1 << bit_number);
	printf("%d\n", a1);
	system("pause");
	return 0;
}

其实不难的。

2.1.4 赋值

赋值操作符非常简单,就是数学上的等号:=,同样,也可以采用下面的方法对变量进行赋值。

#include <stdio.h> 
// 函数指针与回调函数
int main()
{
    
    
	short a1 ,b1, c1;
	a1 = b1 = c1 = 10;
	printf("a1的值为:%d\n", a1);
	printf("b1的值为:%d\n", b1);
	printf("c1的值为:%d\n", c1);
	system("pause");
	return 0;
}

最终得到的结果都为10。当然这种“连续赋值”的形式在变量定义的时候进行赋值是不被允许的。
比方这种形式:

#include <stdio.h> 
// 函数指针与回调函数
int main()
{
    
    
	short a1 = b1 = c1 = 10;
	printf("a1的值为:%d\n", a1);
	printf("b1的值为:%d\n", b1);
	printf("c1的值为:%d\n", c1);
	system("pause");
	return 0;
}

原因很简单,因为赋值运算符的结合顺序是自右向左的,而首先对变量c1进行赋值的时候,该变量尚未定义,所以会报错。
当然还有复合赋值符,这种运算符非常常见,因为在运算比较复杂的时候可以大大简化代码量,且不易出错。
比方说a = a + 10;可以用a+=10;进行表达,其他类似的运算也是如此。

2.1.5 单目操作符

单目操作符意思是只接受一个操作数,C语言中有不少这样的操作符,包括:逻辑非!,变量按位取反~,变量自加++,变量自减--,变量前添加负号-,正号+,取地址运算符&,间接访问操作符*,求变量字节数操作符sizeof()。这些操作符都比较好理解,也很常用,就不一一介绍了,其中最容易混淆的是i++++i这两种运算,也是考试中最常考的内容之一。下面着重介绍。
其中前者是先对表达式取值为i,然后再对i自身加1,而后者是先对自身加一,然后再对表达式取值。
也就是说,对于i自身的值来说,两种运算对变量自身的值并无影响,只是表达式的值不一样而已。一起来看下面的例子。

#include <stdio.h> 
// 函数指针与回调函数
int main()
{
    
    
	int i = 10;
	printf("i的值为:%d\n", i);
	printf("i++的值为:%d\n", i++);
	i = 10;
	printf("++i的值为:%d\n", ++i);
	system("pause");
	return 0;
}

打印输出如下:
在这里插入图片描述

2.1.6 关系操作符

常见的关系操作符有6种,分别是:“>,>=,<,<=,==,!=”,含义很简单,其中的大于小于和数学上的没什么区别,只是数学上的等号在C语言中是双等号,数学上的≠在C语言中是!=。一般关系运算符的优先级比较低,这也符合我们正常的编程逻辑。也就是算术操作符优先级高于关系操作符

2.1.7 逻辑操作符

逻辑操作符包含两个,分别是&&||,即条件与条件或,这个也很好理解,条件与是两者都满足才是真,其他时候均为假,而条件或是只有一个为真即可,结果为真。

2.1.8 条件操作符

条件操作符接受三个操作数。它们也会控制表达式的求值顺序。有的教材中条件操作符成为三目运算符,毕竟本来C语言中得三目运算符并不算多。条件操作符可以说是条件语句在特殊形式下的简化形式。而且非常常用。比方说下面这个问题(来自力扣):

  1. 各位相加 给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。

某解法如下:

int addDigits(int num){
    
    
    int sum = 0;
    while(num > 0)
    {
    
    
        sum += num % 10;
        num /= 10;
    }
    return sum < 10 ? sum : addDigits(sum);
}

每次都将该数各个位上的值进行相加,如果小于10则直接返回,否则执行递归。

2.1.9 逗号操作符

逗号表达式并不是非常常见,这些表达式自左向右逐个进行求值,整个逗号表达式的值就是最后那个表达式的值。其形式为:
表达式1,表达式2,表达式3,……,表达式N

2.1.10 下标引用、函数调用和结构成员

这些内容将在后续的章节讨论,下标引用与数组和指针有关,函数调用和函数有关,结构成员和结构体有关。

2.2 布尔值

在标准C中并没有bool数据类型,一般是这样用的,在C语言中,所有非零数值皆为真,零为假

2.3 左值和右值

左值和右值很好理解,左值是想赋值的部分,而右值是读取数值的部分,比方说:

a = b + 15;

则a为左值,b + 15为右值。不可以调换位置。

2.4 表达式求值

在表达式求值中有一些值得注意的问题,比方说,隐式类型转换操作符的优先级,等等问题,这是在实践中经常会遇到的问题。

隐式类型转换很好理解,因为在运算中有时候数据类型不统一,或者左值和右值的数据类型不统一都会出现这个问题。但一般为了保证程序的正常运行和结果不出错,隐式类型转换总会将数值转换为我们期望的类型。

操作符的优先级只需要熟悉就行,一般来说,算术操作符>关系操作符>逻辑操作符,用多了自然就可以记住。

3 总结

本章的内容很基础,也比较简单,只需要多加实践即可!

----------------------------------------------------END----------------------------------------------------

猜你喜欢

转载自blog.csdn.net/weixin_43719763/article/details/127536047
今日推荐