第 2 章 处理数据
文章目录
2.1 初始化
C++ 支持以下种初始化的方式:
int owls = 101; //case 1
int wrens(432); //case 2
int hamburgers = {24}; //case 3
int emus{7}; //case 4
int rocs = {}; //case 5 变量初始化为0
int psychics{}; //case 6 变量初始化为0
其中,case 1
的初始化语法来自 C 语言,而其他几种均来自于 C++。对于用大括号初始化的方式,若括号内不包含任何东西,则变量初始化为
0
0
0。
通过使用 C++ 新增的大括号初始化器,初始化常规变量的方式与初始化类变量的方式更像,C++11 使得可将大括号初始化器用于任何类型(可以使用等号,也可以不使用),这是一种更加通用的初始化语法。
简记:可用
=、()、{}
初始化变量。
2.2 简单变量
2.2.1 整型字面值
整型字面值(常量)是显示地书写的常量。C++ 能够以三种不同的计数方式来书写整数:
10
10
10 进制、
8
8
8 进制和
16
16
16 进制。C++ 使用前一(两)位来标识数字常量的基数。如果第一位为
1
∼
9
1\sim 9
1∼9,则基数为
10
10
10;如果第一位为
0
0
0,第二位为
1
∼
7
1\sim 7
1∼7,则基数为
8
8
8;如果前两位为 0x
或 0X
,则基数为
16
16
16。
#include <iostream>
int main()
{
using namespace std;
int chest = 42;
int waist = 0x42;
int inseam = 042;
cout << "Monsieur cuts a striking figure!\n";
cout << "chest: " << chest << endl;
cout << hex;
cout << "waist: " << waist << endl;
cout << oct;
cout << "inseam: " << inseam << endl;
}
上面的程序展示了利用三种不同方式书写整数。其中,dec、hex 和 oct
分别用于指示 cout
以十进制、十六进制和八进制格式显示整数。诸如 cout<<hex;
等代码不会在屏幕上显示任何内容,而只是修改 cout
显示整数的方式。另外,由于标识符 hex
位于名称空间 std
种,而程序用了该名称空间,所以不能将 hex
用作变量名。然而,如果省略编译指令 using
,而使用 std::hex
,则可以用 hex
用作变量名。
2.2.2 成员函数 cout.put
#include <iostream>
using namespace std;
int main()
{
char ch = 'M';
cout.put(ch);
}
函数 cout.put()
是一个重要的 C++ OOP 概念——成员函数——的第一个例子,其功能是输出一个字符。类定义了如何表示和控制数据,成员函数归类所有,描述了操纵类数据对象的方法。例如,类 ostream
有一个 put()
成员函数,用来输出字符。只能通过类的特定对象(如 cout
)来使用成员函数。要通过对象使用成员函数,必须用句点将对象名和函数名称连接起来。句点(.
)被称为成员运算符。cout.put()
的意思是,通过类对象 cout
来使用函数 put()
。
2.2.3 char
char
与 int
不同,在默认情况下既不是没有符号,也不是有符号,是否有符号由 C++ 决定实现。下面介绍几种 C++ 新增字符类型。
-
wchar_t
程序需要处理的字符集可能无法用一个 8 8 8 位的字节表示,如汉字系统。在这种情况下,可以使用类型
wchar_t
(宽字符类型)表示扩展字符集。这种类型也是一种整型,大小取决于实现(可能是unsigned short
,也可能是int
)。
cin、cout
将输入和输出看作是char
流,因此不适于用来处理wchar_t
类型。iostream
提供了作用相似的工具wcin、wcout
来处理wchar_t
流。另外,可以通过加上前缀L
来指示宽字符常量和宽字符串。如下:wchar_t bob = L'P'; wcout << L"tall" << endl;
-
char16_t
和char32_t
进行字符串编码时,如果有特定长度和符号特征的类型,将很有帮助,而类型 wchar_t
的长度和符号特征随实现而异。因此,C++11 新增了类型 char16_t
和 char32_t
,两者都是无符号的,长度分别为
16
、
32
16、32
16、32 位。C++11 使用前缀 u
来表示 char16_t
字符类型和字符串常量,如 u'C'
和 u"be good"
;使用前缀 U
表示 char32_t
常量,如 U'R'
和 U"dirty rat"
。
2.2.4 bool
C++ 增加了一种新类型 bool
(不需要像 C 一样引头文件),和 C 一样,将非零解释为 true
,将零解释为 false
。如:
bool is_ready = true;
字面值 true、false
都可以通过提升转换为 int
类型,true
转换为
1
1
1,false
转换为
0
0
0:
int ans = true; //ans = 1
int promise = false; //promise = 0
另外,任何数字值或指针值都可以被隐式转换为 bool
值:
bool start = -100; //start = true;
bool stop = 0; // stop = false;
2.3 const
限定符
在 C 语言中,常量通常使用 #define
定义,而 C++ 有一种更好的处理符号常量的方法,就是用 const
关键字来修改变量声明和初始化。如 const int Months = 12;
。
常量被初始化之后,其值就固定了,编译器将不允许再修改该常量的值。
如何区分常量和普通变量呢?一种常见的做法是将名称的首字母大写。这决不是一种通用约定,但阅读程序时有助于区分常量和变量。另一种约定是将整个名称大写,使用 #define
时通常使用这种约定。
注意,应在声明中对 const
进行初始化。下面代码无效:
const int a;
a = 10;
用 const
修饰常量有以下几个好处:首先,它能够指明变量类型;其次,可以使用 C++ 的作用域规则将定义限制在特定的函数或文件中;最后,可以将 const
用于更加复杂的类型,如数组和结构体。
2.4 浮点数
2.4.1 书写浮点数
C++ 有两种书写浮点数的方式。第一种是使用标准小数点表示法:
12.34
0.0012
8.0
第二种是 E 表示法:
2.52e+8
7E5
-18.32e13
9.11e-31
E 表示法适合用于非常大和非常小的数。
E 表示法确保数字以浮点格式储存,即使没有小数点,如 7E5
。注意,既可以使用 E
也可以使用 e
,指数既可以是正数也可以是负数。
2.4.2 浮点类型
#include <iostream>
int main()
{
using namespace std;
cout.setf(ios_base::fixed, ios_base::floatfield);
float tub = 10.0 / 3.0;
double mint = 10.0 / 3.0;
long double ore = 10.0 / 3.0;
}
C++ 有三种浮点类型:float、double、long double
,前两个通常分别为
32
、
64
32、64
32、64位,而 long double
可能为
80
、
96
、
128
80、96、128
80、96、128位。
程序中 setf()
迫使输出使用定点表示法,它防止程序把较大的值切换为 E 表示法,并使程序显示到小数点后
6
6
6 位。
2.4.3 浮点常量
在默认情况下,像 8.24
和 2.4E8
这样的浮点常量都属于 double
类型。如果希望常量为 float
类型,应使用 f
或 F
后缀。对于 long double
类型,可使用 l
或 L
后缀。
2.5 类型转换
2.5.1 以 {}
方式初始化时进行的转换
C++11 使用大括号的初始化称为列表初始化,这种初始化对于类型转换的要求更严格:列表初始化不允许缩窄,即变量的类型可能无法表示赋给它的值。例如,不允许将浮点型转换为整型。
const int code = 66;
int x = 66;
char c1 {31325}; //错误,不允许缩窄
char c2 = {66}; //正确
char c3 {code}; //正确
char c4 = {x}; //错误,x不是常量
x = 31325; //7a 5d
char c5 = x; //正确,x会被截断,保留5d,最终结果为93
2.5.2 表达式中的转换
先看看自动转换。在计算表达式时,C++ 将 bool、char、unsigned char、signed char、short
值转换为 int
,这些转换被称为整型提升。通常将 int
类型选择为计算机最自然的类型,这意味着计算机使用这种类型时,运算速度可能最快。例如:
short chickens = 20;
short ducks = 35;
short fowl = chickens + ducks;
在计算 fowl
时,chickens
和 ducks
都先提升为 int
类型,然后再将求和后的 int
结果转换为 short
。
将不同类型进行算术运算时,也会进行一些转换。当运算涉及两种类型时,较小的类型将被转换为较大的类型。例如,float + int
,int
将转换为 float
类型。
2.5.3 强制类型转换
强制类型转换的通用格式如下:
(typeName) value; //e.g. (int)1.0
typeName (value); //e.g. int(1.0)
第一种格式来自于 C,第二种格式是纯粹的 C++。新格式的想法是,要让强制类型转换就像是函数调用。
C++ 还引入了
4
4
4 个强制类型转换运算符,对它们的使用更加严格,将在以后介绍。其中,static_cast<>
可用于将值从一种数值类型转换为另一种数值类型。C++ 开发者认为,C 语言的强制类型转换比较危险,所有 static_cast<>
比传统强制类型转换更加严格。
2.5.4 C++11 中的 auto
声明
C++11 重新定义了 auto
,让编译器能够根据初始值类型推断变量的类型。auto
是一个 C 关键字,但极为少用。在 C++ 中,如果使用 auto
而不指定变量类型,编译器将把变量的类型设置成与初始值相同(自动推断类型)。
auto n = 100; //n is int
auto x = 1.5; //x is double
auto y = 1.3e12L; //y is long double
auto
引入对于复杂类型非常好用,如:
std::vector<double> scores;
std::vector<double>::iterator pv = scores.begin();
引入 auto
:
std::vector<double> scores;
auto pv = scores.begin();