C++字符串与向量与数组
# 运算符
# 三元表达式
三元表达式将一个简单的if-else逻辑嵌入到表达式中,其格式如下:
条件表达式 ? 表达式1 : 表达式2;
表示如果条件表达式结果为真,则结果为表达式1的结果,否则为表达式2的结果。 例如:
bool isopen = true;
string res = isopen ? "已开启" : "未开启";
cout << res << endl;
2
3
# sizeof运算符
sizeof运算符用来获取类型占用大小,它会返回表达式结果类型或指定类型所占的字节数,sizeof的使用格式有两种:sizeof (类型名)
和sizeof 表达式
。
例如:
// 直接指定类型即可获取指定类型所占的内存空间大小。
sizeof(int);
// sizeof不会关心表达式的值,只会关心其结果的类型,获取类型的占用大小。
int *p;
// 得到指针类型本身所占的空间大小
sizeof p;
// 得到指针所指类型的空间大小,此处为int类型的大小
sizeof *p;
// 对于数组会返回该数组占用的大小,因此我们可以使用sizeof计算数组的元素数量,用数组大小除以单个元素大小即可。
sizeof(iarr) / sizeof(*iarr);
2
3
4
5
6
7
8
9
10
11
# 类型转换
在C++语言中,类型之间是有关联关系的,如果两种类型可以互相转换那他们就存在关联关系。而类型转换就是将表达式从原类型转化成另一种类型。
# 隐式转换
编译器自动对运算对象进行的类型转换被称作隐式转换,隐式转换一般出现在以下情况:
- 条件判断中,非布尔值会转化为布尔值。
例如条件判断中,整数值为非0会转化为真,整数值为0会转化为假。
- 大多数表达式中,整数提升会把比int宽度小的小整数类型转换成较大的整数类型。在char、bool、short等小整数类型参与运算时,它们会至少提升至int类型。
例如两个bool类型相加,则运算结果会为int类型。
- 初始化或赋值过程中,右侧的运算对象会转换为左侧运算对象的类型。
例如给int类型的变量,赋值了一个浮点数类型1.22值,则运算结果只取整数部分转化为int类型,也就是1值。
- 函数调用时,实参类型如果与形参类型不一致,则实参会转换成形参的类型。
例如函数需要一个int类型的参数,但是传入了一个浮点数类型1.22值,则传入的实参会转化为int类型,也就是1值。
- 多种类型参数运算时,其结果会为最宽的那个类型。浮点数和整数运算时,会结果会为浮点数。无符号类型和有符号类型运算时,结果会为无符号,宽度不一致时还会使用最宽的那个类型。
例如int类型和long类型值运算时结果转化为long类型。int类型和float类型运算时结果为float型。unsigned int类型和long类型运算时结果为unsigned long类型。
# 显式转换
显式转换又称强制类型转换,它可以让我们将对象强制转换成另一种指定的类型。
强制类型转换的格式为:cast-name<type>(expression);
,expression表示要进行类型转换的表达式对象、type表示要转换的目标类型、cast-name表示转换方式。
显式转换方式共有以下四种:
- static_cast 用于相关类型之间的转换,只要表达式不包含底层const都可以使用。例如在将较大的算术类型赋值给较小的类型时也可以使用,显式转换就不会有警告信息。
float slope = static_cast<float>(1.2);
- const_cast 用于消除变量的const限定,只能改变运算对象的底层const,转换之后的变量将不再具有const性质。他能将常量对象转换成非常量对象,常用于有函数重载上下文中。
const char *pc;
char *p = const_cast<char*>(pc);
2
- reinterpret_cast 用于重新解释类型,它能进行不相关类型之间的转换,但目标和原始值之间至少要有相同的位数,否则转换会出错。他可以用于实现多个进程的内存共享,首先将指针转换为整数进行传输,再将整数转换为指针进行使用。
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
using std::hex;
using std::uppercase;
int main() {
string s = "Hello";
string* sptr = &s;
// 将指针存储的内存地址(&s)转换为整数,sptr是指针类型在64位系统下是8字节,所以转换目标也要是8字节,因此使用int64_t
int64_t sptri = reinterpret_cast<int64_t>(sptr);
// 输出可以得到数字,将其转换为十六机制后对比可以发现,指针转为整数,实际就是将指针内存地址的十六进制转为十进制。
cout << "指针地址为:" << sptr << endl;
cout << "转换后的整数为:" << sptri <<",十六进制为:" << std::uppercase << std::hex << sptri << endl;
// 将整数值转换为指针类型
string* rep = reinterpret_cast<string*>(sptri);
// 输出可以得到s的值"Hello"
cout << "整数转换回指针后,其解引用的值为:" << *rep << endl;
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
它为不相关类型之间转换带来了便利,但也伴随着风险的,编译器不会对其给出任何警告和提示,排错时会非常困难。reinterpret_cast依赖于机器,要想安全使用该显式转换需要对涉及的类型和编译器实现转换的过程非常了解。
- dynamic_cast 用于运行时检测的类型转换。
# 旧式强制类型转换
除了上面四种显式转换方式外,我们还可以使用C++早期版本的显式转换。有关联关系的类型使用旧式强制类型转换,效果类似于static_cast和const_cast。没有关联关系的类型使用旧式强制类型转换,效果类似于reinterpret_cast。 旧式强制类型转换共有两种格式:
// 函数形式的强制类型转换
type(expression);
// C语言风格的强制类型转换
(type)expr;
2
3
4
例如:
// 同等与static_cast<int>('A');
int i = int('A');
// 将内存地址(指针)转换为int类型,同等于reinterpret_cast<int>(&i);
int64_t sptri = (int64_t)&i;
// 将int类型值转换为char指针,同等于reinterpret_cast<char*>(sptri);
char* rep = (char*)sptri;
// 输出A
cout << *rep << endl;
2
3
4
5
6
7
8