Prev: C++Ⅱ:条件与循环
Next: C++Ⅳ:函数
1 介绍数据类型
1.1 数据类型
操作系统根据变量的[ruby=data type]数据类型[/ruby]为其分配内存并决定存储什么样的数据。 数据类型规定了如何正确使用标识符、能存储什么样的数据、能进行什么操作。 C++内置许多数据类型。 Part题: 数据类型旨在? A. 定义头文件名 B. 定义标识符的合理使用 C. 定义循环或if语句 |
1.2 表达式
下面的例子演示了C++中合法和非法的表达式。
你可以通过重载操作符来实现原本非法的表达式。关于这个我们之后会学。 Part题: 下面哪个表达式在C++中是合法的? A. "hello" + 11 B. "hello" * 3.14 C. 12 + 4 D. 12 + "Mike" |
1.3 数值型数据
数值型数据包括: [ruby=Integers]整型[/ruby](整数),例如-7,42。 [ruby=Floating point]浮点[/ruby]数,例如3.14,-42.67。 接下来的课程中,我们会多解释一点。 Part题: 下面哪几个是数值型数据? A. 3.14 B. 1000 C. "hello" D. 'abc' |
1.4 字符串 & 字符
[ruby=string]字符串[/ruby]是由数字、字符、符号组成的。字符串的内容放在双引号中,例如"Hello","我叫David"等。 [ruby=Characters]字符[/ruby]是单个的字母或符号,必须放在单引号中,例如'a'、'b'等。 C++中,单引号标记字符,双引号标记字符串。'a'是一个字符,但"a"是一个字符串。 Part题: 下面哪个是合法的字符,不是字符串? A. "this" B. 'this' C. 't' D. "or this" |
1.5 布尔值
[ruby=Boolean]布尔[/ruby]数据类型只返回两个可能的值:[ruby=真]true[/ruby](1)或[ruby=假]false[/ruby](0)。条件表达式是布尔值的一个例子。 Part题: 10 == 10的结果是true还是false? |
2 int,float,double
2.1 整型(一)
整型类型存储整数,可以是正数或负数。举例,42,-42等。整型的大小取决于程序运行的系统架构,在现代系统上应该是4字节。 Part题: 3.14是整型吗? |
2.2 整型(二)
用int关键字定义整型数据。
包括整型在内的几种基础数据类型都可以使用下面的一个或多个属性[ruby=modifiers]修饰符[/ruby]: [ruby=有符号]signed[/ruby]:一个有符号整型可以存储非负数或负数。 [ruby=无符号]unsigned[/ruby]:一个无符号整型只能存储非负数。 [ruby=短]short[/ruby]:默认大小的一半。 [ruby=长]long[/ruby]:默认大小的两倍。 举例:
根据操作系统不同,整型会保留4-8个字节。 Part题: 填空声明一个只能存储非负整数的变量var。
|
2.3 浮点数
浮点类型可以存储实数,例如420.0,-3.33,0.03325。 “浮点”一词表示在小数点前后都可以出现数字。你可以说小数点有“飘浮”的能力。 有三种不同的浮点数据类型:[ruby=单精度浮点]float[/ruby],[ruby=双精度浮点]double[/ruby],和[ruby=长双精度浮点]long double[/ruby]。 在绝大多数现代计算机架构中,float占4字节,double占8字节,long double可能是double(8字节),也可能是16字节。 举例:
浮点数都是有符号的,意味着它们能存储非负数和负数。 Part题: 浮点数据类型能存储负数吗? |
3 string,char,bool
3.1 字符串
字符串是字符的序列,被双引号包围。 字符串是标准资源的一部分。 如果要使用字符串,必须先包含<string>库。或者,你也可以使用包含string库的库。
<string>库包含在<iostream>库中,所以如果你已经使用了<iostream>,就不再需要单独包含<string>。 Part题: 填空使程序能使用字符串数据类型。
|
3.2 字符
一个字符型变量存储一个1字节的整数,但字符型变量的值通常被解释为一个ASCII字符,而不是整型。 字符数据类型被单引号包围。 举例:
[ruby=American Standard Code for Information Interchange]美国信息交换标准代码[/ruby](ASCII)是一套用于表示计算机文本的字符编码标准。 Part题: 填空声明一个char型变量称为var,值为'z'。
|
3.3 布尔值
布尔数据类型只返回两个可能的值:[ruby=真]true[/ruby](1)或[ruby=假]false[/ruby](0)。 用关键字bool声明一个布尔变量。
如果将布尔值赋给整型,则true变为1,false变为0。 Part题: 填空声明两个布尔变量a和b,用true作为b的初值。
|
4 变量命名规则
4.1 变量命名规则(一)
当给变量命名的时候,要遵循下面的规则:
(Ps. 可以使用汉字作为变量名,但不可使用全角标点符号) 有两种约定俗成的命名方法: Part题: 下面哪条是命名变量的正确规则? A. 不能以字母开头 B. 不能以数字开头 C. 不能包含下划线 |
4.2 大小写敏感性
C++是[ruby=case-sensitive]大小写敏感[/ruby]的,意味着大写的标识符与同名的小写标识符不等同。 举例,myvariable,MYVARIABLE和MyVariable都不相同,它们是三个不同的变量。 起名时应该使其用途明了,例如firstName,lastName。 Part题: 下面哪条是C++中合法的变量名? A. salary B. 14var C. &*^var D. name3_var |
4.3 变量命名规则(二)
C++关键字(保留字)不能用作标识符。 举例,int、float、double、cout不能用作变量名。 事实上对变量名的长度没有限制(视不同系统而言),但是尽量确保变量名有实际意义。 Part题: 填空声明一个名为var3的int变量,一个名为salary的double变量,一个名为ab_c14的bool变量。
|
5 数组
5.1 数组
[ruby=array]数组[/ruby]用来存储一系列数据,也可以将数组想象成相同类型的变量集合。 相比声明多个单独的变量存储单独的值,你同样可以可以用一个数组存储所有值。 当声明数组时,要规定其元素类型,还有其存储的元素数量。 举例:
上面的例子中,变量a被声明为能存储5个整型值的数组 [在方括号中规定] 。 可以在声明时给数组赋初值。
初值包含在{花括号}中,是一个由逗号分隔的列表。 花括号 { } 中值的个数必须不能超过方括号 [ ] 中定义的数组长度。 Part题: 填空创建一个名为myArr的整型数组,大小为5,包含值1、2、3、4、5。
|
5.2 初始化数组
如果省略数组大小,那么会创建一个大小刚好能容纳全部初值的数组。 举例:
这创建一个与之前例子中相同的数组。 数组中的每个元素,或成员,都有其[ruby=index]索引[/ruby],标注了元素的特定位置。 数组的第一个成员索引为0,第二个成员索引为1。 所以,这是我们之前定义的数组b:
要访问数组元素,用方括号中元素位置对数组进行索引。 举例:
Part题: 填空输出一个大小为5的数组的第一个值和最后一个值。
|
5.3 访问数组元素
索引也可以用来给元素赋新值。
这给数组的第三个元素赋值42。 牢记数组索引以0开始。 Part题: C++中数组从几开始计数? A. 0 B. 1 C. 2 |
6 在循环中使用数组
6.1 循环中的数组(一)
有时需要对列表中的元素进行迭代,根据特定的计算给元素重新赋值。通常这需要用[ruby=loop]循环[/ruby]完成。 Part题: 填空声明一个整型数组,大小为9。
|
6.2 循环中的数组(二)
让我们声明一个数组,它会存储5个整型,而且用for循环为每个元素赋值:
数组中的每个元素都被赋予了42的值。 for循环中的x变量用作了数组的索引。 数组最后一个元素的索引是4,所以for循环的条件是x<5。 Part题: 填空声明一个包含9个整型的数组。用for循环给每个元素赋值45。
|
6.3 循环中的数组(三)
让我们输出数组中对应的索引和值。
Part题: 填空输出有3个元素的数组arr中的所有元素:
|
7 计算中的数组
7.1 计算中的数组
下面的代码演示了用for循环计算一个数组中所有元素之和的程序。
让我们回顾一下:我们声明了一个数组,变量sum用于存储元素之和。 接着,我们利用一个for循环迭代数组中的每个元素,并将对应的元素值加到sum变量中。 数组中,第一个元素的索引是0,所以for循环将变量x初始化为0。 Part题: 填空用for循环计算myArray中各元素的和并输出到屏幕上。myArray是一个包含4个double元素的数组。
|
8 多维数组
8.1 多维数组(一)
一个[ruby=multi-dimensional]多维[/ruby]数组存放着一个以上数组。用下面的方式声明多维数组。
下面,我们创建一个3x4的二维int数组:
将这个数组以3行4列表格的方式呈现:
记住,元素计数永远以0开始。 Part题: 填空声明一个2行4列的二维数组multiArr:
|
8.2 二维数组
多维数组可以用花括号包围的值初始化。下面是一个有2行3列的数组:
元素要使用数组的行索引与列索引访问。举例:
第一个索引0指第一行。第二个索引2指第一行中的第三个元素4。 Part题: 填空输出arr第1行第2列的值。
|
8.3 多维数组(二)
数组可以包含任意数量的维度。
上面的例子声明了一个三维string数组。和我们前面做的一样,可以用索引访问和修改元素。 多于三维的数组更难维护。 Part题: 填空声明一个2行3列的数组。用cin输入位于第2行第2列的元素。
|
9 初识指针
9.1 指针(一)
每个变量都是一块内存位置,有自己的[ruby=address]地址[/ruby]。 这个地址可以用[ruby=ampersand]and号[/ruby] (&)运算符(也叫[ruby=address-of]取地址[/ruby]运算符),它表示内存中的地址。 举例:
这会输出存储着变量score的内存地址。 Part题: 填上缺失的运算符,使"fish"变量的地址输出到屏幕上。
|
9.2 指针(二)
[ruby=Pointer]指针[/ruby]是以其他变量的地址为值的变量。 在C++中,指针能使某些任务更容易执行。其他任务,例如动态内存分配,不能不用指针来完成。 所有的指针都是一样的数据类型——一个十六进制long,表示内存地址。 不同指针的区别只有指针所指向变量的数据类型。 Part题: 指针是什么? A. 函数 B. 包含地址的数据类型 C. 头文件 |
9.3 指针(三)
指针也是变量,与其他种类的变量一样,在使用前必须先声明。 星号用来声明指针(和你用来做乘法的星号一样的星号),然而,在这种语句中信号用来将某个变量指定为指针。 下面都是有效的指针声明:
与其他变量相同,我们给指针定义类型并起名。指针的声明类型表示指针指向元素的类型。 星号可以和数据类型放一起,亦可以与变量名放一起,也可以单独放在中间。 Part题: 填上缺失的符号,使变量"ptr"成为指向int的指针。
|
9.4 使用指针
这里,我们将变量的地址赋给一个指针。
上面的代码声明了一个指向整型的指针scorePtr,并用and号(取地址)运算符将变量score的地址赋给它。 现在,scorePtr的值是score的内存位置。 Part题: 填空声明一个指向int的指针,赋予它变量var的地址。
|
10 再谈指针
10.1 指针运算
对于指针,有两种运算符: [ruby=Address-of]取地址[/ruby]运算符 (&):返回其操作数的地址。 [ruby=Contents-of]取内容[/ruby](或[ruby=dereference]间接引用/间接访问[/ruby])运算符 (*):返回其操作数包含的地址存储的值。 举例:
星号(*)在声明中只是简单地表示这个变量是个指针(星号是声明类型的一部分)。不要将它与间接引用运算符混淆了,后者是用来获取某个地址中所存放的值。它们只是两种同类型操作的不同运算。 Part题: 填空声明变量x=25,指针p=x的地址。向屏幕输出指针包含的地址。
|
10.2 间接引用
间接引用运算符(*) 基本就是指针所指值的别名。 话不多说,上例子:
上面三条语句效果相同,结果相同。我们可以通过间接引用变量的指针来访问变量的值。 由于p指向变量x,所以间接引用指针 (*p)与直接使用变量x完全一样。 Part题: 填空声明两个变量a,b;和两个指针pa,pb,分别指向a和b。通过指针pa改变a的值,通过指针pb将值加到b里。
|
11 动态内存
11.1 静态和动态内存
要成为一个成功的C++程序员,就不能不充分了解[ruby=dynamic memory]动态内存[/ruby]的原理。 在C++程序中,内存分两部分: [ruby=stack]栈[/ruby]:你所有的[ruby=local variable]局部变量[/ruby]占用栈内存。 [ruby=heap]堆[/ruby]:未用到的内存,当程序运行时需要动态分配内存时使用这里的内存。 很多时候,你都不会察觉在用变量存储信息时所用内存大小,有时需要的内存大小可以在运行时再决定。 你可以用new运算符在堆中给变量分配一块内存,这个运算符返回所分配内存的地址。
这会在堆中分配一块足以存储一个整型大小数据的内存,并返回这个地址。 Part题: 填空来分配一个int变量大小的内存(用"new"关键字):
|
11.2 动态内存(一)
分配的地址可以存在指针里,之后可以间接引用来访问其变量。 例子:
我们给一个整型动态分配了内存,并给其赋值5。 指针p作为局部变量存储在栈中,它自身存储了堆中分配的地址。值5存储在堆中那个地址的位置。 Part题: 填空声明一个指向int的指针ptr,包含用new int;表达式返回的地址。
|
11.3 动态内存(二)
对于栈中的局部变量,内存管理是自动进行的。 在堆中,就必须手动管理分配的内存,当不再需要它的时候用delete运算符释放这块内存。
这条语句释放pointer指向的内存。 举例:
忘记释放用new关键字分配的地址会导致内存泄漏,因为那块内存在程序结束运行前会一直存在。 Part题: C++中哪个关键字用来释放分配的内存? |
11.4 悬垂指针
delete运算符释放给变量分配的内存,但并不删除指针本身,因为指针存储在栈上。 指向不存在的内存地址的指针叫做[ruby=dangling pointers]悬垂指针[/ruby]。 举例:
NULL指针是有着值0的常量,在不少标准库中都有定义,包括iostream。 Part题: 填空在堆中分配一块int大小的地址,让"ptr"指向它,然后释放分配的内存。
|
11.5 动态内存(三)
动态内存也可以分配给数组。 举例:
注意语法中的方括号。 动态内存分配在很多情况下都很有用,例如当你的程序要依靠输入的时候。举个例子,当你的程序需要读取一个图像文件,它无法提前知道图像的大小,和存储这个图像所需的内存为多少。 Part题: 多选题:下面正确的表述有: A. new在堆中动态分配内存 B. delete释放堆中的内存 C. new返回一个浮点数 D. delete从你计算机中卸载程序 |
12 sizeof() 运算符
12.1 sizeof
虽然对于不同的数据类型,所分配的内存大小由你的计算机架构决定,但C++对每种数据类型的大小都有一个最小限制:
sizeof运算符可以用来获取变量或数据类型占用内存的大小,以字节为单位。 语法:
sizeof运算符以字节为单位返回一个类型或一个变量的大小。 举例:
输出在不同计算机和不同编译器上可能不同。 Part题: 用sizeof()运算符向屏幕输出char类型变量的大小。
|
12.2 数组大小
C++ sizeof运算符也能用来计算数组的大小。 还是举例:
在我们的电脑上,double占8字节。由于数组存储10个double,所以整个数组占80 (8*10) 字节内存。 另外,用整个数组占用的内存大小除以数组中单个元素的大小就能得到数组中元素个数。 例例例:
Part题: 填空声明有10个double的数组,并用sizeof()运算符输出数组占用内存大小。
|
章末检测
1. 补全变量a,b,c,d的数据类型。a是整型,b是双精度浮点,c是字符,d是字符串。
2. 下面哪些是合法的C++变量名? A. notLegal B. 13legal_name C. *!@is-legal D. think_is_LEGAL 3. 填空声明一个包含12个double的数组darr。
4. 补全代码,用for循环向屏幕输出myArray中的元素。
5. 填空声明一个包含14个整型的数组myArray,并用cin运算符给每个元素赋值。
6. new int;表达式的作用是? A. 删除堆中所有内存 B. 在堆中分配内存 C. 声明名为new int的函数 7. 填空声明一指向int的指针"ptr"并将var的地址赋之。
8. 填空声明两个变量a,b;和两个指针pa,pb分别指向a,b。通过pa和pb向屏幕输出a除以b的值。
|