作者简介: 博 主 在 读 机 器 人 研 究 生 , 目 前 研 一 。 对 计 算 机 后 端 感 兴 趣 , 喜 欢 c + + , g o , p y t h o n , 目 前 熟 悉 c + + , g o 语 言 , 数 据 库 , 网 络 编 程 , 了 解 分 布 式 等 相 关 内 容 \textcolor{orange}{博主在读机器人研究生,目前研一。对计算机后端感兴趣,喜欢c++,go,python,目前熟悉c++,go语言,数据库,网络编程,了解分布式等相关内容} 博主在读机器人研究生,目前研一。对计算机后端感兴趣,喜欢c++,go,python,目前熟悉c++,go语言,数据库,网络编程,了解分布式等相关内容
个 人 主 页 : \textcolor{gray}{个人主页:} 个人主页: 小呆鸟_coding
支 持 : \textcolor{gray}{支持:} 支持: 如 果 觉 得 博 主 的 文 章 还 不 错 或 者 您 用 得 到 的 话 , 可 以 免 费 的 关 注 一 下 博 主 , 如 果 三 连 收 藏 支 持 就 更 好 啦 \textcolor{green}{如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦} 如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦 就 是 给 予 我 最 大 的 支 持 ! \textcolor{green}{就是给予我最大的支持!} 就是给予我最大的支持!
本文摘要
本专栏主要是对c++ primer这本圣经的总结,以及每章的相关笔记。目前正在复习这本书。同时希望能够帮助大家一起,学完这本书。 本文主要讲解第2章 变量和基本类型 文章目录
- 第3章 字符串、向量和数组
- 3.1 命名空间的 using 声明
- 3.2 标准库类型string
- 3.2.1 定义和初始化string对象
- 3.2.2 string对象上的操作
- 3.2.3 处理string对象中的字符
- 3.3 标准库类型 vector
- 3.3.1 定义和初始化vector对象
- 3.3.2 像vector对象中添加元素
- 3.3.3 其他vector操作
- 3.4 迭代器介绍
- 3.4.1 使用迭代器
- 3.5 数组
- 3.5.1 定义和初始化内置数组
- 3.5.2 访问数组元素
- 3.5.3 指针和数组
- 3.5.4 c风格字符串
- 3.5.5与旧代码的接口
- 3.6 多维数组
String、vector是俩种最重要的标准库类型,String支持可变长字符串
,vector支持可变长的集合
迭代器是一种与 string 和 vector 配套的标准库类型。常用于访问string中的字符或vector中的元素
内置数组是一种基础的类型,string和vector都是对它的某种抽象。
using std::cin;
(包含头文件)
#include
using std::string
string 默认初始化是一个空字符串
初始化string
对象的方式:
初始化方式 | 解释 |
---|---|
string s1 | 默认初始化,s1 是个空字符串 |
string s2(s1) | s2 是 s1 的副本 |
string s2 = s1 | 等价于 s2( s1 ),s2 是 s1 的副本 |
string s3(“value”) | s3 是字面值 “value” 的副本,除了字面值最后的那个空字符外 |
string s3 = “value” | 等价于 s3(“value”),s3 是字面值 “value” 的副本 |
string s4(n, ‘c’) | 把 s4 初始化为由连续 n 个字符 c 组成的串 |
注意:
初始化方式
string s5 = "hello"; //拷贝初始化
string s6("hello"); //直接初始化
string s7{hello}; //列表初始化
string 常用操作
string 常用操作 | |
---|---|
getline(is, s) | 从is中读取一行赋给s,返回is (is 是输入流) |
s.empty() | s 为空返回true,否则返回false |
s.size() | 返回 s 中字符的个数 |
s[n] | 返回 s 中第 n 个字符的引用,位置 n 从0计起 |
s1+s2 | 返回 s1 和 s2 连接后的结果 |
s1=s2 | 用 s2 的副本代替 s1 中原来的字符 |
s1==s2 | 如果 s1 和 s2 中所含的字符完全一样,则它们相等;string对象的相等性判断对字母的大小写敏感 |
s1!=s2 | 同上 |
<, <=, >, >= | 利用字符在字典中的顺序进行比较,且对字母的大小写敏感(对第一个不相同的位置进行比较) |
注意
:
cin >> string
,在读取string对象时,string对象会自动忽略开头的空白(空格、换行符、等)并从第一个真正的字符串开始读,知道遇见下一个空白为止,因此不能使用 cin 读取句子
,但是可以读取单词
;string s;
cin >> s; //输入hello world
cout << s << endl; //输出为hello
读写string对象
使用cin
和 cout
来读写string对象
使用getline 函数读取一行
getline()
函数定义在头文件string
中注意是换行符和上面空白字符不一样
)注意
:getline 会将换行符也读入,但是不将换行符存入 string 对象。触发 getline() 函数返回的那个换行符实际上被丢弃掉了。得到的string对象中不包含换行符。string s; //读取到文件末尾结束
while(getline(cin, s)) //输入为hello world
cout << s << endl; //输出为hello world
string::size_type 类型
string:: size_type
auto
和 declltype
来获取此类型auto len = s.size();// len 的类型是 string::size_type
注意:
在一条表达式中已经有了size()函数,就不要使用int了,这样可以避免混用int 和 unsigned可能会带来问题。
俩个string对象相加
string s1 = "hello,";
string s2 = "world";
string s3 = s1 + s2;
cout << s3 << endl; //hello,world
字面值和string对象相加
切记字面值和string是不一样的
俩个string对象相加
string s1 = "hello,";
string s2 = "world";
string s3 = s1 + s2;
cout << s3 << endl; //hello,world
string对象和字符字面值相加
至少有一个是string
string s4 = s1 + "," //正确,左侧为string对象,右侧为字符字面值
string s5 = "hello" + "," //错误,左右俩侧都是字符字面值
string s6 = s1 + "," + "world" //正确
string s7 = "hello" + "," + s1 //错误,俩个字面值不能相加
//等价于string s7 = ("hello" + ",") + s1
cctype 头文件中有下列标准库函数来处理 string 中的字符。
cctype头文件中的函数 | 解释 |
---|---|
isalnum(c) |
当c 是字母或数字时为真 |
isalpha(c) |
当c 是字母时为真 |
iscntrl(c) |
当c 是控制字符时为真 |
isdigit(c) |
当c 是数字时为真 |
isgraph(c) |
当c 不是空格但可以打印时为真 |
islower(c) |
当c 是小写字母时为真 |
isprint(c) |
当c 是可打印字符时为真 |
ispunct(c) |
当c 是标点符号时为真 |
isspace(c) |
当c 是空白时为真(空格、横向制表符、纵向制表符、回车符、换行符、进纸符) |
isupper(c) |
当c 是大写字母时为真 |
isxdigit(c) |
当c 是十六进制数字时为真 |
tolower(c) |
当c 是大写字母,输出对应的小写字母;否则原样输出c |
toupper(c) |
当c 是小写字母,输出对应的大写字母;否则原样输出c |
建议
:使用 c++ 版本的标准库头文件,即 cname 而非 name.h 类型的头文件。cname 头文件中的名字都从属于命名空间 std;
范围for循环
string str("hello world");
for(auto c:str) // 对于str中的每个字符
cout << c << endl; // 输出当前字符,后面紧跟一个换行符 hello world
改变 string 对象中的值
时,需要把循环变量定义成引用类型
。必须通过显示添加 & 符号来声明引用类型。for(auto &c:s)
c = toupper(c); // 小写转换为大写
访问string中的某一个字符,有俩种方式 1. 可以通过[ ], 2.可以通过迭代器
类模板
而非类型,vector是一个类型。容器
,可以容纳各种数据类型vector <int> v1; //vector默认初始化是一个0.
vector<string> v2(v1); // v2=v1
vector<string> v2 = v1; //等价于v2(v1)
vector<string> v3(10,"dainian"); // 10个string
vector<string> v4(10); // 10个空string
vector<string> v5{"a","hahah"}; // 列表初始化
vector<string> v5 = {"a","hahah"}; //等价上面
列表初始化
{}
来表示列表初始化,初始化过程会尽量把花括号内的值当作一个初始值列表来处理。vector<string> v {10}; // v 有 10 个默认初始化的元素
vector<string> v {10, "hello"}; // v 有 10 个值为 "hi" 的元素
值初始化
如果vector 对象的元素是内置类型,比如int 则元素初始值为0,如果是类类型,则由类默认初始化。
v.size(); //返回v中元素的个数
v.empty(); //如果v不含有任何元素,返回真;否则返回假
v.push_back(t); //向v的尾端添加一个值为t的元素
v[n] //返回v中第n个位置上元素的引用
v1 = v2 //用v2中的元素拷贝替换v1中的元素
v1 = {a,b,c...} //用列表中元素的拷贝替换v1中的元素
v1 == v2 // v1和v2相等当且仅当它们的元素数量相同且对应位置的元素值都相同
v1 != v2
<,<=,>, >= //以字典顺序进行比较
(只能访问元素,或者更改已经存在的元素)
,但是不能用于添加元素。
如果是容器,尽量都采用迭代器进行操作
好比指针
)auto b = v.begin(), e = v.end() //返回的是iterator类型
auto c = v.cbegin(), f = v.cend() //返回的是const_iterator类型
注意:如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器
迭代器运算符
运算符 | 解释 |
---|---|
*iter | 返回迭代器iter所指向的元素的引用 |
iter->mem | 等价于(*iter).mem |
++iter | 令iter指示容器中的下一个元素 |
- -iter | 令iter指示容器中的上一个元素 |
iter1 == iter2 | 判断两个迭代器是否相等 |
iter1 != iter2 | 判断两个迭代器是否不相等 |
迭代器类型
迭代器分为俩种类型:
vector<int>::iterator it; //it能读写
string::iterator it;
vector<int>::const_iterator it; //it只能读
string::const_iterator;
begin和end返回值类型
vector<int> v;
const vector<int> v1;
auto it = v.begin(); //it类型是iterator
auto it1 = v1.begin(); //it1类型为const_iterator
注意:凡是使用了迭代器进行循环,都不要向迭代器所属的容器中添加或者删除元素,可以更改元素,都则,迭代器不知道指向哪个元素,迭代器会失效
迭代器运算
string 和 vector支持的迭代运算。注意不能将俩个迭代器相加。
vector
和string
迭代器支持的运算:
运算符 | 解释 |
---|---|
iter + n | 迭代器加上一个整数值仍得到一个迭代器,迭代器指示的新位置和原来相比向前移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指示容器尾元素的下一位置。 |
iter - n | 迭代器减去一个证书仍得到一个迭代器,迭代器指示的新位置比原来向后移动了若干个元素。结果迭代器或者指向容器内的一个元素,或者指示容器尾元素的下一位置。 |
iter1 += n | 迭代器加法的复合赋值语句,将iter1 加n的结果赋给iter1 |
iter1 -= n | 迭代器减法的复合赋值语句,将iter2 减n的加过赋给iter1 |
iter1 - iter2 | 两个迭代器相减的结果是它们之间的距离,也就是说,将运算符右侧的迭代器向前移动差值个元素后得到左侧的迭代器。参与运算的两个迭代器必须指向的是同一个容器中的元素或者尾元素的下一位置。 |
>、>=、<、<= | 迭代器的关系运算符,如果某迭代器 |
int a[0]; //数组的维度必须是个常量表达式
unsigned cnt = 42 //不是常量表达式
constexpr unsigned cnt = 42; //是常量表达式
string strs[get_size()]; //当get_size()是constexpr时,是常量表达式
字符数组的特殊性
char a1[] = {'c','+', '+' }; //列表初始化,没有空字符,维度是3
char a2[] = "c ++"; //有空字符串,维度是4;
const char a4[3] = "c++"; //错误,没有空间存放空字符
不能用数组为另一个数组赋值或拷贝。可以按元素一个一个拷贝,但不能直接拷贝整个数组。
理解复杂的数组声明
因为数组本身是一个对象,所以允许定义数组的指针以及数组的引用。
从数组的名字开始右内向外的顺序比较好理解
int *ptr[10]; // ptrs是一个含有10个整型指针的数组
int (*ptr)[10] = &arr; // ptrs是一个指针,指向一个含有10个整数的数组
int (&ptr)[10] = &arr; // ptrs是一个引用,引用一个含有10个整数的数组
例如:
(*ptr)[10] = &arr
; ptrs是一个指针,指向一个含有10个整数的数组for语句
或者下标运算符
来进行访问size_t类型
(是一种无符号类型,他被设计的足够大以便能表示内存中任意对象的大小)数组相比vector的缺点是什么
//数组需要每个元素进行拷贝
int arr[10];
for (int i = 0; i < 10; ++i) arr[i] = i;
int arr2[10];
for (int i = 0; i < 10; ++i) arr2[i] = arr[i];
//vector可以直接拷贝
vector<int> v(10);
for (int i = 0; i != 10; ++i) v[i] = arr[i];
vector<int> v2(v);
for (auto i : v2) cout << i << " ";
不是一种类型,而是一种写法
,是为了表达和使用字符串而形成的一种约定俗成的写法。空字符('\0')
结束。函数 | 介绍 |
---|---|
strlen(p1) | 返回p1 的长度,空字符不计算在内 |
strcmp(p1, p2) | 比较p1 和p2 的相等性。如果p1==p2 ,返回0;如果p1>p2 ,返回一个正值;如果p1 |
strcat(p1, p2) | 将p2 附加到p1 之后,返回p1 |
strcpy(p1, p2) | 将p2 拷贝给p1 ,返回p1 |
char ca[] = {"hello", "world"} //不以空字符结束
cout << strlen(ca) << endl; //错误:ca没有以空字符结束
对于 string,可以使用 s = s1 + s2,s1 > s2 等加和与比较,而 c 风格字符串不行,因为他们实际上是指针。
string对象和C风格字符串的混用
可以使用字符串字面值来初始化 string 对象或与 string 对象加和,所有可以用字符串字面值的地方都可以使用以空字符结束的字符数组来代替。
反过来不能使用 string 对象初始化字符数组,必须要用 c_str() 函数将 string 对象转化为 c 风格字符串
string s ("hello world");
const char *str = s; //错误,不能用string对象初始化char*
const char* cp = s.c_str(); // s.c_str() 返回一个指向以空字符结束的字符数组的指针。
使用数组初始化 vector 对象
int arr[] = {0, 1, 2, 3, 4, 5};
vector<int> ivec(begin(arr), end(arr));
建议不要使用 c 风格字符串和内置数值,都使用标准库容器
严格来说 C++ 中没有多维数组,那实际是数组的数组。
int arr[20][30][40] //将所有元素初始化为 0
多维数组的初始化
//显示初始化所有元素
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}
int a[3][4] = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}} //与上面等价
//显示初始化部分元素
int a[3][4] = {{0},{1},{2}}; //只是初始化了每一行的第一个元素
多维数组的下标引用
int arr[3][4];
arr[0];//这是一个有四个元素的一维数组
arr[0][0];//第一行第一列的元素
使用范围 for 语句处理多维数组
注意范围 for 语句中改变元素值要显示使用 & 符号声明为引用类型。
注意使用范围 for 循环处理多维数组时,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。
constexpr size_t rowCnt = 3, colCnt = 4;
int ia [rowCnt][colCnt];
for(auto& row : arr) //给每一行赋值
for(auto col : row) //给每一列进行赋值,例如先赋值[0][0],[0][1],[0][2]
输出 arr 的元素有四种方法
// 范围 for 语句-不使用类型别名
for (const int (&row)[4] : arr)
for (int col : row)
cout << col << " ";
cout << endl;
// 范围 for 语句-使用类型别名
using int_array = int[4];
for (int_array &p : ia)
for (int q : p)
cout << q << " ";
cout << endl;
// 普通 for 循环
for (size_t i = 0; i != 3; ++i)
for (size_t j = 0; j != 4; ++j)
cout << arr[i][j] << " ";
cout << endl;
// 指针
for (int (*row)[4] = arr; row != arr + 3; ++row)
for (int *col = *row; col != *row + 4; ++col)
cout << *col << " ";
cout << endl;
指针vs引用
动态数组
new
和 delete
表达和c中malloc
和free
类似的功能,即在堆(自由存储区)中分配存储空间。int *pia = new int[10];
10可以被一个变量替代。delete [] pia;
,注意不要忘记[]。