CPP语法
C++
实用知识
输入输出
1 |
|
保留几位小数
1 | double pi = 3.1415926; |
大小写互转
1 |
|
库<cctype>
1 |
|
set集合
set
是一个有序的关联容器,其元素默认按照升序排列。你不能直接对set
使用sort
函数进行排序,因为sort
函数适用于顺序容器(如vector
),并且需要迭代器作为参数。- 如果你希望按照降序输出
set
的元素,可以使用std::greater<int>
作为第三个参数调用std::set
的构造函数来创建一个降序的set
。 - 使用 greater
构造降序排序的 set。 set<int, greater<int>> sortedSet(mySet.begin(), mySet.end());
1 |
|
sort()
- sort 函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变。如果某些场景需要保持相同元素间的相对顺序,可使用
stable_sort
函数 - 将
[first, last)
区间内元素升序排列。【注意区间为左闭右开】 - sort函数仅支持可随机访问的容器,如数组, string、vector、deque等。
- 实现降序排列,需传入第三个参数–比较函数,
greater<type>()
,这里的元素为int
类型,即函数为greater<int>()
; 如果是其他基本数据类型如float
、double
、long
等也是同理。 sort()
并非只是普通的快速排序,除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。
1 | // 方式一、使用数组 |
字符串转化为整形
1 |
|
Vector
初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 一维
int a[3] = { 1,2,3 };
vector<int> v = {1,2,3,4};
vector<int> v2(a, a+2); // {1, 2}
vector<int> v3(v.begin()+1, v.end() - 1); // {2, 3}
// 二维
vector<vector<int>> v(3, vector<int>(4,0));
vector<int> v0 = { 1,2,3,4 };
vector<vector<int>> v1(4, v0);
vector<vector<int>> v(v1.begin()+1, v1.end()-1); //此时的v是 {{1,2,3,4},{1,2,3,4}}
// 其他初始化方式
vector<int> v1(10); // 创建一个大小为 10 的 vector,所有元素初始化为默认值 (0)
vector<int> v2(10, 5); // 创建一个大小为 10 的 vector,所有元素初始化为 5
vector<int> v; // 创建一个空的 vector
int n = 10; // 假设 n 是你想要分配的空间大小
v.resize(n); // 分配 n 个空间,所有元素初始化为默认值 (0)vector.emplace_back()
优于vector.push_back()
vector.back()
获取最后一个元素。
C++ 结构体
创建结构步骤
定义struct结构
1
2
3
4
5
6
7
8
9
10
11
12/*关键字:struct*/
struct Point{
int x;
int y;
Point* father;
// 构造函数,初始化节点的数据成员
// 选择性地传递一个指向父节点的指针 father。
// 如果你没有显式地提供 father 参数,在构造对象时它将自动被初始化为 nullptr,这是 C++ 中处理默认参数的一种方式。
Node(int x_, int y_, Point* father_ = nullptr)
: x(x_), y(y_), father(father_) {}
};定义后创建变量,其中struct在c++中可以省略关键字struct,不会报错
1
2Point p1; // C++中,struct可省略
struct Point p2; // c语言中初始化:使用由逗号分隔值列表,并将值用花括号括起来;
1
2
3
4
5
6
7
8
9
10
11Point p1;
p1 = {1, 2, 10};
Point p2 = {3, 4, 11};
Point p3 {5, 6, 12}; // 或者省略 =
Point p4 {}; //大括号内不包含任何内容,各个成员都将设置为0,字符串string类型设置为空字符串 ""
// 也能这样
vector<Point> points;
for(int i = 0; i < 3; i++)
points.push_back({1, 1, 10});使用成员运算符
.
来访问各个成员变量同时给变量进行赋值;
结构体声明的位置
- 外部声明
- 将结构体的声明放在main()的前面,外部声明可以被后面任何函数使用
- 内部声明
- 将结构体的声明放在main()函数中,紧跟在开始括号的后面,内部声明只能被该声明所属的函数使用,通常应使用外部声明,便于所有函数都可以使用这种类型的结构;
其他属性
- 可以将结构体作为函数的参数传给函数,同时也可以将函数返回一个结构体;
- 同时可以使用赋值运算符
=
将结构体赋给另一个同类型的结构体(结构体中的每个成员都设置为另一个结构体中相应成员的值,称为成员赋值)
汇总
1 |
|
C++ 类
C++中struct和class的区别是什么
- C++需要兼容C语言,所以C++中struct可以当成结构体使用。
- C++中struct还可以用来定义类。和class定义类是一样的,
- struct定义的类默认访问权限是public,class定义的类默认访问权限是private。
定义
声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理
1 | //声明和定义全部放在类体中 |
类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名 ::
1 | //声明放在类的头文件person.h中 |
类的实例化
实例化
用类类型创建对象的过程,称为类的实例化
- 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间
Person p;
和Person p = Person();
都会调用无参构造函数- 前者直接声明并定义一个 Person 类的对象 person。根据情况,编译器会调用 Person 类的默认构造函数来初始化 person 对象。
- 后者使用了复制初始化的方式来创建对象 person。右侧的 Person() 是一个临时对象,通过调用 Person 类的默认构造函数来创建。然后,使用复制初始化的语法将这个临时对象复制到 person 对象中。
Person p(name, sex, age);
和Person p = Person(name, sex, age);
都会调用有参构造函数
this
指针
- C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
this
指针特性:this指针是形参,存在于栈桢中- this指针的类型:类类型* const,即成员函数中,不能给this指针赋值,不能修改this指针。
- 只能在“成员函数”的内部使用
- this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
不能显示写this相关的实参和形参,但是可以在类中显式使用
经典例子
1 | class A{ |
如上例子,我们发现是可以正常运行的。
有人可能会说,这是空指针解引用,运行时报错。
p虽然是空指针,但是Print函数地址不存在对象中,这就不是空指针的解引用。
再看看这个例子
1 | class A{ |
能通过编译,但是会在运行时报错。cout << this->_a << endl;
这句代码就变成了空指针的解引用操作了。_a
是存在于对象中的。
C++ 字符串string
初始化
string s1;
默认初始化,是一个空串""
。string s1(s2)
string s1 = s2
s1 是 s2 的副本。string s3("value")
string s3 = "value"
s3 是字面值 “value” 的副本string s4(n, 'c')
把 s4 初始化为 n 个 字符 c 组成的串。
比较大小
1 | // 尽管两者的前面对应的字符都一样,但是phrase长度长(多一个空格),所以phrase>str。 |
获取和处理string中的每个字符
使用下标运算符
[]
使用迭代器
1
2
3
4
5string s = "Hello world!";
for (auto it = s.begin(); it != s.end(); it++){ // std::string::iterator it;
cout << *it << ",";
}
cout << endl;基于范围的 for
1
2
3
4string str("some string");
for (auto c : str)
cout << c << ",";
cout << endl;
substr
成员函数
- std::string 类型的对象调用 substr 方法并不会修改其自身内容。相反,substr 方法会返回一个新的 std::string 对象,该对象包含了从原始字符串中指定位置开始的指定长度的子串。
1 | string s ("value"); |
append() 追加方法
在字符串的末尾添加字符串str
string& append (const string& str);
string& append (const char* s);
- 这种情况实际上就相当于
+=
在字符串的末尾添加字符串str的子串,子串以subpos索引开始,长度为sublen
string& append (const string& str, size_t subpos, size_t sublen);
1
2
3
4string s1 = "hello";
string s2 = "the world";
s1.append(s2,4,5); //把字符串从s2中从4开始的5个字符连接到当前字符串的结尾
// 运行结果为:s1 = "helloworld";若是添加的子串中只有索引开始的位置,没有长度,则表示字符串从第n个字符到末尾的字符连接到当前字符串末尾【注意和char* 类型的区别!】,如下:
1
2
3
4
5string s1 = "hello";
string s2 = "the world";
s1.append(s2, 3);
// 运行结果为:s1 ="hello world"
在字符串的末尾添加字符串s中的前n个字符。
string& append (const char* s, size_t n)
在string的后面添加C-string的一部分。把c类型字符串c的前n个字符连接到当前字符串结尾,如下:
1
2
3
4string s = "hello";
const char*c = "the world";
s.append(c,3);
// 运行结果为:s = "hellothe";
在字符串的末尾添加n个字符c;
string& append (size_t n, char c);
1
2
3string s1 = "hello";
s1.append(3, '!'); //在当前字符串结尾添加3个字符!
// 运行结果为 s1 = "hello!!!";
在字符串的末尾添加以迭代器first和last表示的字符序列。
string& append (InputIterator first, InputIterator last););
insert() 插入方法
iterator insert(iterator pos, CharT ch)
迭代器insert顺序容器通用的迭代器版本
1
2
3string s1("value");
s1.insert(s1.begin()++, 's'); //执行后,s1为"svalue"
s1.insert(s1.begin(), 's'); //执行后,s1为"vsalue"
basic_string& insert(size_type index, size_type count, CharT ch)
下标insert在下标index前插入count个字符ch
1
2
3string s1("value");
s1.insert(3, 2, 's'); //执行后,s1为"valssue"
s1.insert(5, 2, 's'); //执行后,s1为"valuess"
basic_string& insert( size_type index, const CharT* s );
basic_string& insert( size_type index, const basic_string& str );
在下标index前插入一个常量字符串或者string对象。
1
2
3
4
5
6string s1("value");
string s3 = "value";
const char* cp = "value";
s1.insert(0,s3); //执行完后,s1为"valuevalue"
s1.insert(0,cp); //执行完后,s1为"valuevalue"
erase() 删除方法
三种形式
basic_string & erase(size_type pos=0, size_type n=npos)
- 如果string对象s调用,它删除s从pos下标开始的n个字符,并返回删除后的s。当
pos > s.size()
时,报错
- 如果string对象s调用,它删除s从pos下标开始的n个字符,并返回删除后的s。当
iterator erase(const_iterator position)
- 如果string对象s调用,它删除s迭代器position位置的字符,并返回下一个字符的迭代器。
iterator erase(const_iterator position)
- 如果string对象s调用,它删除s迭代器[first,last)区间的字符,并返回last字符的迭代器。
1
2
3
4
5
6
7
8
9string s1("value");
string s2("value");
string s3("value");
string s4("value");
s1.erase(); //执行后,s1为空
s2.erase(0,2); //执行后,s2为"lue"
s3.erase(s3.begin()); //执行后,s3为"alue"
s4.erase(s4.begin(),++s4.begin());//执行后,s4为"alue"
replace() 替换方法
- replace可看作是erase和insert的结合体,它删除指定的字符,删除后再插入指定的字符。
- 和insert一样,可以通过下标或者是迭代器指定位置。
1 | string s("i very love China!"); |
搜索操作
函数形式
string搜索函数 | 描述 |
---|---|
s.find(args) | 在s中查找第一次出现args的下标 |
s.rfind(args) | 在s中查找最后一次出现args的下标 |
s.find_first_of(args) | 在s中查找第一个在args中出现的字符,返回其下标 |
s.find_first_not_of(args) | 在s中查找第一个不在args中出现的字符,返回其下标 |
s.find_last_of(args) | 在s中查找最后一个在args中出现的字符,返回其下标 |
s.find_last_not_of(args) | 在s中查找最后一个不在args中出现的字符,返回其下标 |
args参数格式
args参数格式 | 描述 |
---|---|
c,pos | 搜索单个字符。从s中位置pos开始查找字符c。pos可省略,默认值为0 |
s2,pos | 搜索字符串。从s中位置pos开始查找字符串string对象s2。pos可省略,默认值为0 |
cp,pos | 搜索字符串。从s中位置pos开始查找指针cp指向的以空字符结尾的C风格字符串。pos可省略,默认值为0 |
cp,pos,n | 从s中位置pos开始查找指针cp指向的数组的前n个字符。 |
- 注意:
std::string::npos
是string类中定义的一个std::size_t
类型变量,值为std::size_t
类型的最大值。
1 | std::string str("There are two needles in this haystack with needles."); |
compare操作
- 若 s = 指定的字符串,s.compare()返回 0
- 若 s > 指定的字符串,s.compare()返回正数
- 若 s < 指定的字符串,s.compare()返回负数
1 | string str1("green apple"); |
C++ pair
用法
简介
std::pair
主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。(不需要因此额外定义结构体)- C++标准程序库中凡是“必须返回两个值”的函数, 也都会利用pair对象。
- class pair可以将两个值视为一个单元。容器类别 map 和 multimap 就是使用 pairs 来管理其 键值 / 实值 (key/value) 的成对元素。
- pair被定义为struct不是class,所以可以直接使用pair的成员变量,直接存取pair中的个别值.。
- 两个pairs互相比较时, 第一个元素具有较高的优先级.。
定义
其标准库类型–pair类型定义在
#include <utility>
头文件中,定义如下:- 类模板:
template<class T1,class T2> struct pair
- 参数:T1是第一个值的数据类型,T2是第二个值的数据类型。
- 类模板:
需要注意的是,由于map内部实现涉及到pair,因此添加map头文件时会自动添加utility头文件,
所以,记不住的话,可以用map头文件来代替。
初始化
定义时初始化:
使用构造函数:只需要跟上一个小括号,里面填写两个想要初始化的元素即可。
1
pair<string, int> p1("pair",5);
直接初始化:
1
pair<string, int> p2 = {"test", 3};
通过赋值:
1
2
3
4
5
6pair<string, int> p;
p.first = "asdf";
p.second = 6;
// 临时变量的赋值
p = pair<string,int> ("zxcv",666);
使用自带的make_pair函数:
1
auto p2 = make_pair(“asdf”,6); // 不必费力写成 pair<string, int>(“asdf”,6)
常见用途
用来代替二元结构体及其构造函数,可以节省编码时间
作为 map 的键值对来进行插入,示例如下
1
2
3
4map<string,int> mp;
mp.insert(make_pair("wsad",6));
mp.insert(pair<string,int>("jkluio",10086));若是 pair 在容器中
1
2
3queue<pair<int,int>> q; // pair<id, steps>
// ......
q.emplace(id, steps);作为函数返回值
1
2
3pair<int, int> function(int id, int n){
return {id, n}; // 本质上还是一个结构体
}
C++ 查找方法
- 只能用于查找序列容器:用于在序列容器(如
std::vector
,std::list
,std::array
等)中线性查找指定元素。
std::find()
查找方法
1 |
|
std::find_if()
自定义查找条件
1 |
|
std::count()
统计元素个数
1 |
|
C++ 手搓 split()
方法
以字符进行分割:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17vector<string> Split(const string &s, const char &separator) {
vector<string> ans;
string tmp = "";
for (int i = 0; i < s.size(); i++) {
if (s[i] != separator) {
tmp += s[i];
}else {
if(tmp != ""){
ans.push_back(tmp);
tmp = "";
}
}
}
if(tmp != "")
ans.push_back(tmp);
return ans;
}以字符串进行分割:
1
2
3
4
5
6
7
8
9
10
11
12
13
14vector<string> Split(const string &s, const string &separator) {
vector<string> ans;
string token, str = s;
size_t pos = 0;
while((pos = str.find(separator)) != string::npos) {
token = str.substr(0, pos);
if(token != "")
ans.push_back(token);
str.erase(0, pos + separator.length());
}
if(str != "")
ans.push_back(str);
return ans;
}
advance() 方法的使用
- advance() 函数用于将迭代器前进(或者后退)指定长度的距离。
void advance (InputIterator& it, Distance n);
- 注意:
- advance() 函数本身不会检测 it 迭代器移动 n 个位置的可行性,如果 it 迭代器的移动位置超出了合理范围,it 迭代器的指向将无法保证,此时使用 *it 将会导致程序崩溃。
其成员函数
迭代器辅助函数 | 功能 |
---|---|
advance(it, n) | it 表示某个迭代器,n 为整数。该函数的功能是将 it 迭代器前进或后退 n 个位置。 |
distance(first, last) | first 和 last 都是迭代器,该函数的功能是计算 first 和 last 之间的距离。 |
begin(cont) | cont 表示某个容器,该函数可以返回一个指向 cont 容器中第一个元素的迭代器。 |
end(cont) | cont 表示某个容器,该函数可以返回一个指向 cont 容器中最后一个元素之后位置的迭代器。 |
prev(it) | it 为指定的迭代器,该函数默认可以返回一个指向上一个位置处的迭代器。注意,it 至少为双向迭代器。 |
next(it) | it 为指定的迭代器,该函数默认可以返回一个指向下一个位置处的迭代器。注意,it 最少为前向迭代器。 |
示例
1 |
|