C++

C++

数据范围

int $ -2.14\times10^9 \sim 2.14\times10^9$

unsigned int $0\sim4.29 \times10^ 9$

long long $-9.22\times10^{18}\sim9.22 \times10^ {18}$

unsigned long long $0\sim1.84 \times10^ {19}$

float $-3.40\times10^{38}\sim3.40 \times10^ {38}$ 6~7

double $-1.79\times10^{308}\sim1.79 \times10^ {308}$ 15~16

long double $-1.2\times10^{4932}\sim1.2\times10^{4932}$ 18-19

易错点

$memset$ 只管后面的两个字符,然后前面的直接就复制过去, 所以 $memset( a,0x3f,sizeof(a) )$ 效果等同于 $memset( a,0x3f3f3f3f,sizeof(a) )$

$strlen()$ 的时间复杂度为 $\mathcal{O}(n)$

$s.size()$ 的返回值为 $unsigned long$

动态数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int *a = new int[50];
delete [] a;

int (*a)[50] = new int[100][50];

int **p= new int*[size];//定义指针数组
for(int i=0;i<size;i++){
p[i]=new int[Column];
}
for(int i=0;i<size;i++){
delete [] p[i];
}

char *p = (char *)malloc(100);
free(p);

IO

scanf

1
2
3
4
%f float
%lf double
%Lf long double
sscanf("3.42","%lf",&b); //将字符串转换为数值double

printf

1
2
3
4
5
6
7
- 左对齐
0 右对齐时,用0填充左边未使用的列
+ 当一个数为正数时,前面加上一个+号
' ' 当一个数为正数时,前面加上一个空格
printf("a = %08.3Lf",a); //右对齐,开头补零,字符宽度8位,精度3位,以long double型输出。
printf("%*d",width,num);
sprintf(buf,"%.2f",a); //将double型数值转换为字符串

整行读入

1
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
//scanf()读入char[]
char str[1024];
scanf("%[^\n]",&str);
getchar();

//getchar()读入char[]
char str[1024];
int i=0;
while((str[i]=getchar())!='\n')
i++;
getchar();

//gets()读入char[]
char str[1024];
gets(str);

//getline()
string str;
getline(cin,str);//读入string

char str2[1024];
cin.getline(str2,1024);//读入char数组

//get()读入char[]
char str3[1024];
cin.get(str3,1024);//读入char数组
cin.get(str,1024).get();

文件输入输出

1
2
3
4
5
6
7
8
freopen("/Users/perpeternal/Downloads/test.in", "r", stdin);	
freopen("/Users/perpeternal/Downloads/test.out", "w", stdout);

FILE *in = fopen("/Users/perpeternal/Downloads/test.in","r");
FILE *out = fopen("/Users/perpeternal/Downloads/test.out", "w");
fscanf(in,"%d",&n);
fprintf(out,"%d",n);
fclose(in);fclose(out);

可变参数

1
2
3
4
5
6
7
8
9
10
11
12
void out(int count,...){
va_list ap; //声明一个va_list变量
va_start(ap, count); //第二个参数表示形参的个数
for (int i = 0; i < count; i++) {printf("%d ",va_arg(ap, int));}
va_end(ap); //用于清理
}
out(4,1,2,3,4);

void out(initializer_list<int> list) {
for (auto ptr = list.begin(); ptr != list.end(); ptr++) printf("%d ",*ptr);
}
out({1,2,3,4});

手动优化

手动加栈

1
#pragma comment(linker, “/STACK:1024000000,1024000000”)

优化

-O0 表示无优化状态

-O1 表示对代码进行了优化

-O2 表示减小目标文件大小

-O3 表示减小代码段及栈空间的大小

全局:

1
#pragma GCC optimize (2)

部分:

1
2
3
4
#pragma GCC push_options 
#pragma GCC optimize (“O0”)
...
#pragma GCC pop_options

随机数

1
2
3
4
//这是两个预定义类(类型),定义的变量可以用重载好的 () 运算符获取随机数
mt19937 gen(time(0)); //生成 [0, 2^32-1]
mt19937_64 gen(time(0)); //生成 [0, 2^64-1]
gen(); //生成随机数

assert

1
assert(0); //终止程序,报re

inf&nan

1
2
3
4
int isfinite(x); 判断x是否有限,是返回1,其它返回0
int isnormal(x); 判断x是否为一个数(非inf或nan),是返回1,其它返回0
int isnan(x); 当x时nan返回1,其它返回0
int isinf(x); 当x是正无穷是返回1,当x是负无穷时返回-1,其它返回0。有些编译器不区分。

bitset

1
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
bitset<4> bitset1;  //无参构造,长度为4,默认每一位为0

bitset<8> bitset2(12);  //长度为8,二进制保存,前面用0补充
bitset<2> bitset2(12);  //长度为3,二进制保存,取12二进制的后两位

string s = "100101";
bitset<10> bitset3(s);  //长度为10,前面用0补充

char s2[] = "10101";
bitset<13> bitset4(s2);  //长度为13,前面用0补充
bitset<2> bitset5(s2) //取s2前两位

//位运算
bitset<4> foo (string("1001"));
bitset<4> bar (string("0011"));

cout << (foo^=bar) << endl; // 1010 (foo对bar按位异或后赋值给foo)
cout << (foo&=bar) << endl; // 0010 (按位与后赋值给foo)
cout << (foo|=bar) << endl; // 0011 (按位或后赋值给foo)

cout << (foo<<=2) << endl; // 1100 (左移2位,低位补0,有自身赋值)
cout << (foo>>=1) << endl; // 0110 (右移1位,高位补0,有自身赋值)

cout << (~bar) << endl; // 1100 (按位取反)
cout << (bar<<1) << endl; // 0110 (左移,不赋值)
cout << (bar>>1) << endl; // 0001 (右移,不赋值)

cout << (foo==bar) << endl; // false (0110==0011为false)
cout << (foo!=bar) << endl; // true (0110!=0011为true)

cout << (foo&bar) << endl; // 0010 (按位与,不赋值)
cout << (foo|bar) << endl; // 0111 (按位或,不赋值)
cout << (foo^bar) << endl; // 0101 (按位异或,不赋值)

bitset<8> foo ("10011011");
cout << foo.count() << endl;  //5  (count函数用来求bitset中1的位数,foo中共有5个1
cout << foo.size() << endl;   //8  (size函数用来求bitset的大小,一共有8位

cout << foo.test(0) << endl;  //true  (test函数用来查下标处的元素是0还是1,并返回false或true,此处foo[0]为1,返回true
cout << foo.test(2) << endl;  //false  (同理,foo[2]为0,返回false

cout << foo.any() << endl;  //true  (any函数检查bitset中是否有1
cout << foo.none() << endl;  //false  (none函数检查bitset中是否没有1
cout << foo.all() << endl;  //false  (all函数检查bitset中是全部为1
bitset<8> foo ("10011011");

cout << foo.flip(2) << endl;  //10011111  (flip函数传参数时,用于将参数位取反,本行代码将foo下标2处"反转",即0变1,1变0
cout << foo.flip() << endl;   //01100000  (flip函数不指定参数时,将bitset每一位全部取反

cout << foo.set() << endl;    //11111111  (set函数不指定参数时,将bitset的每一位全部置为1
cout << foo.set(3,0) << endl;  //11110111  (set函数指定两位参数时,将第一参数位的元素置为第二参数的值,本行对foo的操作相当于foo[3]=0
cout << foo.set(3) << endl;   //11111111  (set函数只有一个参数时,将参数下标处置为1

cout << foo.reset(4) << endl;  //11101111  (reset函数传一个参数时将参数下标处置为0
cout << foo.reset() << endl;   //00000000  (reset函数不传参数时将bitset的每一位全部置为0
bitset<8> foo ("10011011");

string s = foo.to_string();  //将bitset转换成string类型
unsigned long a = foo.to_ulong();  //将bitset转换成unsigned long类型
unsigned long long b = foo.to_ullong();  //将bitset转换成unsigned long long类型

cout << s << endl;  //10011011
cout << a << endl;  //155
cout << b << endl;  //155

priority_queue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//在结构体外重载结构体小于运算符
struct Time{
int start, end;
};
bool operator <(const Time& a,const Time& b){
return a.start > b.start;
}//只能重载小于,这里以大于重载小于是因为默认情况下,优先队列是以大的作为队首,这样一反,就可以再默认情况下使得小的作为队首

//在结构体中重载小于运算符
struct Time{
int start, end;
bool operator < (const Time& t)const{
return start > t.start;
}
};

priority_queue<Time> pq;

vector

1
2
3
4
5
6
7
8
9
vector<int>v1;
vector<int>v1(v2);
vector<int>v1=v2;
vector<int> v1 = {1,2,3.0,4,5,6,7};
vector<int> v3(v1.begin()+2,v2.end()-1);
vector<int> v4(n);//初始化vector大小为n
vector<int> v5(n,x);//初始化vector为n个x

v.resize(n,x)//重置vector为n个x

set & map

set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct node{  
int x,y;
bool operator < (const node& t)const{
return x > t.x;
}
};
set<node> SET;

struct cmp{
bool operator()(const int &k1,const int &k2)const{
return k1>k2;
}
};
set<int,cmp>s;

map

1
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
29
30
31
32
33
34
typedef struct UrlKey
{
uint64_t dwBussID;
uint64_t dwVersion;
uint64_t dwHashUrl;
}UrlKey;

//自定义map的value
typedef struct UrlValue
{
string strUrl;
}UrlValue;
struct cmp_key
{
bool operator()(const UrlKey &k1, const UrlKey &k2)const
{
if(k1.dwBussID != k2.dwBussID)
{
return k1.dwBussID < k2.dwBussID;
}

if(k1.dwVersion != k2.dwVersion)
{
return k1.dwVersion < k2.dwVersion;
}
if(k1.dwHashUrl != k2.dwHashUrl)
{
return k1.dwHashUrl < k2.dwHashUrl;
}
         return false;
}
};

map<UrlKey, UrlValue, cmp_key> UrlMap;

unordered_set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct node{
string s;
int step;
node(string _s):s(_s),step(0){}
bool operator == (const node y)const{
return s==y.s;
}
};
struct Hash{
size_t operator () (const node y)const{
return hash<string>()(y.s);
}
};
unordered_set<node,Hash>us;

multiset

1
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <set>
using namespace std;

int main()
{
/*type of the collection:
*-duplicates allowed
*-elements are integral values
*-descending order
*/
typedef multiset<int,greater<int> > IntSet;

IntSet coll1, // empty multiset container

//insert elements in random order
coll1.insert(4);
coll1.insert(3);
coll1.insert(5);
coll1.insert(l);
coll1.insert(6);
coll1.insert(2);
coll1.insert(5);

//iterate over all elements and print them
IntSet::iterator pos;
for (pos = coll1.begin(); pos != coll1.end(); ++pos) {
cout << *pos << ' ';
}
cout << endl;

//insert 4 again and process return value
IntSet::iterator ipos = coll1.insert(4);
cout << "4 inserted as element "
<< distance (coll1.begin(),ipos) + 1
<< endl;

//assign elements to another multiset with ascending order
multiset<int> coll2(coll1.begin(),coll1.end());

//print all elements of the copy
copy (coll2.begin(), coll2.end(),
ostream_iterator<int>(cout," "));
cout << endl;

//remove all elements up to element with value 3
coll2.erase (coll2.begin(), coll2.find(3));

//remove all elements with value 5
int num;
num = coll2.erase (5);
cout << num << " element(s) removed" << endl;

//print all elements
copy (coll2.begin(), coll2.end(),
ostream_iterator<int>(cout," "));
cout << endl;
}

string

1
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
string s(str) //拷贝构造函数 生成str的复制品
string s(str,stridx) //将字符串str内“始于位置stridx”的部分当作字符串的初值
string s(str,stridx,strlen) //将字符串str内“始于stridx且长度顶多strlen”的部分作为字符串的初值
string s(cstr) //将C字符串作为s的初值
string s(chars,chars_len) //将chars字符串前chars_len个字符作为字符串s的初值。

s.assign(str); //不说
s.assign(str,1,3);//如果str是”iamangel” 就是把”ama”赋给字符串
s.assign(str,2,string::npos);//把字符串str从索引值2开始到结尾赋给s
s.assign(“gaint”); //不说
s.assign(“nico”,5);//把’n’ ‘I’ ‘c’ ‘o’ ‘\0’赋给字符串
s.assign(5,’x’);//把五个x赋给字符串

s.append(str);
s.append(str,1,3);//不解释了 同前面的函数参数assign的解释
s.append(str,2,string::npos)//不解释了
s.append(“my name is jiayp”);
s.append(“nico”,5);
s.append(5,’x’);
s.push_back(‘a’);//这个函数只能增加单个字符 对STL熟悉的理解起来很简单

s.insert(0,”my name”);
s.insert(1,str);

s.replace(1,2,”nternationalizatio”);//从索引1开始的2个替换成后面的C_string

s.erase(13);//从索引13开始往后全删除
s.erase(7,5);//从索引7开始往后删5个

s.substr();//返回s的全部内容
s.substr(11);//从索引11往后的子串
s.substr(5,6);//从索引5开始6个字符

返回符合搜索条件的字符区间内的第一个字符的索引,没找到目标就返回npos
第一个参数是被搜寻的对象。第二个参数(可有可无)指出string内的搜寻起点索引,第三个参数(可有可无)指出搜寻的字符个数。
find()
rfind() //从后向前
find_first_of()
find_last_of()
find_first_not_of()返回在字符串中首次出现的不匹配str中的任何一个字符的首字符索引, 从index开始搜索, 如果全部匹配则返回string::npos。
find_last_not_of()

s.c_str() 返回 char*

strcmp(const char *s1,const char * s2)//若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。

编译过程

compile

test.cpp - 预处理(Pre-processing) - test.i - 编译(Compiling) - test.s - 汇编(Assembling) - test.o - 链接(Linking) - test

Pre-processing

-E 选项使用g++/gcc将源代码预处理后不执行其他动作。
下面的命令将test.cpp预处理,并在标准输出中显示:

1
g++ -E test.cpp

后面加上 -o 选项表示将源代码预处理后输出在指定文件中,比如test.i:

1
g++ -E test.cpp -o test.i

Compiling

-S 选项使用g++/gcc将预处理后的文件编译,翻译成汇编代码。只编译不汇编
下面的命令将会编译test.i文件,并自动在当前文件夹生成test.s文件

1
g++ -S test.i

若要指定其他输出名,则需 -o 指定,比如生成名为xxx.s的汇编代码文件

1
g++ -S test.i -o xxx.s

Assembling

-c 选项将编译生成的test.s文件生成二进制目标代码
下面的命令将在当前文件夹自动生成test.o的二进制目标代码文件

1
g++ -c test.s

如果要指定输出文件名,则需 -o 指定,比如生成xxx.o的二进制目标代码文件

1
g++ -c test.s -o xxx.o

Linking

链接阶段是将相关的目标文件链接起来,形成一个整体,生成可执行文件
无选项链接
下面的命令会把二进制目标文件test.o所需的相关文件链接成一个整体,并在当前文件夹自动生成一个名为a.out的可执行文件

1
g++ test.o

如果要执行这个可执行文件,需要输入命令

1
./a.out

当然也可以指定生成的可执行文件的文件名

1
g++ test.o -o test.exe

单个源文件直接生成可执行文件

当然g++/gcc也可以直接把源代码直接生成可执行文件
下面的命令将test.cpp直接在当前文件夹生成a.out可执行文件,若要指定文件名,可使用 -o 选项

1
2
g++ test.cpp
g++ test.cpp -o test.exe

多个源文件直接生成可执行文件

也可以将多个源代码编译链接成一个可执行文件
下面的命令将test.cpp直接在当前文件夹生成a.out可执行文件,若要指定文件名,可使用 -o 选项

1
2
g++ test1.cpp test2.cpp 
g++ test1.cpp test2.cpp -o test.exe

使用C++11标准编译

如果要使用C++11版本特性,则需要使用 -std=c++11 选项

1
g++ -std=c++11 test.cpp -o test.exe