1、第一部分第四课:内存,变量和引用
2、第一部分第五课预告:简易计算器
上一课《【C++探索之旅】第一部分第三课:第一个C++程序》中,我们已经学习了如何创建,编译,运行我们的第一个C++程序。我们也解释了这个程序每一行的意义。
我们不但在IDE(Integrated Development Environment,集成开发环境。例如Visual Studio,Codeblocks,xCode等)中创建程序,也学习了如何在终端命令行中创建。
不过到目前为止,我们写的程序还非常简单,只能在屏幕上显示消息,还不能和用户进行交互。我们慢慢来弥补这一缺憾。
在此之前,我们首先来学习一个计算机科学的基本概念,就是:变量。
变量使用电脑的内存来存储信息,以便之后再次使用。大家应该用过计算器吧,我们平时不太使用的几个键:M+,M-,MR,MC,其实就是在使用变量和内存的概念(M是Memory的缩写,表示《内存》),这几个键的作用如下:
M+:把目前显示的值放在存储器中 (memory +)
M- :从存储器内容中减去当前显示值 (memory -)
MR:调用存储器内容 (memory recall)
MC:清除存储器内容 (memory clear)
以上这些按键,可以操作存储在计算器的存储器(内存)里的计算值。
我们将在电脑上学习类似的事情,毕竟我们的电脑兄说到底不过是一台大“计算器”,本质上就是做二进制(0和1)的运算,不然也不会叫“计算机”了对吧。
什么是变量
上面我们举了计算器的例子来更形象地说明,毕竟在信息技术的世界里,基本的原理是相通的。在我们的电脑里,也有一些电子元件,可以储存数值,并且能保存一段时间。当然,背后的科学原理是比较复杂的。
不过大家可以放心,我们没必要搞清楚这背后的一套复杂的原理,我们只需要学会怎么把数值存储到电脑的内存中就好了。至于复杂的部分就交由编译器和操作系统来处理了,是不是突然觉得生活很美好呢?
我们只需要知道变量其实就是电脑借给我们的一小段内存,里面储存了数值。我们可以想象电脑里面有一个大橱柜(比喻内存),如下图所示。这个大橱柜非比寻常,因为它拥有成千上万(甚至数十亿)个小抽屉,这些小抽屉就是内存中我们可以存放数值的地方。
电脑的内存的原理就有点像一个有着很多抽屉的大橱柜。
对于一个计算器来说,我么通常一次只能储存一个数值。但是我们的电脑可比普通的计算器厉害多了。不然也不会那么贵了,对吧?说的就是你,苹果电脑。
聪明如你应该料想到了:在C++程序中,我们可以同时储存很多变量。因此,就需要区分这些变量,以便之后调用时可以分得清谁是谁。因此,在C++程序中,每个变量拥有一个名字。这个名字就有点像上图中的抽屉外面贴的标签,使我们能够找到所要的抽屉。
我们的电脑还可以使我们储存不同的数值,比如我们想储存数字,字母,单词,句子,图片,声音,等等。这就涉及到变量的类型了。
你可以想象变量的类型就好比抽屉的不同样式,在生活中,我们放葡萄酒和书籍的抽屉是不一样的,不是吗?
变量名
对于人来说,名字很重要,名字起得好,有很多益处。名字起得不好,会很搞笑。
变量也有名字,而给C++中的变量起名字有如下规则:
只能包含字母,数字和下划线(_)
第一个字符必须是字母或下划线
不能和C++的关键字重复,比如不能是int,char,if,while等。
例如:
name,studentNum,year2015,_computerPrice 等都是规范的命名。
而:
+animal,@gmail,*1991,等都是通不过的命名。
除此之外,C++对于大小写敏感。也就是说,大写字母和小写字母在C++看来是不同的。有的编程语言不区分大小写。所以,在C++中,givenName,GIVENname,GiVenName是不同的变量名。
另外,希望大家养成良好的命名习惯,使自己的变量做到见名知意,这样程序就可以自注释了。比如,我们提倡这样的变量名:myName,computerPrice。而不推荐类似 name1,variable3,hehe2,之类不知所云的名字。
对于程序的编译器来说,这样并没有什么用,因为它才不管你名字起得是不是见名知意。但是,对于你自己和以后要阅读你的程序人来说,一个好的变量名会发挥很大的作用,不然过了一段时间再看自己的代码,可能都忘了这个变量是用来干嘛的。
小编自己有个变量命名习惯,此习惯不少程序员也遵守:
变量名由小写字母开头
如果变量名由几个单词组成,那么紧挨着写
除了第一个单词,其他单词的第一个字母大写
例如:
bestRestaurantName,secondBugReport,等等。
这样的命名法也称为《小驼峰式命名法(lower camel case)》。
变量类型
之前说了,变量除了有名字,还有类型。就好比“小明”这个名字,不知道是人呢还是一只宠物。
C++的变量类型如下图所示:
有点多是吗?初学时不用一下子都记住,我们慢慢来学习。一开始只要知道几种常用的变量类型就可以了。如下:
常用类型 |
可以存储的数值 |
---|---|
|
|
|
一个字符 |
|
整数 |
|
无符号整数(正整数或0) |
|
带小数点的数(其实double是双精度浮点数) |
|
字符串(0到多个字符) |
一般,我们在IDE中输入以上这些变量类型时,IDE会用颜色来高亮显示。
这些类型可储存的数值有大小范围,也就是上下限。比如有的很大的整数,int类型就不能储存。这些上下限取决于你的电脑,操作系统和编译器。
当我们使用变量时,就需要考虑用哪种变量类型了。例如你要储存一个学校的学生数目,那么int和unsigned int会适合。要储存一个人的身高,那么用double会适合。要储存你自己的名字,那么string会适合。
那么bool这种变量类型是什么意思呢?
bool其实是boolean(布尔类型)的意思,它只能储存两种值:true(真)或false(假)。
我们可以用bool类型的变量来储存例如: 用户名是否正确,是不是程序员,有没有女朋友,之类。
变量声明
变量的英语是variable,是《可变的,变化不定的》,所以说,变量和女人的心有点像,不是吗?开个小玩笑。
因此,变量储存的数值是可以改变的。
好了,铺垫也够多了,该来正式请求电脑出借它的“抽屉”了(前面我们用抽屉比喻一块内存空间)。用术语来说,就是变量声明。
注意:我们暂时用《声明》这个词,其实要澄清一下:
==========================
对变量而言,声明与定义的关系稍微复杂一些。在声明部分出现的变量有两种情况:一种是需要在内存中建立存储空间的(如int a;);另一种是不需要建立存储空间的(如extern int a; 以后会讲到extern关键字)。前者称为定义型声明(defining declaration),或简称为定义(definition)。后者称为引用型声明(referenceing declaration)。
广义地说,声明包括定义,但并非所有的声明都是定义。对 int a; 而言,它是定义性声明,既可说是声明,又可说是定义。而对 extern int a; 而言,它是声明而不是定义。一般为了叙述方便,把建立存储空间的声明称为定义,而把不需要建立存储空间的声明称为声明。
在这一课中所有用到《声明》的地方,其实用的是《定义型声明》。以后的课会讲解《引用型声明》。
==========================
我们需要向电脑提供变量的类型,名字和它储存的值。这里的值会成为变量的初始值。
为了做到这一点,我们只需按照以下格式:
类型 名字 (值);
以上的格式是C++中初始化一个变量的方式。
我们也可以用另一种从C语言继承过来的格式:
类型 名字 = 值;
这两种格式的效果是一样的。我们推荐使用第一种格式,以后的课程中会讲述为什么选第一种格式更好。
可不要忘了句末的分号(;),这个错误即使是有经验的程序员也会犯。当然这个错误也不难发现,只不过它会让你的编译器不安分而已。
我们就来声明(定义型声明)一个变量,这个变量叫做userAge,用于储存《用户年龄》:
#include
using namespace std;
int main()
{
int userAge(16);
return 0;
}
上面程序的第6行发生了什么呢?
答:电脑得知我们要向它的内存借一个“抽屉”,这个抽屉有以下特性:
可以储存整数
抽屉外面贴了一个标签,名叫 userAge
抽屉里储存的值是16
因此,一旦程序运行完了第6行代码,你就成为电脑内存中那个抽屉的主人了,如下图:
因为之后我们会继续向电脑借很多“抽屉”,所以我们需要把图画得简单些。如下:
大大的蓝色矩形代表的是电脑的内存,目前,内存几乎是空的。
黄色的小正方形代表电脑出借给我们的内存的一块空间。也就是我们之前比喻的一个抽屉。它里面储存的值是16,而它的标签是userAge。
既然我们画了如此好(chou)看(lou)的图,那岂能只声明一个变量。一不做二不休:
#include
using namespace std;
int main()
{
int userAge(16);
int money(432); //钱数
double pi(3.14159);
bool isHoliday(true); //是不是假期
char letter('a');
return 0;
}
上面的程序中,我们在userAge这个变量之外,又声明了好几个新的变量。
有两点需要注意:
bool类型的变量只能储存true或false中的一个值,不是true(真),就是false(假),除此之外不能储存其他值。
char变量的值需要用单引号括起来,不要写成 char letter(c); 而是 char letter('c');
插一句题外话:写程序时要勤写注释,哪怕看似比较简单的地方,因为以后别人看你的程序,或者你自己回看自己的程序,假如没有注释,那可能会增加不少难度。
对于上面这个程序,我们也可以画一个图,只要在之前的图上增加新的变量即可。
可以看到,我们多声明了几个变量,内存里面开始变得丰富多彩起来了。马上要圣诞了,人多一些总是热闹。
上面的程序,我们如果编译,运行,可以看到它什么也没有输出。那是当然的,因为我们只是声明了一些变量,还没使用它们呢。
我希望你没有太失望,虽然这个程序没有显示什么,但其实在背后电脑是进行了很多操作的。只不过这些操作对用户隐藏起来了,我们也不太感兴趣而已。不过我们还是总结一下上面的变量声明究竟做了什么:
你的程序向操作系统(简称OS,是Operating System的缩写。例如Windows,Mac OS X,Linux等都是常见的操作系统)借一些内存来使用
操作系统查看内存是否有空余的空间,如果有则分配几个“抽屉”(代表内存空间)给你的程序
你的程序逐一将那些值存放进对应的抽屉。例如在贴有userAge标签的抽屉里,存放进16;在贴有money标签的抽屉里存放进432;等等
运行到最后一行(return 0;)时,你的程序把所有抽屉清空,并且还给操作系统
字符串的情况
前面说了,字符串这种变量类型的情况有点特殊。为了使用字符串变量,我们首先需要在程序中多加一行:
#include
表示引入string这个C++的标准库,这样我们才能使用其中的函数等。我们可以写个程序:
#include
#include
using namespace std;
int main()
{
string userName("Steve Jobs");
return 0;
}
可以看到,我们声明了一个字符串变量,它的名字是userName,里面存放的值是Steve Jobs(苹果的前CEO)。
可以看到,给string型变量赋值,用的是双引号",而之前给char型变量赋值时用的是单引号'。其实呢,字符串(string)就是由一串字符(char)组成的。
偷懒的小技巧
在继续下面的内容之前,我们介绍一种“偷懒”的小技巧,很多程序员都会用:
如果你有多个同一类型的变量要声明,那么可以将它们放在同一行里,彼此用逗号隔开。如下:
int a(2), b(4), c(6); //我们声明了三个整型变量a, b, c,分别存放了2, 4, 6三个值
string userNameApple("Steve Jobs"), userNameMicrosoft("Bill Gates");
//我们声明了两个字符串变量userNameApple和userNameMicrosoft,分别存放Steve
Jobs(史蒂夫乔布斯)和Bill Gates(比尔盖茨)。
这样我们就不用每次都写一遍变量类型名了,上例中是int和string。
声明但不初始化
上面我们学习了如何声明一个变量(其实是定义型声明),其实声明一个变量时你的程序陆续做了两件事:
首先,程序向操作系统请求拨给一块内存空间,称为“变量分配”。
然后,在这块内存空间上存入初始值,称为“变量初始化”。
但是,有的时候我们在声明变量时还没有想好要赋什么值。所以,我们也可以声明变量,但不初始化。
怎么做呢?很简单,只需要写变量类型和变量名,就可以了。如下:
类型 名字;
是不是很简单呢?我们来看例子程序:
#include
#include
using namespace std;
int main()
{
string qqName; // QQ用户名
string qqNumber; // QQ号
bool isVIP; // 是不是QQ的VIP会员
return 0;
}
注意:有一个常见的错误是:
在变量名之后加空的括号,例如 string qqNumber();
这是不正确的,不要加括号,只需要类型和名字。
我们也用图解来演示上面的程序:
可以看到,在声明变量后,变量中的值是一个任意值。
但是通常我们最好在声明时给变量赋初值,特别是指针的情况,以后我们会学习。而且有的变量类型还必须在声明时就初始化。
显示变量的值
在上一课中,我们已经学习了如何在屏幕上显示文本,希望你没有忘记大明湖畔的夏雨荷。
是的,这位"夏雨荷"就是 cout<<
cout有点类似C语言的printf函数,是C++里面负责标准输出的。不过又有不同,我们可以看到cout后面不是加括号,而是连接了<<这个特殊的符号。
暂时我们不深入,因为cout其实不是一个函数,cout是一个ostream类的对象(关于类和对象,之后的课程会讲解),它有一个成员运算符函数operator<<(涉及到C++的运算符重载的技术,以后会讲)。(这一句指令暂时不需要理解,只要知道cout<<可以用来向屏幕输出内容即可)。
那么机智如你,应该猜到怎么显示变量的值了吧。
是的,就是把文本替换成变量名就行了。如下:
cout << userAge;
这么简单,你敢信?
是的,就是这么简单。
#include
using namespace std;
int main()
{
int userAge(16);
cout << "你的年龄是 : ";
cout << userAge;
return 0;
}
运行以上程序,显示:
你的年龄是 : 16
当然了,我们也可以同时显示好几个变量的值,并且把一句话的内容都写在一行上。如下:
#include
#include
using namespace std;
int main()
{
int userIQ(150);
string userName("Albert Einstein"); // 阿尔伯特.爱因斯坦
cout << "你名叫 " << userName<< ", 你的智商是 " << userIQ<< endl;
return 0;
}
运行以上程序,显示:
你名叫 Albert Einstein, 你的智商是 150
引用
在结束这一课之前,我们还有一个很重要的知识点需要介绍。
这个知识点就是:引用
《引用》的英语是reference。
我们之前说过,变量可以被看成内存里的一个“抽屉”。这个抽屉外面可以贴标签,就是变量名。
实际生活中,我们可以在同一个抽屉外面贴上不止一个标签。那么,在C++中,我们也可以给同一个内存的“抽屉”上贴好多个标签。
因此,我们就多了一种访问变量的方式。就好像我们给变量取一个别名。但是别名听起来没有那么高大上,所以C++中称之为“引用”。听着是不是挺玄乎的,其实就是别名。
我们可以用下图来演示:
可以看到,在内存中的这个变量上,有两个标签。一个是userAge,声明此变量时起的变量名;另一个是myVariable,是它的别名,也就是引用。
比如,黄晓明,也可以叫小明,两个名字指代的都是那个人,都爱着Angelababy。
那么引用怎么声明呢?要用到一个特殊的符号:&
int userAge(16); // 声明一个变量,名字是userAge
int& myVariable(userAge); // 声明一个引用变量,名叫myVariable,它是userAge变量的别名。
可以看到,userAge放在了myVariable后面的括号里,还记得变量如何初始化吗?就是在括号里填入初始值。因此,这里相当于把userAge“赋值”给了myVariable
说到底,userAge和myVariable指向的是同一个“抽屉”,同一个变量。它们的值都是16。
用术语说就是:myVariable引用了userAge。
引用变量的类型必须和它要引用的变量一样。而且,引用变量声明时必须赋初值。
我们来看一个例子程序:
#include
using namespace std;
int main()
{
int userAge(16); // 一个变量,名字是userAge,包含一个整型数值16
int& myReference(userAge); // 变量userAge的一个引用
// 从现在开始,我们可以不加区分地使用userAge或myReference
// 因为它们实际上是一个内存中“抽屉”的两个标签,指向的是相同内容
cout << "你已经 " << userAge << " 岁了. (通过 变量名)" << endl;
// 惯常的方式
cout << "你已经 " << myReference << " 岁了. (通过 引用)" << endl;
// 用引用的方式来访问变量值
return 0;
}
运行以上程序,显示:
你已经 16 岁了. (通过 变量名)
你已经 16 岁了. (通过 引用)
那么,引用到底有什么用呢?
好问题。在上面的例子中,仿佛看不出引用有多大用处。
也许暂时你觉得引用比较抽象,也貌似没什么用。但是要知道,引用是C++中很重要的一块知识点,而且以后我们会“大宝啊,天天见”,会经常使用到“引用”的。而且还会区分什么时候用引用,什么时候用指针。
因此,先对引用的概念有个了解,对我们之后处理更复杂的用例是大有裨益的。
总结
变量是存储在内存里的一段信息
根据存储的信息的不同,变量有不同类型:int,char,bool,double,等
变量在使用前需要先声明,例如:int number(28); // 此处是定义型声明
可以用cout来显示变量的值
引用其实是变量的别名,有点像标签,使我们可以用另一个名字来调用变量,例如:int& numberReference(number);
今天的课就到这里,一起加油吧!
下一课我们学习:简易计算器