当前课程知识点:C/C++:从基础语法到优化策略 > Final Exam > Final exam > 2.4 C++ Arithmetic Operators
返回《C/C++:从基础语法到优化策略》慕课在线视频课程列表
大家好
我们这一部分讲一下C++里面的算数运算符
算数运算符呢 有这么几个
就说有五个基本的算数运算符
我们这讲的只是算数的运算符
不包含逻辑的 也不包含一些位运算
那么这五个基本的算数运算符呢 其实比较简单
就加减乘除外加一个求余
算数运算符呢 一个操作符操作两个数
就是说operand就是操作数有两个
这个操作符和操作数呢 它们共同构成一个表达式
这个表达式expression
它们其实也不仅是一个运算符和两个操作数
它实际上可能几个组合在一起 变成一个很长的表达式
那么这个有什么好讲的呢
在这里面也是有一些注意事项大家要特别注意的
首先就说这里面我们的运算优先级 大家相信都比较熟悉了
就说乘法要比加法的优先级高
如果我们用括号的话 那就会改变优先级
它的计算方式是从左到右的 一般来说
那么我们在这看一个简单的例子啊
这个例子它的赋值的类型是float
那么这个float类型的logs 它等于17除以5乘以5
那么log的值是多少
如果我们看右边的表达式
按照常理来讲 17除以5再乘以5那相当于没有除也没有乘嘛
那也就是按说应该是17 对吧
但实际上这个表达式它的值是15 为什么呢
首先 我们从左往右去计算
17除以5等于几呢
17除以5因为17是个整数 5也是个整数
那么17除以5那就会把小数部分丢掉 也就是3
17除以5等于3 3再乘以5那就是15啊
这个是需要特别注意的地方
有的时候就是在计算里面呢
如果你都是整数 那么它的小数部分就会被舍弃掉
再进行运算
另外 就说在操作的时候
那么它是怎么操作
那么如果两个数啊 这两个数都是integer 就都是整数
那么它就进行整数的除法
如果有小数部分 那么就会丢掉
像刚才我们那个例子里讲的17除以5等于3
所以说最终的结果是一个整数
那么如果这两个操作数呢 其中的一个或者两个都是浮点数
至少有一个是浮点数 那么这个时候
这个结果的小数部分就会保留下来
那么结果就是一个浮点数
所以呢
嗯 这里面主要的这个就这几种类型
就真正的去参与计算的就是int long float和double
有的同学会问怎么没有short 怎么没有char
为什么呢
如果你的整数的类型是short吧
那么short就会被提升到或者隐式地转到int去参与计算
嗯 为什么要这样做
因为计算机里面 你虽然short省了存储 只占16位
但是计算机的指令 那就做整数运算的指令
指令级那是32位的 你只用16位也是浪费
所以说呢 为了简洁 它都是转成32位进行计算
所以说整数运算至少是32位的
那么 还有就是求余呢
求余就是除完之后求余数 这个好理解
这个地方有一个例子 我可以再演示一下
就这个 这个例子里面我们来看
首先定义了一个常量 const int
pounds per stone就是说
它来转换英制里面的英镑和担之间的变化
它就说14磅是一担 stone
那么这里面呢 我们来看 那它让我们先输入一个数值
然后呢 赋给pounds 就是有多少磅
然后呢 我们除以这个14
那么除以14 这时候因为它都是整数运算
所以说它的小数就会舍掉 那么就是说它有多少担
然后这个英镑呢 再对14取余
那么余数 那就剩的尾数嘛
所以说我们就可以说这么多磅 是这么多担
又剩这么多余数 这是大致的
我们可以运行一下这个程序
编译 运行
它让我们输入多少磅呢
14 那我们就输个30
它说 这是两担 还剩两磅
这是求余 求余相对好理解
好
那么我们再介绍一下就是类型转换
就说类型转换在很多时候会发生
如果我们给一个变量赋值的时候
那么很多时候 比如说我们在写代码的时候
常定义把1或者0赋给一个浮点数
那么它就是整数到浮点数的转换
在表达式里面 那么有时候呢
就是表运算符两侧的符号类型不一样的时候
那么这种混合的类型 那也会引起类型转换
类型转换有什么问题要注意呢
第一个就是说如果你在赋值的时候 你要特别小心
如果你从double赋给float 或者从float赋给integer赋给整数
或者从long赋给short
也就说它的范围变小之后 或者精度变小
那么你这个时候要特别注意啊 这时候可能出错
大多数编译器当你这样做的时候
它会给你警告 说你这样可能引起问题
如果你是隐式的 就说你直接那样去赋 它就会警告你
所以说呢 你就需要采用显示的方式去赋值
这里面的问题大家就要注意了
就是再强调一下赋值的时候
从大的范围的值向小的范围赋 你要考虑一下会不会
小的范围的这个变量hold不住这个大的范围
有没有这种可能性发生
如果有这种可能性 你要去想解决方案
而不是等到程序最后出了bug再去找bug 那就很难了
那么还有就是说 在初始化的时候或者赋值的时候
那么C++呢 它是采用截断的方式
也就是说如果你去把浮点数赋给整数
转换的时候 那它是直接把小数给截断
而不是采用四舍五入法去赋值 所以这个要很小心
还有呢对于赋值来讲 我们这列了一些例子
第一个例子啊 这个例子第一行就是说我们定义这个常数变量
const int code = 66
那么我们进行赋值的时候 我们可以把66
直接这样去初始化这个变量x
我们也可以这样去赋值
首先说这种花括号前面没有等号 这种写法是对的
但是当只有什么时候是对的呢
只有你的采用的C++的标准是C++11及以后的标准
它是对的
如果C++03或者其他的标准 它是错的 没有这个规范
这是一个新标准
首先这个语法看上去对的 但这个值不对
因为 你这个值太大了
char只有从负128到正127
那么它是hold不住这个值 所以说这样是不行的
你可以编译一下这个东西 看它会不会出错
如果你这个地方这样是可以的 再加个等号
当然不加等号也是可以的
这地方code是可以的
但是要注意可以的前提是这加一个const
如果没有const也是有问题的
为什么呢 因为如果它是const就表示它是个常量
那没问题就赋值嘛 初始化赋一个常量
如果初始化赋一个变量 那可能会有问题
这个地方就是刚才我说的这个例子 x是个变量
那这个地方是不行的
所以呢 这个地方但是这样是可以的
x是个很大的整数 我去这样赋
直接用等号赋值是可以的 用这种方式去初始化赋值是不行的
这个东西有点复杂 为什么行 为什么不行
它就是这样规定的
我们很多时候也没办法 这也是C++的一个特点
我们可以看到在赋值这件事情上
C++有很多种赋值方式 让我们脑袋有点大
的确是这样 因为C++的一个特点就是做一件事情有很多种做法
有的时候会把你搞晕掉
所以说呢为了不晕掉 我的建议也许是
不要去用这么多的复杂的方法
你还要这样用还要那样用 最后呢导致的问题是
你是用了高级特性 但是你的代码的可读性可能会变差
因为我们写代码的时候 读代码的人
即使你写的很高级 但是呢读代码的人不一定有很高的能力
所以说让你的代码有很高的可读性以及不容易被误解
这是很重要的
所以说呢 我个人不是建议去把C++的那些高级技巧
故意去用起来来显示你的水平很高
这样做是非常糟糕的
我们写代码应该写简单易懂不容易被误解的代码
好 那么下一点要讲的就说在表达式中的这个自动类型转换
他这有列了七条规则
我可以简单介绍一下前几条 后面大家慢慢看
第一条就是说如果两个数
其中的一个或者两个是long double
那么剩下的就会被强制转成long double
也就说如果有个long double 那另外一个必须是long double
如果不是 就转它
如果不是第一种情况的前提下
首先排除掉的第一种情况 然后呢
两个操作数中的一个是double 如果两个是double就不用讲了
如果其中一个是double 那么另外的一个也会被转成double
同样的 如果前两种情况都不成立
那么其中的一个操作数是float 那么另外一个操作数也会转成float
那么也就是说 从前三条就可以看出
长度是从低往高转往长转
同样的 如果不是前面的情况
如果有一个是integer types
那么integral promotions are made它的意思就是说
如果操作符两边的值是整数类型
那么就进行integral promotion
就是说你如果是short就转成int
让int去做 就全部用int做
但是如果有一个是long就去做long 按照高的去做
这后面的例子后面的规律大致相同
基本上就是说两个操作之间就高不就低 大致是这样
嗯 好
那么我们来看
转换格式的时候 我们有一个叫promote
就说当我们传参的时候也是一样的
如果你传的是一个char类型的整数 那么它会转成int去传
它不会给你传一个字节 它一传就是传四个
所以这些要特别的注意啊
当然这个其实很多时候传过去之后又是char了
所以说可能一般来说不太容易犯错 这个地方还好
但是也不一定 过会还给大家看一个例子
首先 类型转换前面讲的是这种promotion
就讲的是隐式的
那么还有一种显式的 就是Force type conversions
那么怎么去强制转 你可以这样写
这是老式的写法 这是新式的写法
那么这个里面啊是这样
那么具体用哪种 那我们来说尽量去用新式的写法去做
下面我们来展示几个例子
嗯 其中的一个例子就是前面我们还没展示的这个例子
init初始化的例子 然后以及后面的这两个例子
我们来看一下 第一我们先来看初始化的这个例子
首先我们来看
这个例子里面我们先赋值tree = 3
这个地方其实就是一个转换
我们的等号的右边是个3 那么它就会是个int类型的
那么它在赋值的时候初始化为float类型
那你会转成float类型 做一次转换
这个地方这种转换方式是可以的 这是double转成int
那么它值也是3 被截掉了
同样的 这个是2.34乘以10的12次方
这个值 我们把它转成int类型
大家想int最高的范围是2乘以10的大约是九次方左右
那这个时候是12次方 那所以说这个值用int它表达不了
那么它的值它会赋给它什么呢 我们过来看看
好 我们来编译一下这个程序
没有出错 这是warning
对吧 警告我们什么呢 它说double往int转
那么这个值从3.98转成3
那么这种隐式地去转 那就可能就是告诉你
警告这样去转是有问题的 可能有问题
它只是警告 不是错误
同样地 它会说
这个2.34乘以10的12次方是out of range value
它只是警告你 然后你可以这样继续做 那我们去看
它警告之后我们不管它 反正程序已经生成了
我们去看它的结果 我们看tree是从3转成float数 就3.00000
guess就3.9变成了3
debt这个2.34又意味着你有很多债务
这样一赋值转成int 变成了什么 0
变成了0
所以说呢 在这儿那就有问题了
你有很多债 突然债务全部归零了
这样是不是很开心呢
嗯 借债的当然开心啊
借了别人钱的开心 但是借出去钱的人不开心
这是类型 还有一个typecast和promotion的例子
在这个里面 这个类型转换
这个叫 auks 19.99 11.99 这样累加
它的值是多少呢
这个好理解 我们前面就讲了这个19.99那就会变成三十一点几
那么既然它是个int类型 那它就是31对吧
这个是多少呢
首先它会先做类型转换 这是一个old style
首先它会先做类型转换 这是一个old style
类型转化 19.99转成int类型 11.99转成int
那这样的话 就会变成19加11就是30
这个呢 同样的话 它这两行其实是一样的 效果
不同的是这个类型转换风格不一样
没关系 它们的值应该是一样
来看下面例子 我们把Z Z是一个字符
这个Z字符我们赋给ch 那我们可以把它打印出来
它就是会打出Z
然后呢 如果我们把它转成整数去打印
那它就会打印出Z的这个编码值 是的
我们也可以用这种方式static_cast去转成整数
这两种方式其实它们最终的结果是一样的
我们来看一下这个例子
OK 我们出来结果31 这个如我们刚才讲的
30 30 Z的编码是90
我们用两种转换方式 它的码都是一样 都是90
我们再来看最后一个例子
promotion promotion就是讲是什么呢
我们先看这个例子 c1在这是127 c2呢是10
那么在这里 c1加c2赋给一个整数是多少
这很明显 c1等于127已经到达了signed char的边界了
因为这是它能表达的最大数值
你再加1 128 signed char是表达不了的
那我直接加了10 那它会是多少呢
如我们前面的整数例子 它会变成一个负数吗 还是其他的
它应该是多少
按照我们整数的那一部分的理解 那么c1加c2它的范围已经是越界了
那可能会变成负数 对不对 这我给大家看一看它到底是什么
我们先编译一下
然后呢 运行一下
结果是sum是137 有没有搞错
没有错 为什么
这里面就是因为promotion 这是个加法操作
那也就是说 这两个数相加的时候
它是先被promote到int 然后再做加法
所以说这是int加int 不是signed char加signed char
所以是int 127加int 10
所以得到结果就是int 137
int 137赋给csum
它的值就是137
没有错 137 这是这里面
所以呢 这些知识点大家要非常的小心
好 我们再来看最后的这个例子
在这个里面 就说我们最后讲讲C++11里面有什么新的标准
C++11里面 我们这个标准里面引入了一个新型的变量auto
用auto可以定义一个变量
这个变量呢 它可以是任意类型 按照你的需求
比如说 在这里n等于100
100是个int类型 所以n就是个int类型
这1.5是个double类型 那么x就是double
这个地方是个long double 那么y就是long double
很方便 所以解决了大家的问题
用这个东西的时候呢要很小心 我个人是不太喜欢用auto
当然 就是一般来说我们这样去滥用 其实我不推荐
auto可能在什么时候有用 也许在一些模板类的时候
比如说一个列表里面存着一些元素 我们不知道元素的类型
那你可以用auto做变量类型 也许会更好一些
是吧 但是不要滥用
还有就是在这向大家介绍一下STL
STL全名叫Standard Template Library
它里面定义了很多的类
比如说vector就是一个类 但是这是一个模板类
它意思就是说这是一个向量 向量里面的元素是double类型的
同样的 这是个迭代器
还有就是这个里面你可以放一些元素 还有这是它的一些简单的用法
begin就是第一个元素 等等
还有更多的数据结构都在这里面有定义啊
你希望用的一些算法也在里面
比如说sort 就是排序里面也有 等等
所以说包罗万象很多
最后推荐一个网站
这个网站呢 叫https://en.cppreference.com/w/cpp
给大家看一下 cppreference这个网站
它里面这个页面呢 它展示了C++的所有标准的东西在里面
而且它还按照标准的不同 C++11 14 17 20
这样列出来 所以说这个就是一个很好的手册
当你要确认某个函数 某个类或者某种变量的名称关键字
是不是在标准里面 你可以在这查
这是最标准的写法 最标准的一个规定
这是英文版的网站 你把前面这个域名改一下 你可以切到中文版
是一个非常好用的非常完整的手册
大家有问题的时候可以在里面去检索
-Quiz 1
-Quiz 2
-3.3 Relational expressions (> < ==)
-3.5 Branching statements (if else)
-3.8 break and continue statements
-Quiz 3
-4.4 Structures, Unions and Enumerations
-Quiz 4
-5.3 Allocate memory: C++ style
-Quiz 5
-6.3 Recursion and pointer to functions
-Quiz 6
-Quiz 7
-8.1 C/C++ with ARM development board
-Quiz 8
-9.2 Constructors and destructors
-Quiz 9
-10.1 Operators in cv::Mat in OpenCV
-10.4 Automatic conversions and type casts for classes
-Quiz 10
-11.1 Dynamic memory and classes
-11.2 New and improved String class
-11.3 Using pointers to objects
-Quiz 11
-12.2 Static and dynamic binding
-12.3 Access control: protected
-12.4 Inheritance and dynamic memory allocation
-Quiz 12
-13.1 Constructor and assignment
-13.2 Classes with object members
-Quiz 13
-14.1 CNN for image classification
-Quiz 14
-15.3 RTTI and type cast operators
-Quiz 15
-Final exam

