C++ Primer Plus学习(一)—— 基础知识
基础知识
最近开始对C++进行系统学习,学习的过程中也会将书上的知识和实践所得进行梳理分享,希望和大家一起学习进步!
预备知识
- C++融合了3种不同的编程方式:C语言(高效、简洁、快速、可移植性)代表的过程性语言,C++在C语言基础上添加的类代表的面向对象语言(OOP-Object Oriented Programming),C++模板支持的泛型编程。
- 计算机语言要处理两个概念——数据和算法。过程性语言强调的是编程的算法方面,面向对象编程的理念是设计与问题的本质特性相对应的数据格式。
- OOP编程并不仅仅是将数据和方法合并为类定义。例如,OOP还有助于创建可重用的代码,这将减少大量的工作。信息隐藏可以保护数据,使其免遭不适当的访问。多态让您能够为运算符和函数创建多个定义,通过编程上下文来确定使用哪个定义。继承让您能够使用旧类派生出新类。
int main(void)
和int main()
效果是一样的,表明函数不接受任何参数;void main()
表示该函数不返回任何值。- 如果编译器到达
main()
函数末尾时没有遇到返回语句,则认为main()
函数以如下语句结尾:return 0
。这条隐含的返回语句只适用于main()
函数,而不适用于其他函数。
头文件名命名约定
-
头文件类型 约定 示例 说明 C++旧式风格 以.h结尾 iostream.h C++程序可以使用 C旧式风格 以.h结尾 math.h C、C++程序可以使用 C++新式风格 没有扩展名 iostream C++程序可以使用,使用namespace std 转换后的C 加上前缀c, 没有扩展名 cmath C++程序可以使用,可以使用不是C的特性,如namespace std
名称空间/命名空间
- 如果使用iostream,而不是iostream.h,则应使用下面的名称空间编译指令来使iostream中的定义对程序可用:
using namespace std
(using编译指令) 或者using std::cout
,using std::endl
等。 - 对象是类的特定实例,而类定义了数据的存储和使用方式。
cout
是一个预定义的对象,知道如何显示字符串,数字和单个字符等。
名称 符号 备注 另一个含义 插入运算符 << 运算符重载 左移运算符 控制符 endl 重启一行 - 换行符 \n 显示用引号括起的字符串时,用该换行符,其他情况下使用控制符endl - 地址运算符 & 运算符重载 按位AND运算符 乘法 * 运算符重载 对指针解除引用
C++源代码风格:
· 每条语句占一行;
· 每个函数都有一个开始花括号和一个结束花括号,这两个花括号各占一行;
· 函数中的语句都相对于花括号进行缩进;
· 与函数名称相关的圆括号周围没有空白。
- 类之于对象就像类型之于变量;类描述了一种数据类型的全部属性(包括可使用它执行的操作),对象是根据这些描述创建的实体。
- 函数原型之于函数就像变量声明之于变量。
- 库文件中包含了函数的编译代码,而头文件中则包含了原型。只包含cmath头文件可以提供原型,但不一定会导致编译器搜索正确的库文件。
- C++允许在创建变量时对它进行赋值,这个过程叫做初始化(initialization)。
- 当前通行的理念是,只让需要访问名称空间std的函数访问它是更好的选择。
处理数据
变量名
C++必须遵循几种简单的命名规范:
- 在名称中只能使用字母字符、数字和下划线;
- 名称的第一个字符不能是数字;
- 区分大写字符与小写字符;
- 不能将C++关键字用作名称;
- 以两个下划线或下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符;
- C++对于名称的长度没有限制,名称中所有的字符都有意义,但有些平台有长度限制。
位与字节
- 字节(byte)通常指的是8位(bit)的内存单元。从这个意义上说,字节指的就是描述计算机内存量的度量单位,1KB等于1024字节,1MB等于1024KB。然而,C++字节由至少能够容纳实现的基本字符集的相邻位组成,也就是说,可能取值的数目必须等于或超过字符数目。在美国,基本字符集通常是ASCII和EBCDIC字符集,他们都可以用8位来容纳,所以在使用这两种字符集的系统中,C++字节通常包含8位。然而,国际编程可能需要使用更大的字符集,如Unicode,因此有些实现可能使用16位甚至32位的字节。
- sizeof运算符返回类型或变量的长度,单位为字节。
数据类型
类型 | 字节 | 范围 |
---|---|---|
char | 1 个字节 | -128 到 127 或者 0 到 255 |
unsigned char | 1 个字节 | 0 到 255 |
signed char | 1 个字节 | -128 到 127 |
int | 4 个字节 | -2147483648 到 2147483647 |
unsigned int | 4 个字节 | 0 到 4294967295 |
signed int | 4 个字节 | -2147483648 到 2147483647 |
short int | 2 个字节 | -32768 到 32767 |
unsigned short int | 2 个字节 | 0 到 65,535 |
signed short int | 2 个字节 | -32768 到 32767 |
long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
signed long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
unsigned long int | 8 个字节 | 0 到 18,446,744,073,709,551,615 |
float | 4 个字节 | 精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字) |
double | 8 个字节 | 双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字) |
long double | 16 个字节 | 长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。 |
wchar_t | 2 或 4 个字节 | 1 个宽字符 |
注:C++提供了一种灵活的标准,它确保了最小长度:
- short至少16位;
- int至少与short一样长;
- long至少32位,且至少与int一样长;
- long long至少64位,且至少与long一样长。
为何float有效位数为7位
C/C++编译器标准都遵照IEEE制定的浮点数表示法来进行float,double运算,这两种数据类型在内存中的存储主要分成三部分,分别是:
-
符号位(Sign):0代表正数,1代表负数
-
指数位(Exponent):用于存储科学计数法中的指数部分,并且采用移位存储方式
-
尾数位(Mantissa):用于存储尾数部分
-
float是32位,其中有23位用于存放尾数,带有一个固定隐含位(小数点前有一位固定是1, 也就是说,23位尾数可能是 .1···23位···1,即整体为24位1.1···23位···1),所以float有24个二进制有效位位数。
-
2^24=16,777,216 共有8个十进制位,所以有些编译器float的有效数字位是8位,有些有效数字位是7位。
-
double也一样,是64位, 其中有52位用于存放尾数, 一个固定隐含位. 共有 53个二进制有效位位数。
-
2^53次方有15个十进制位, 所以有些编译器double的有效数字位是15位, 有些是16位。
-
举个例子:
· 17.625转成二进制数为10001.101(2^4 + 2^0 + 2^(-1) + 2^(-3));
· 10001.101为 (1.0001101 * 10^4)去掉第一位1,得到尾数为 0001101,指数为4;
· 指数是无符号的,偏移量为127,因此17.625的指数位位131,即10000011;
· 因此17.625在内存中的存储形式为 0 10000011 0001101000000000000000 -
还有一个问题,float的上下限是怎么取到的?
· 8位指数可以表示2^8=256,即(0~255),是个无符号的量,但是有127的偏移量,也就是指数范围是(-127 ~ 128)
· 因此,float最大可以表示129位二进制数,即范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38 -
这里再附一份浮点类型的列表
Type | Sign | Exponent | Significand field | Total | Exponent Bias | Bits Precision | Number of decimal digits |
---|---|---|---|---|---|---|---|
Half | 1 | 5 | 10 | 16 | 15 | 11 | ~3.3 |
Single | 1 | 8 | 23 | 32 | 127 | 24 | ~7.2 |
Double | 1 | 11 | 52 | 64 | 1023 | 53 | ~15.9 |
注:Half是用16位表示浮点数的一种数据类型,在IEEE 754中也有规定,这种数据类型在深度学习系统中的应用比较广泛。但是在当前主流cpu上,不支持half类型数据的计算和输出。
climits
头文件climits定义了符号常量来表示类型的限制。
符号常量 | 表示 |
---|---|
CHAR_BIT | char的位数 |
CAHR_MAX | char的最大值 |
CHAR_MIN | char的最小值 |
SCHAR_MAX | signed char的最大值 |
SCHAR_MIN | signed char的最小值 |
UCHAR_MAX | unsigned char的最大值 |
SHRT_MAX | short的最大值 |
SHRT_MIN | short的最小值 |
USHRT_MAX | unsigned short的最大值 |
INT_MAX | int的最大值 |
INT_MIN | int的最小值 |
UINT_MAX | unsigned int的最大值 |
LONG_MAX | long的最大值 |
LONG_MIN | long的最小值 |
ULONG_MAX | unsigned long的最大值 |
LLONG_MAX | long long的最大值 |
LLONG_MIN | long long的最小值 |
ULLONG_MAX | unsigned long long的最大值 |
初始化
- 初始化将赋值与声明合并在一起;
- 可以使用字面值常量来初始化;
- 可以将变量初始化为另一个变量条件是后者已经定义过;
- 可以使用表达式来初始化变量,条件是当程序执行到该声明时,表达式中所有的值都是已知的;
- 如果不对函数内部定义的变量进行初始化,该变量的值将是不确定的。这意味着该变量的值将是它被创建之前,相应内存单元保存的值;
- 将大括号初始化器用于单值变量的初始化,大括号内也可以不包含任何东西,这种情况下,变量将被初始化为零。
整型
- 对于一个short值,32767 + 1 --> -32768; 对于一个unsigned short,0 - 1 --> 65535.
注:如果超出了限制,其值将为范围另一端的取值。C++确保了无符号类型的这种行为,但C++并不保证符号整型超越限制(上溢和下溢)时不出错。 - 通常,int被设置为对目标计算机而言最为“自然”的长度。自然长度(natural size)指的是计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其他类型,则应使用int。
- C++使用前一(两)位来标识数字常量的基数。如果第一位为1 ~ 9,则基数为10(十进制);如果第一位是0,第二位为1 ~ 7,则基数为8(八进制);如果前两位为0x或0X,则基数为16(十六进制)。
- C++提供了控制符dec、hex和oct,分别用于指示cout以十进制,十六进制和八进制格式显示整数。
int chest = 42; int waist = 42; int inseam = 42; cout << hex; //该行只是修改cout显示整数的方式,不会在屏幕上显示任何内容! cout << "waist = " << waist << endl; cout << oct; cout << "inseam = " << inseam << endl;
浮点数相对整型的优缺点
- 优点:
· 可以表示整数之间的值;
· 由于有缩放因子,可以表示的范围大得多; - 缺点:
· 浮点运算的速度通常比整数运算慢;
· 浮点运算的精度会降低。
转义运算符
转义字符 | 意义 | ASCII码值(十进制) |
---|---|---|
\a | 响铃(BEL) | 007 |
\b | 退格(BS) ,将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF) ,将当前位置移到下一行开头 | 010 |
\r | 回车(CR) ,将当前位置移到本行开头 | 013 |
\t | 水平制表(HT) (跳到下一个TAB位置) | 009 |
\v | 垂直制表(VT) | 011 |
\ | 代表一个反斜线字符 | 092 |
’ | 代表一个单引号(撇号)字符 | 039 |
" | 代表一个双引号字符 | 034 |
? | 代表一个问号 | 063 |
\0 | 空字符(NUL) | 000 |
\ddd | 1到3位八进制数所代表的任意字符 | 三位八进制 |
\xhh | 十六进制所代表的任意字符 | 十六进制 |
算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A + B 将得到 30 |
- | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
* | 把两个操作数相乘 | A * B 将得到 200 |
/ | 分子除以分母 | B / A 将得到 2 |
% | 取模运算符,整除后的余数 | B % A 将得到 0 |
++ | 自增运算符,整数值增加 1 | A++ 将得到 11 |
– | 自减运算符,整数值减少 1 | A-- 将得到 9 |
注:python中和C++中取模运算符有所区别
项目 | python | C++ |
---|---|---|
9%2 | 1 | 1 |
9%(-2) | -1 | 1 |
(-9)%2 | 1 | -1 |
(-9)%(-2) | -1 | -1 |
类型转换
C++自动执行很多类型转换:
- 将一种算术类型的值赋给另一种算术类型的变量时,C++将对值进行转换;
- 表达式中包含不同的类型时,C++将对值进行转换;
- 将参数传递给函数时,C++将对值进行转换。