C++复习总结,仅供笔者复习使用,参考教材:
- 《零基础C++——从入门到精通》
- 《C++ Primer Plus》
本文主要内容为:C++ 基本语法、输入输出、流程控制、字符串和数组。
C++ 指针、函数和STL容器部分 见 C++复习总结2;
C++ 结构体、面向对象和泛型编程部分 见 C++复习总结3.
目录
一. 基本语法
1. 基本数据类型
以下为 gnu++14 标准下的数据类型:
类型 | 说明 | 字节数 | 表示范围 | 占位符 |
---|---|---|---|---|
bool | 布尔型 | 1 | 0 / 1 | %d |
char | 字符型 | 1 | -27 ~ 27-1 | %c: 字符 %d: ASCII码 |
wchar_t | 宽字符型 | 2 | 0 ~ 216-1 | |
short | 短整型 | 2 | -215 ~ 215-1 | |
int | 整型 | 4 | -231 ~ 231-1 | %d |
unsigned int | 无符号整型 | 4 | 0 ~ 232-1 | |
long long | 长整型 | 8 | -263 ~ 263-1 | %Ld |
unsigned long long | 长整型 | 8 | 0 ~ 264-1 | |
float | 单精度浮点型(10-6) | 4 | -2128 ~ 2128 | %.f |
double | 双精度浮点型(10-15) | 8 | -21024 ~ 21024 | %.lf |
long double | 扩展精度浮点型 | 16 | %.Lf | |
string | 字符串 | 8 | ———— | “%s”, s.c_str() |
可以用 typeid(var).name()
返回数据类型,用 sizeof(type)
返回类型存储空间大小(字节数)。
2. 变量与常量
- char 元素可以用整数定义和输出:
char c = 99; cout<<int(c)<<endl
; - int 元素可以用二进制数
int bin=0b1001
、八进制数int oct=0213
和十六进制数int hex=0x4b
定义; - int 元素相除不会得到浮点数,需要提前作类型转换;
- float 元素可以用科学计数法定义:
float f=31415926e-7f
; - 变量名必须用字母或下划线开头,不能使用数字;
- const 常量不能修改:
const int a=5
; - typedef 可以定义变量的别名:
typedef int age; age myAge=20
.
3. 操作符
- 算术操作符:
+、-、*、/、%
; - 关系操作符:
==、!=、>、<、>=、<=
; - 逻辑操作符:
&&、||、!
; - 位操作符:
&、|、^、~、<<、>>
; - 三目运算符:
condition ? expression1 : expression2
4. 转义符
转义符 | 说明 |
---|---|
\" | 字符串内部打印 " |
\’ | 字符串内部打印 ’ |
\n | 换行符 |
\t | 制表符(占8格整齐输出) |
5. 一些数据处理
- 生成 [a, a+b] 的随机整数:
#include <iostream>
#include <algorithm>
int main{
int a=3;
int b=5;
int ran=rand()%(b+1)+a;
return 0;
}
- 求 a 和 b 的最大公因数:
#include <iostream>
#include <algorithm>
int main{
int a=3;
int b=5;
int c=__gcd(a,b);
return 0;
}
- 取绝对值:
#include <iostream>
#include <math.h>
int main{
int n=3;
int f=5.2;
int abs_n=abs(n);
float abs_f=fabs(f)
return 0;
}
- 取整:
ceil()
函数向上取整,floor()
函数向下取整:
#include <iostream>
#include <cmath>
int main() {
double num = 3.14;
double result = ceil(num); // 向上取整
double result = floor(num); // 向下取整
return 0;
}
- 浮点数四舍五入到指定位数:利用
round()
函数,其原理为:(int)(x+0.5)
;
#include <iostream>
#include <math.h>
using namespace std;
int main(){
double f0=3.1415926;
double f1=round(f0); //3
double f2=round(f0*10)/10; //3.1
double f3=round(f0*10000)/10000;//3.146
return 0;
}
- 输出浮点数四舍五入到指定位数:
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
int n=5;
float f=3.1415926;
printf("%.0f\n",f); //3
printf("%.3f\n",f); //3.142
printf("%.*f\n",n,f); //3.14159
cout<<fixed<<setprecision(n)<<f<<endl; //需要调 iomanip 包
return 0;
}
- 输出整数指定位数(当前位数小于指定位数时用前导零补齐):
#include <iostream>
using namespace std;
int main(){
int n=10;
int num=1234567;
printf("%03d\n",num); //1234567
printf("%08d\n",num); //01234567
printf("%0*d\n",n,num); //0001234567
return 0;
}
- 计算运行时间:使用
clock_t
变量获取程序运行前后的时间clock()
并作差得到程序的运行时间 (s);
#include<iostream>
#include<algorithm>
#include<time.h>
using namespace std;
int main() {
clock_t start,end;
start=clock();
int a[100000];
for(int i=0;i<100000;i++) a[i]=rand()%200;
sort(a,a+100000);
end=clock();
cout<<double(end-start)/CLOCKS_PER_SEC<<endl;
return 0;
}
二. 流程控制语句
if...else if...else
语句;switch
语句:别忘了 break 和 default、多个 case 情况可以合并;while
语句;do...while
语句;for
语句;break
语句;continue
语句;goto
语句;
三. 输入输出
1. cin
cin
接收输入遇到空格或回车键就停止,可用来接收 int、char、不含空格的 string 或 char 数组:
#include <iostream>
using namespace std;
int main(){
char a[20];
cin>>a; //hello world
cout<<a; //hello
return 0;
}
2. scanf
scanf
是除 cin 外的另一种输入方法,不仅可以节约时间,还可以 在题目要求的格式下 接收输入:
#include <iostream>
using namespace std;
int main(){
int n;
char c;
scanf("The number is %d, the char is %c.", &n, &c);
char s[20];
scanf("%s",s);
return 0;
}
注意:
- scanf 语句通过
%+变量类型
将接收到的 字符 转换成指定的变量类型并赋值给 变量的地址。因此,在接收 int、char、bool 型变量时需要加取址符&
,接收 char 型数组时则不用取址; - scanf 语句接收 char 数组时也不能包含空格;
- 缓冲区太长时需要释放:
fflush(stdin)
; - 可以用
while(scanf("%d%c", &n, &c) != EOF)
来接收数量未知的输入元素,并用 CtrlZ+Enter 结束输入(若输入无格式要求,也可以直接采用while(cin >> a)
);
3. getline
getline(cin,s)
主要用于接收 string 类型元素的输入,可以接收空格,遇到回车键结束。一般与 getchar()
配合使用以吞掉换行符:
#include <iostream>
#include <string>
using namespace std;
int main(){
int N;
cin>>N;
getchar(); //吸收回车
for(int i=0;i<N;i++){
string s; //若无getchar,则第一个getline的是N
getline(cin,s); //s中包含空格,不能直接cin
}
return 0;
}
4. gets/puts
gets(a)
/ puts(a)
一般用于对 字符数组 的整体输入输出。
四. 字符、字符串与数组
1. 字符
char 类型除了前面提到的一些基础用法,还有一些自己的方法:
isalnum(c)
:判断字符是否是字母或数字;toupper(c)
/tolower(c)
:将字符串换成大/小写;isupper(c)
/islower(c)
:判断字符是否是大/小写;isdigit(c)
/isalpha(c)
/iscntrl(c)
/ispunct(c)
/isspace(c)
:判断字符是否是数字/字母/控制字符/标点空白符;getchar()
:接收单个字符输入;putchar()
:输出字符;
2. 字符串
C++ 中提供了 string 库,有一些自带的方法:
s.empty()
:判断字符串是否为空并返回结果;s.length()
:返回字符串长度;s+=s_new
:字符串拼接;s.push_back(c)
:尾部添加一个新字符(不同于上面的拼接字符串);s.pop_back()
:尾部移除一个字符;s.insert(i, s_new)
:在 i 处插入字符或字符串;s.replace(start, num, s_new)
:从 start 开始后面的 num 个元素替换成 s_new;s.substr(start, len)
:从 start 处截取长度为 len 的子字符串并返回;s.find(s2, start)
:返回从 start 处向后查找 s 中第一次出现 s2 的位置,没有则返回 -1;stoi(s)
/stod(s)
:字符串转 int 型 / double 型并返回【C++11】,遇到非数字就停止;string(1,c)
:将 char 型转换成字符串并返回;to_string(i)
/to_string(f)
/to_string(d)
:将 int 型 / float 型 / double 型转换成字符串并返回【C++11】;
string 还可以通过 stringstream
和其他数据类型相互转换:
//string <-> int
#include <iostream>
#include <sstream>
using namespace std;
int main(){
stringstream ss;
string s1="10086";
int n1;
ss<<s1;
ss>>n1;
ss.clear(); //连续使用需要清除流
int n2=12345;
string s2;
ss<<n2;
ss>>s2;
cout<<n1<<endl<<s2<<endl;
return 0;
}
//string <-> char
#include <iostream>
#include <sstream>
using namespace std;
int main(){
stringstream ss;
char c1='a';
string s1;
ss<<c1;
ss>>s1;
ss.clear();
string s2=string(1,c1); //char->string可以直接转换
char c2;
string s3="f";
ss<<s3;
ss>>c2;
cout<<s1<<" "<<s2<<endl<<c2<<endl;
return 0;
}
3. 静态数组
静态数组在 C 中就有了,是一种完全静态的数据结构,在初始化的时候就需要指定大小,并且不能修改数组长度。它存放在 栈 中,内存分配与释放完全由系统自动完成,效率最高。
静态数组创建时可以只对部分赋值,则其余都会保留默认值:
#include <iostream>
using namespace std;
int main(){
int arr1[5]; //默认值未知
int arr2[5]={}; //默认值为0
int arr3[5]={1}; //0号元素为1,其余为默认值0
int arr4[5]={1,3,2}; //0~2号元素被赋值,其余为默认值0
int arr5[]={0,1,2,3,4}; //根据数组元素数量自动补齐大小
return 0;
}
4. 动态数组
动态数组是程序员通过 new
关键字创建的,存放在 堆 中,需要程序员在使用完通过 delete
关键字释放内存,否则会出现 内存泄漏。
#include <iostream>
using namespace std;
int main(){
int n=5;
int *arr=new int[n];
int *tmp=arr;
for(int i=0;i<n;i++){
*tmp=i;
cout<<*tmp++<<" ";
}
delete [] arr;
delete tmp;
return 0;
}
5. vector
C++ 标准库引入了动态的数据结构 ---- vector,存放在 堆 中,由STL库负责内存分配与释放,使用起来相当方便。同时并提供了一些方法:
- 初始化:vector 初始化可以通过 指定初始值、其他vector复制 或 数组复制:
#include <iostream>
#include <vector>
using namespace std;
int main(){
int arr[5]={1,5,3,6,7};
vector<int> v1(10); //大小为10,初值为0
vector<int> v2(10,1); //大小为10,初值为1
vector<int> v3(arr,arr+4); //用arr[0]~arr[3]初始化v3
vector<int> v4(v2); //用v2初始化
vector<int> v5(v2.begin(),v2.begin()+4); //用v2部分初始化
return 0;
}
v.assign(b.begin(), b.begin()+3)
/v.assign(n,0)
:对 vector 重新赋值;v.erase(v.begin()+1, v.begin()+3)
:删除 vector 部分元素;v.resize(10,2)
:调整 vector 大小并指定默认值;v.front()
/v.back()
:返回 vector 首/尾元素;v.clear()
:清空数组;v.empty()
:返回数组是否为空;v.push_back(a)
/v.pop_back()
:末尾添加/弹出元素;v.insert(v.begin()+2, 3, 5)
:在 vector 中插入元素;merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v.begin())
:将 v1 和 v2 合并成到 v;find(v.begin(), v.end(), 3)
:在 vector 中查找元素;
resize()
函数常用来创建二维数组:
vector<vector<bool> > dp;
vector<bool> tmp(n);
dp.resize(m,tmp);
但嵌套的二维数组 vector<vector<int> >
必须保证每行元素个数相同,否则会被中断!如果想要每行元素随意的二维数组,可以采用元素类型为 vector 的静态数组:
vector<int> node[10001];
6. 一些通用函数
sort()
:对数组排序,支持自定义判断方法:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool cmp(int a,int b){ //自定义排序方法
return a>b;
}
int main(){
int arr[5]={1,5,3,6,7};
vector<int> v(arr,arr+5);
sort(arr,arr+5);
sort(v.begin(),v.end(),cmp);
for(int i=0;i<5;i++) cout<<"arr["<<i<<"]:"<<arr[i]<<endl;
for(int i=0;i<v.size();i++) cout<<"v["<<i<<"]:"<<v[i]<<endl;
return 0;
}
reverse()
:对 vector 或 字符串 逆置:
reverse(str.begin(),str.end());
reverse(v.begin(),v.end());
lower_bound()
/upper_bound()
:在 有序 数组中查找第一次 / 最后一次出现的大于等于 / 大于 / 小于等于 / 小于 a 的地址,解引用后即为相应的值:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* lower_bound/upper_bound 函数返回地址,解引用后得到值 */
int arr[10]={1,1,3,5,5,8,8,8,9,10}; //非降序数组
//第一次出现大于等于5的位置与值
cout<<lower_bound(arr,arr+10,5)-arr<<" ";
cout<<*lower_bound(arr,arr+10,5)<<endl; //3 5
//第一次出现大于5的位置与值
cout<<upper_bound(arr,arr+10,5)-arr<<" ";
cout<<*upper_bound(arr,arr+10,5)<<endl; //5 8
//最后一次出现小于5的位置与值
cout<<prev(lower_bound(arr,arr+10,5))-arr<<" ";
cout<<*prev(lower_bound(arr,arr+10,5))<<endl; //2 3
//最后一次出现小于等于5的位置与值
cout<<prev(upper_bound(arr,arr+10,5))-arr<<" ";
cout<<*prev(upper_bound(arr,arr+10,5))<<endl; //4 5
return 0;
}
其中 std::prev(it)
表示将迭代器退回一个位置,从而变换得到小于(等于)的位置。需要注意的是,在使用 std::prev
之前,要 确保迭代器不指向数组开头,以避免越界。