1.1.2  迈出另一只脚的第一步——了解运算符与强制类型转换

it2024-03-18  58

嗨,各位小可爱们,大家好哇!

又见面了嗷,这一篇笔记咕咕咕咕咕咕咕咕咕了特别特别久!

因为笔者要作死准备CMC(明明还是大一吧),所以没天没夜的在学数分和高代,晚上还得做一做吉米多维奇来愉悦身心,哪里还有精力嗷~【这一篇笔记还是在计算思维(C程序设计)课上完成的[doge]。

 

emmmmmmm...言归正传,在本篇笔记中主要向大家介绍各类运算符和强制类型转换。由于属于基础内容,因此称为“迈出另一只脚的第一步”【总感觉怪怪的qwq

【其实强制类型转换是上一篇就应该介绍的东西,但是由于自己忘了+前一篇内容感觉挺多了,所以放在这里来讲。

但是,从后面的学习中,大家可以看出这两个内容并不是毫无关系。【其实是自己临时牵线趴


1.1.2  迈出另一只脚的第一步——了解运算符与强制类型转换


目录

1.1.2  迈出另一只脚的第一步——了解运算符与强制类型转换

00  了解运算符

01  算术运算符

算术运算符——四则运算

算术运算符——取模运算

算术运算符——递增递减运算

02  赋值运算符

03  比较运算符

04  逻辑运算符

05  强制类型转换

06  ASCII码


00  了解运算符

 

运算符是什么?

 

大家在小学就熟悉了四则运算。在C++中,四则运算属于算术运算符;

在小学还会学习基本的不等式,这四种基本的大小比较关系,在C++中属于比较运算符。

到了高中之后,稍稍接触过数论的童鞋就会接触到取模运算,取模运算也属于C++中的算术运算符。

进入大学之后,学数学或者学CS的同学就会学习数理逻辑,了解有非、与、或这三种基本逻辑关系(非门、与门、或门也是三种基本的逻辑门电路)。在C++中,也存在完全相同的逻辑运算符。

当然,在前面的笔记 1.1.1  让我们迈出C++编程的第一步吧! 的学习中,我们还知道 = 是赋值的意思。当然,这属于赋值运算符。

以上就是我们将要了解的运算符的基本知识。如果头有点晕,那么理清思绪,把我刚刚说的都忘干净,跟我走吧。


01  算术运算符

 

C++主要的算术运算符为:

加法运算+减法运算

-

乘法运算*除法运算/取模运算%递增运算++递减运算

--

 

算术运算符——四则运算

四则运算是很容易实现的。希望大家能够自己实现。代码示例如下:

#include<iostream> using namespace std; int main() { int a = 20; int b = 10; //加法运算 cout << "a + b = " << a + b << endl; //减法运算 cout << "a - b = " << a - b << endl; //乘法运算 cout << "a * b = " << a * b << endl; //除法运算 cout << "a / b = " << a / b << endl; cout << "b / a = " << b / a << endl; system("pause"); return 0; }

我们观察输出:

我们看到,前面四个式子都是正常输出的,但是当我们计算 10 / 20 时,原本正确的答案应该为 0.5 ,但是输出的却是 0 。

这是怎么回事?难道计算机会犯错吗?我们在这里将问题先留给各位来思考。

 

算术运算符——取模运算

众所周知, 表示  与  关于模同余。在C++中,用下面的代码来表示这个意思。

b = a % m;

例如,我们执行下面的代码:

//取模运算 int c = 10; int d = 4; cout << "c模d为:" << c % d << endl;

输出为: 

取模运算是十分常用的,读者应给予足够的重视。

 

算术运算符——递增递减运算

在C++中,我们可以使用 ++ 或 -- 来表示递增或递减。所谓的递增递减就是 +1 或 -1。

当然,这个内容并没有向上面说的这么简单。例如,我们执行下面的代码:

//递增递减运算 int e = 5; cout << "e = " << e << endl; e = 5; cout << "e = " << e++ << endl; e = 5; cout << "e = " << ++e << endl; e = 5; cout << "e = " << e-- << endl; e = 5; cout << "e = " << --e << endl;

注:上面一堆 e = 5; 并不是多余的操作,而是初始化的必要操作。

输出结果为:

各位小可爱们应该知道上述四个算式的区别了。

递增/递减运算有下面四种:

递增运算++前置递增先让变量+1,再进行表达式运算后置递增先进行表达式运算,再让变量+1递减运算--前置递减先让变量-1,再进行表达式运算后置递减先进行表达式运算,再让变量-1

显然,递增/递减运算符是一种简化代码的方法。灵活运用递增/递减运算符能够让代码简洁清晰。


02  赋值运算符

 

赋值运算符不应该很简单吗?赋值运算符不就是 = 号吗?

当然啦,我们现在知道最常用的赋值运算符就是 = 号。但是赋值运算符不只有等号哦。

赋值运算符分为:

=赋值+=加等于

-=

减等于*=乘等于/=除等于%=模等于

通常来说,例如,对输入的a,我们要求让a-2并输出后者,我们用上述的知识可以写:

int a; cin >> a; a = a - 2; cout << "a = " << a << endl;

如果我们用赋值运算符,我们可以写:

int a; cin >> a; cout << "a = " << (a-=2) << endl;

注意:这里的括号是必要的。如果没有括号会发生什么?读者应该自行尝试一下。

我们看到,输出是完全一样的:

我们看到,合理运用赋值运算符可以减少用作接收值的代码。 

当然,上述a的值是被改变的。如果我们不希望值被改变,要么应该用另一个变量(如 b )来接收a-2,要么应该直接输出 a - 2 。

大家应该注意:要不要让变量的本身改变是十分关键的。在之后对函数乃至引用的学习中,我们会对这句话有更深的理解。

 

另外还有一个小问题需要强调一下:赋值过程中表达式的左值/右值问题。

我们举一个栗子:

//左值右值问题 int a, b; a = 3; 3 = b;

我们发现马上报错:

 

什么叫表达式必须是可修改的左值? 

简单来说,a和b是变量,而3是常量,赋值表达式是将右式的值赋给左式,因此左值必须可修改。

未来在写代码的时候,可一定要理清楚左值和右值的位置,不要闹笑话了呐!


03  比较运算符

 

说到比较运算符,我们通常想到大于、小于等等。当然,比较还会包括等于、不等于等等。分类如下:

等于==不等于!=大于>小于<大于等于>=小于等于<=

 

在讲比较运算符之前,我先问各位一个小问题:如果在IDE中输入 1 >= 2 ,会报错吗?

大家在自行实验之后会发现:不仅不会报错,还可以成功编译。

??不对吧?明明应该有 1 <= 2啊?

现在我们执行这段代码:

cout << (1 <= 2) << endl; cout << (1 >= 2) << endl;

会输出什么呢?

大家是不是想到了什么?

之前学习布尔类型的时候,记不记得我们说过:在C++中,真即为1,假即为0?

 

好了,现在我们可以开始讲比较运算符了。

例如,前面说过的 1 >= 2 ,这是一个运算表达式,而这个表达式会返回一个值。在代码中输入一个表达式,真正输入到程序之中的是这个表达式的返回值。

例如,输入 (1 + 2)时,由于算术运算符构成的表达式返回的是一个同类型的值,因此该表达式返回的就是一个整型数据 3。(尽管我们举的例子全是整型的,事实上对于浮点型甚至字符(串)型均是适用的。至于为什么能够适用这么多的数据类型,我们在重载与模板的学习中会进行详细的说明)

回到我们的比较运算符。由于 (1 >= 2) 在数学中是一个错误的式子,因此该表达式返回的是 false ,也就是 0。

这样,我们就解释了上面的输入,也即比较运算式的返回值问题。

 

另外还有一个很重要的问题,就是赋值 = 与 等于 == 的区别!几乎没有一个初学者不会在初学阶段犯这个错误的。不过不要担心,在一段时间之后,大家都不会多次犯这个问题了(当然,有时候你会发现一大段完美的代码频频报错,竟然还是这里出了问题)。


04  逻辑运算符

 

相比于比较运算符,我们更加容易理解逻辑运算式返回的就是 1 (true) 和 0 (false)。

前面说过,三大核心逻辑运算符就是:非,或,与。所有的逻辑运算都可以由这三个逻辑运算符来组合完成。

非!或||与&&

下面是代码举例:

//逻辑运算符——非 cout << (1 > 2) << endl; cout << !(1 > 2) << endl; //逻辑运算符——或 cout << ((1 > 2) || (1 < 2)) << endl; cout << ((1 > 2) || (2 > 3)) << endl; //逻辑运算符——与 cout << ((1 > 2) && (2 < 1)) << endl; cout << ((1 < 2) && (2 < 3)) << endl;

返回值情况为:

如果读者能够很好的理解上述的代码,说明您的基本逻辑理解能力是没问题的。

在这里肯定有小萌新会有疑问:我还是不太理解这些表达式的返回值的本质是什么,也不理解这些返回值有什么用。

对于表达式的返回值的本质,我们在(很)后面的内容中会介绍运算符重载,在了解 operator 之后,我们就会了解运算符是怎么实现运算并返回结果的。

对于返回值的作用,我们就逻辑运算符来说,其作用就是判断真假。在我们马上要学习的程序流程结构中,我们可以看出判断表达式的真假是至关重要的。

 

到这里,我们在C++初学阶段中应当了解的关于运算符的所有内容就学习完成了。如果你现在还不能在脑海中完整的回想起刚刚学习的运算符以及其用法,那么就再去IDE上动手练习吧!


05  强制类型转换

 

如果是一遍上大学的计算机课程一边看这本笔记的萌新,肯定会疑惑:为啥不讲强制类型转换?

其实呢,第一个原因,这个内容的确是比较基础,然后就在上一篇中忘了讲,发现之后又不想动目录了,干脆在这里讲[doge];

 第二个原因,强制类型转换实际上也是一种运算符,放在这里讲没毛病;

第三个原因,后来想了想,既然这个内容属于“附加”类型,啥时候讲都可以,为啥不能够先让读者对数据类型有足够的重视之后再讲呢?

因此,我们现在来介绍强制类型转换。

 

我们先考虑之前提到过的问题:

in在除法运算中,我们知道,整型与整型进行除法运算的结果还是整型。

如果我们想要让整型运算输出浮点型的运算结果,该怎么办呢?现在,我们就要考虑强制类型转换。

强制类型转换的语法为:

           (类型名)           (表达式)

           (double)            (5 / 3)

事不宜迟,我们马上来实验一下吧:

cout << (double)(5 / 3) << endl;

让我们执行这段代码:

啥玩意?怎么不是我们想要的结果呢?

我们换一下,我们输出下面的代码:

cout << (double)5 / (double)3 << endl;

这样就正确了。

首先希望读者自己思考一下,为什么这两段代码输出的是不同的结果?

在第一段代码中,输出的(5 / 3)确实是double类型,但是根据运算符优先级 ,我们先进行了 5 / 3 的运算,返回值为1 ,double类型的1还是1,这就是第一段代码输出的原因。

在第二段代码中,我们将表达式中的每个数据都变成了我们想要的数据类型,自然我们最终得到的结果就是正确的。 

大家通过这个案例,一定可以对强制类型转换有更深刻的理解——强制类型转换只是针对类型名之后的表达式,让其返回值的类型转换。

这也是为什么我要把这个内容放在这里的原因。在上述运算符的内容中,我们了解了表达式在代码执行过程中实际上可以看作是一个返回值,因此,强制类型转换转换的是返回值,而非表达式。

请大家一定要好好理解表达式与返回值的关系。这在入门学习中是十分关键的。

 

我们现在已经基本了解了强制类型转换的方法。此外,我们还将介绍一个有趣的内容——ASCII码。


06  ASCII码

 

首先希望读者自行在互联网上查阅ASCII码的内容。简单来说,ASCII码就是字符的编码定义——请注意,字符是按照其代码形式储存的。

在C++中,我们想要获得一个字符的ASCII码,我们可以用下面的代码:

//输出字符的ASCII码 cout << (int)('a') << endl; cout << (int)('A') << endl;

执行代码可以知道:小写字母a的ASCII码为97,大写字母A的ASCII码为65。

我们执行下面的代码:

//应用ASCII码 cout << (char)('A' + 3) << endl; cout << (char)(97) << endl;

 输出结果为大写字母D和小写字母a。

至此,相信大家已经初步了解并会初步应用ASCII码了。


到这里,我们在这篇笔记中要学习的知识已经全部介绍完成了。

相信大家听过这样一句话:

你学习一门编程语言,我今天介绍的语法知识你完全忘光都没关系,但是更重要的是理解其中的思想——为什么这个要这么实现?它的底层实现是什么?不理解这些,你学了再多语法都不能算是入门,只能算是停留在Hello World的级别。

当然,这句话把算法给忽略了。但是真正的算法是建立在足够的数学基础之上的,即本质上算法是数学的。而就我们目前的目标而言,学会一门编程语言,知道该怎么写是我们的目标。所以说我们介绍的算法都是基础常用的。

另一方面,这段话指出了底层实现。这当然是学习编程语言中最关键的之一。在上面的运算符学习中,我的举例中全是 int 类型,为啥不把字符类型、字符串类型都讲一遍?事实上,如果我现在告诉你:事实上字符串也可以做四则运算,你可能会发出“啊,我怎么会这么多,你们连这个都不会,我好厉害啊”的感慨。但是,为啥你能做各种数据类型的四则运算?在后面函数的学习中,我们通常会让你做一个表示阶乘或幂运算的函数,你会发现如果我要造一个乘法的函数,必须要指定一个数据类型。难道我要为每个数据类型都搞一个函数吗?在后面我们甚至要创建自己的数据类型,那该怎么办?这里面的底层实现,也许我们目前不需要具体了解,但我们一定要清楚:我们必须要养成了解底层实现的习惯。

 

另外,我们还需要读者养成两个习惯:试错和查阅。

在绝大多数书上,给你的都是正确代码,那么当我们自己写出错误的代码时,你怎么知道错误在哪呢?最好的解决方法就是:你犯过这个错误。在上面很多例子中,也许少一个括号代码就错了,但是你不一定知道这是为什么,甚至不知道这是错的。当你试着去这样写,试图寻找错误的原因,这本身就是在学习。有意地尝试犯错,会让你的学习更加深刻有效。

查阅资料是一个学生的基本能力。你不可能能够在一本书、一本笔记或一个系列的视频中找到所有问题的答案。要学习的东西那么多,谁能够掌握每一个内容?有些内容,特别是一些不常用的编程知识,要用的时候能够找到就可以了。另外,当遇到一个奇怪的报错时,互联网是你最好的帮手。(熟练使用Visual Studio中的“联机搜索”)

 

说了这么一大堆,忘了恭喜大家:

Congratulations!在学习C++的旅途中,大家的两只脚都已经迈出了第一步!(还是感觉好奇怪嗷)

 

那么就这样趴,我们在下一篇笔记中再见啦!

最新回复(0)