命名空间
| #include <iostream> |
| |
| using std::cin; |
| |
| int main() { |
| |
| int i; |
| cin >> i; |
| |
| std::cout << i; |
| |
| return 0; |
| } |
| |
标准库类型 string
- 需要包含头文件
#include <string>
- string 定义在命名空间 std 中。
using std::string;
初始化 string 对象的方式
| string s1; |
| string s2(s1); |
| string s2 = s1; |
| string s3("value"); |
| string s3 = "value"; |
| string s4(n, 'c'); |
- 拷贝初始化:编译器把等号右侧的初始值拷贝到新建的对象中去
- 直接初始化:与之相反,不使用等号
| string s5 = "hiya"; |
| string s6("hoya"); |
| string s7(10, 'c'); |
| |
| string s8 = string(10, 'c'); |
| |
| string temp(10, 'c'); |
| string s8 = temp; |
string对象上的操作
| os << s 将 s 写到输出流 os 当中,返回os |
| is >> s 从 is 中读取字符串赋给 s,字符串以空白分隔,返回 is |
| getline(is, s) 从 is 中读取一行赋给s,返回 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 等性判断对字母的大小写敏感 |
| <, <= ,>, >= 利用字符在字典中的顺序进行比较,且对字母的大小写敏感 |
读写 string 对象
| int main() { |
| |
| string s; |
| cin >> s; |
| cout << s << endl; |
| |
| return 0; |
| } |
在执行读取操作时,string对象会自动忽略开头的空白(即空格符、换行符、制表符等),并从一个真正的字符开始读起,直到遇见下一处空白为止。
例如:输入" Hello World! ", 输出为"Hello"。
getline
- getline 只要一遇到换行符就结束读取操作并返回结果(注意换行符也被读进来了),哪怕输入的一开始就是换行符也是如此。(字符串中不存换行符)
string::size_type
- size() 函数返回的是一个 string::size_type 类型,是无符号类型的值,足够存放下任何 string 对象的大小
| int main() { |
| |
| string s; |
| cin >> s; |
| |
| string::size_type len = s.size(); |
| cout << len << endl; |
| |
| return 0; |
| } |
字面值和 string 对象相加
- 当把 string 对象和字串字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是 string
| string s4 = s1 + ", "; |
| string s5 = "hello" + ", "; |
| |
| string s6 = s1 + ", " + "world"; |
| string s7 = "hello" + ", " + s2; |
因为某些历史原因,也为了与C兼容,所以C++语言中的字符串字面值并不是标准库类型string的对象。切记,字符串字面值与string是不同的类型。
cctype 头文件中的函数
| isalnum(c) 当 c 是字母或数字时为真 |
| isalpha(c) 当 c 是字母时为真 |
| iscntrl(c) 当 c 是控制字符时为真 |
| isdigit(c) 当 c 是数字时为真 |
| isgraph(c) 当 c 不是空格但可打印时为真 |
| islower(c) 当 c 是小写字母时为真 |
| isprint(c) 当 c 是可打印字符时为真(即 c 是空格或 c 具有可视形式) |
| ispunct(c) 当 c 是标点符号时为真(即 c 不是控制字符、数字、字母、可打印空白中的一种) |
| isspace(c) 当 c 是空白时为真(即 c 是空格、横向制表符、纵向制表符、回车符、换行符、进纸符中的一种) |
| isupper(c) 当 c 是大写字母时为真 |
| isxdigit(c) 当 c 是十六进制数字时为真 |
| tolower(c) 如果 c 是大写字母,输出对应的小写字母:否则原样输出 c |
| toupper(c) 如果 c 是小写字母,输出对应的大写字母:否则原样输出 c |
例:将第一个单词大写
| string s("some string"); |
| |
| for (decltype(s.size()) index = 0; index != s.size() && !isspace(s[index]); ++ index) { |
| s[index] = toupper(s[index]); |
| } |
| |
| cout << s << endl; |
标准库类型 vector
- 需要包含头文件
#include <vector>
- 需要 using 声明
using std::vector
编译器根据模板创建类或函数的过程成为实例化
| vector<int> ivec; |
| vector<Sales_item> Sales_vec; |
| vector<vector<string> > file; |
定义和初始化 vector 对象
| vector<T> v1 v1 是一个空 vector,它潜在的元素是 T 类型的,执行默认初始化 |
| vector<T> v2(v1) v2 中包含有 v1 所有元素的副本 |
| vector<T> v2 = v1 等价于 v2(v1),v2 中包含有 v1 所有元素的副本 |
| vector<T> v3(n, val) v3 包含了 n 个重复的元素,每个元素的值都是 val |
| vector<T> v4(n) v4 包含了 n 个重复地执行了值初始化的对象 |
| vector<T> v5{a, b, c...} v5 包含了初始值个数的元素,每个元素被赋予相应的初始值 |
| vector<T> v5 = {a, b, c...} 等价于 v5{a, b, c...} |
值初始化
- 如果用的是圆括号,可以说提供的值是用来构造 vector 对象的。
- 如果用的是花括号,可以表述成我们想列表初始化该 vector 对象。
| vector<int> v1(10); |
| vector<int> v2{10}; |
| |
| vector<int> v3(10, 1); |
| vector<int> v4{10, 1}; |
- 如果初始化时使用了花括号的形式但是提供的值又不能用来列表初始化,就要考虑用这样的值来构造 vector 对象了。
| vector<string> v5{"hi"}; |
| vector<string> v6("hi"); |
| vector<string> v7{10}; |
| vector<string> v8{10, "hi"}; |
vector 比较重要的操作
| v.empty() 如果 v 不含有任何元素,返回真:否则返回假 |
| v.size() 返回 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 |
| <, <=, >, >= 顾名思义,以字典序进行比较 |
- size 的返回值类型为:
vector<int>::size_type
只能对确知已存在的元素执行下标操作
| vector<int> ivec; |
| cout << ivec[0]; |
| |
| vector<int> ivec2(10); |
| cout << ivec2[10]; |
迭代器
- 如果容器为空,则 begin 和 end 返回的是同一个迭代器,都是尾后迭代器。
标准容器迭代器的运算符
| *iter 返回迭代器 iter 所指元素的引用 |
| iter -> mem 解引用 iter 并获取该元素的名为 mem 的成员,等价于 (*iter).mem |
| ++ iter 令 iter 指示容器中的下一个元素 |
| -- iter 令 iter 指示容器中的上一个元素 |
| iter1 == iter2 判断两个迭代器是否相等(不相等),如果两个迭代器指示的是同一个元 |
| iter1 != iter2 素或者它们是同一个容器的尾后迭代器,则相等:反之,不相等 |
- 拥有迭代器的标准库类型使用
iterator
和const_iterator
来表示迭代器的类型
| vector<int>::iterator it; |
| string::iterator it2; |
| |
| vector<int>::const_iterator it3; |
| string::const_iterator it4; |
- begin 和 end 返回的具体类型由对象是否是常量决定,如果对象是常量,begin 和 end 返回 const_iterator; 如果不是常量,返回 iterator
| vector<int> v; |
| const vector<int> cv; |
| auto it1 = v.begin(); |
| auto it2 = cv.begin(); |
- 为了便于专门得到 const_iterator 类型的返回值,C++11新标准引入了两个新函数,分别是 cbegin 和 cend;
谨记,但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素,任何一种可能改变 vector 对象容量的操作,都会使该 vector 对象的迭代器失效
vector 和 string 迭代器支持的运算
| iter + n 迭代器加上一个整数值仍得一个迭代器,迭代器指示的新位置与原来相比 |
| 向前移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指 |
| 示容器尾元素的下一位置 |
| iter - n 迭代器减去一个整数值仍得一个迭代器,迭代器指示的新位置与原来相比 |
| 向后移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指 |
| 示容器尾元素的下一位置 |
| iter1 += n 迭代器加法的复合赋值语句,将 iter1 加 n 的结果赋给 iter1 |
| iter1 -= n 迭代器减法的复合赋值语句,将 iter1 减 n 的结果赋给 iter1 |
| iter1 - iter2 两个迭代器相减的结果是它们之间的距离,也就是说,将运算符右侧的迭 |
| 代器向前移动差值个元素后将得到左侧的迭代器。参与运算的两个迭代器 |
| 必须指向的是同一个容器中的元素或者尾元素的下一位置 |
| >, >=, <, <= 迭代器的关系运算符,如果某迭代器指向的容器位置在另一个迭代器所指 |
| 位置之前,则说前者小于后者。参与运算的两个迭代器必须指向的是同一 |
| 个容器中的元素或者尾元素的下一位置 |
- 两个迭代器的距离指的是右侧的迭代器向前移动多少位置就能追上左侧的迭代器,其类型是名为
difference_type
的带符号整数。
数组
定义和初始化内置数组
- 数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的。也就是说,维度必须是一个常量表达式。
| unsigned cnt = 42; |
| constexpr unsigned sz = 42; |
| int arr[10]; |
| int *parr[sz]; |
| string bad[cnt]; |
| string strs[get_size()]; |
显式初始化数组元素
| const unsigned sz = 3; |
| int ial[sz] = {0, 1, 2}; |
| int a2[] = {0, 1, 2}; |
| int a3[5] = {0, 1, 2}; |
| string a4[3] = {"hi", "bye"}; |
| int a5[2] = {0, 1, 2}; |
字符数组的特殊性
- 用字符串字面值初始化数组时,记得结尾还有一个空字符。
| char a1[] = {'c', '+', '+'}; |
| char a2[] = {'c', '+', '+', '\0'}; |
| char a3[] = "C++"; |
| const char a4[6] = "Daniel"; |
复杂的数组声明
| int *ptrs[10]; |
| int &refs[10] = ; |
| int (*Parray)[10] = &arr; |
| int (&arrRef)[10] = arr; |
| int *(&arry)[10] = ptrs; |
访问数组元素
- 使用数组下标的时候,通常将其定义为
size_t
类型,它被设计得足够大以便能表示内存中任意对象的大小,在cstddef
头文件中
指针和数组
| string nums[] = {"one", "two", "three"}; |
| string *p = &nums[0]; |
| |
| |
| |
| |
| string *p2 = nums; |
- 在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
| int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| auto ia2(ia); |
| ia2 = 42; |
| |
| |
| |
| |
| |
- 当使用 decltype 关键字时,上述转换不会发生,decltype(ia) 返回的类型是由 10 个整数构成的数组。
| |
| decltype(ia) ia3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| ia3 = p; |
| ia3[4] = i; |
指针也是迭代器
- vector 和 string 的迭代器支持的运算,数组的指针全都支持。
如:
| int *e = &arr[10]; |
| for (int *b = arr; b != e; ++ b) cout << *b << endl; |
标准库函数 begin 和 end
C++引入两个名为 begin 和 end 的函数*,在iterator
头文件中,声明 std
| int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| int *beg = begin(ia); |
| int *last = end(ia); |
- 两个指针相减的结果的类型是一种名为
ptrdiff_t
的标准库类型,定义在 cstddef
头文件中的机器相关类型,是一种带符号类型
- 如果 p 是空指针,允许给 p 加上或减去一个值为 0 的整型常量表达式。两个空指针也允许彼此相减,结果当然是 0。
下标和指针
- 只要指针指向的是数组中的元素(或者数组中尾元素的下一位置),都可以执行下标运算
| int *p = &ia[2]; |
| int j = p[1]; |
| int k = p[-2]; |
C风格字符串
- 操作C风格字符串的函数定义在
cstring
头文件中
| strlen(p) 返回 p 的长度,空字符不计算在内 |
| strcmp(p1, p2) 比较 p1 和 p2 的相等性。如果 p1 == p2, 返回 0,如果 p1 > p2, |
| 返回一个正值,如果 p1 < p2,返回一个负值 |
| strcat(p1, p2) 将 p2 附加到 p1 之后,返回 p1 |
| strcpy(p1, p2) 将 p2 拷贝给 p1,返回 p1 |
| char ca[] = {'c', '+', '+'}; |
| cout << strlen(ca) << endl; |
- 传入此类函数的指针必须指向以空字符作为结束的数组,无空字符可能沿着 ca 在内存中的位置不断向前寻找,直到遇到空字符才停下来。
与旧代码的接口
混用 string 对象和 C 风格字符串
- 不能用 string 对象直接初始化指向字符的指针。为了完成该功能,string 专门提供了一个名为 c_str 的成员函数
| char *str = s; |
| const char *str = s.c_str(); |
| |
如果执行完 c_str() 函数后程序想一直都能使用其返回的数组,最好将该数组重新拷贝一份
使用数组初始化 vector 对象
| int int_arr[] = {0, 1, 2, 3, 4, 5}; |
| |
| vector<int> ivec(begin(int_arr), end(int_arr)); |
用于初始化 vector 对象的值也可能仅是数组的一部分
| |
| vector<int> subVec(int_arr + 1, int_arr + 4); |
多维数组
严格来说没有多维数组,通常所说的多维数组其实是数组的数组
多维数组的初始化
| int ia[3][4] = { |
| {0, 1, 2, 3}, |
| {4, 5, 6, 7}, |
| {8, 9, 10, 11} |
| } |
| |
| int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; |
| |
| int ia[3][4] = {{ 0 }, { 4 }, { 8 }}; |
| |
| int ix[3][4] = {0, 3, 6, 9}; |
多维数组的下标引用
| |
| ia[2][3] = arr[0][0][0]; |
| int (&row)[4] = ia[1]; |
使用范围 for 语句处理多维数组
| size_t cnt = 0; |
| for (auto &row : ia) |
| for (auto &col : row) { |
| col = cnt; |
| ++ cnt; |
| } |
| |
| for (const auto &row : ia) |
| for (auto col : row) |
| cout << col << endl; |
要使用范围 for 语句处理多维数组,除了最内层的循坏外,其他所有循环的控制变量都应该是引用类型。
指针和多维数组
| int ia[3][4]; |
| int (*p)[4] = ia; |
| p = &ia[2]; |
在上述声明中,圆括号必不可少
其他遍历方法
| for (auto p = ia; p != ia + 3; ++ p) { |
| for (auto q = *p; q != *p + 4; ++ q) |
| cout << *q << ' '; |
| cout << endl; |
| } |
| |
| for (auto p = begin(ia); p != end(ia); ++ p) { |
| for (auto q = begin(*p); q != end(*p); ++ q) |
| cout << *q << ' '; |
| cout << endl; |
| } |
类型别名简化多维数组的指针
| using int_array = int[4]; |
| typedef int int_array[4]; |
| |
| for (int_array *p = ia; p != ia + 3; ++ p) { |
| for (int *q = *p; q != *p + 4; ++ q) |
| cout << *q << ' '; |
| cout << endl; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用