C++笔记

  1. 输入输出
    1. 控制台输入输出
      1. cin>>

根据cin>>sth 中sth的变量类型读取数据,这里变量类型可以为int,float,char,char*,string等诸多类型。这一输入操作,在遇到结束符(Space、Tab、Enter)就结束,且不读取结束符,结束符留在缓存区。

      1. cin.get(字符数组名,接收长度,结束符)

其中结束符意味着遇到该符号结束字符串读取,默认为enter,读取的字符个数最多为(长度 - 1),因为最后一个为'\0'。要注意的是,cin.get(字符数组名,接收长度,结束符)操作遇到结束符停止读取,但并不会将结束符从缓冲区丢弃。可后接一个cin.get();吸收结束符.

      1. cin.getline(字符数组名,接收长度,结束符)

其用法与cin.get(字符数组名,接收长度,结束符)极为类似。cin.get()当输入的字符串超长时,不会引起cin函数的错误,后面若有cin操作,会继续执行,只是直接从缓冲区中取数据。但是cin.getline()当输入超长时,会引起cin函数的错误,后面的cin操作将不再执行。将结束符从缓冲区丢弃

      1. getline(输入流,str)

istream& getline (istream&  is, string& str, char delim);

istream& getline (istream&& is, string& str, char delim);

istream& getline (istream&  is, string& str);

istream& getline (istream&& is, string& str);

is :表示一个输入流,例如 cin。

str :string类型的引用,用来存储输入流中的流信息。

delim :char类型的变量,所设置的截断字符;默认为’\n’。结束符从缓冲区丢弃。

      1. printf()

在Turbo C中格式字符串的一般形式为: [标志][输出最小宽度][.精度][长度]类型 其中方括号[]中的项为可选项。

类型类型字符用以表示输出数据的类型,其格式符和意义下表所示:
表示输出类型的格式字符      格式字符意义
d                以十进制形式输出带符号整数(正数不输出符号)
o                以八进制形式输出无符号整数(不输出前缀O)
x                以十六进制形式输出无符号整数(不输出前缀OX)
u                以十进制形式输出无符号整数
f                以小数形式输出单、双精度实数
e                以指数形式输出单、双精度实数
g                以%f%e中较短的输出宽度输出单、双精度实数
c                输出单个字符
s                输出字符串

p   输出指针(地址)
标志
标志字符为-+#、空格四种,其意义下表所示: 
标志格式字符      标   
-       结果左对齐,右边填空格
+       输出符号(正号或负号)空格输出值为正时冠以空格,为负时冠以负号
#       对csdu类无影响;对o类, 在输出时加前缀o

 对x类,在输出时加前缀0x;对e,g,f 类当结果有小数时才给出小数点
③输出最小宽度
用十进制整数来表示输出的最少位数。 若实际位数多于定义的宽度,则按实际位数输出, 若实际位数少于定义的宽度则补以空格或0。
④精度
精度格式符以“.”开头,后跟十进制整数。本项的意义是:如果输出数字,则表示小数的位数;如果输出的是字符, 则表示输出字符的个数;若实际位数大于所定义的精度数,则截去超过的部分。
⑤长度
长度格式符为h,l两种,h表示按短整型量输出,l表示按长整型量输出。

      1. scanf()

格式字符串

格式字符串的一般形式为: %[*][输入数据宽度][长度]类型 其中有方括号[]的项为任选项。各项的意义如下:
1.类型
表示输入数据的类型,其格式符和意义下表所示。
格式    字符意义
d     输入十进制整数
o     输入八进制整数
x     输入十六进制整数
u     输入无符号十进制整数
f或e    输入实型数(用小数形式或指数形式)
c     输入单个字符
s     输入字符串
2.“*”符
用以表示该输入项读入后不赋予相应的变量,即跳过该输入值。 如 scanf("%d %*d %d",&a,&b);当输入为:1 2 3 时,把1赋予a,2被跳过,3赋予b。
3.宽度
用十进制整数指定输入的宽度(即字符数)。例如: scanf("%5d",&a);
输入:
12345678
只把12345赋予变量a,其余部分被截去。又如: scanf("%4d%4d",&a,&b);
输入:
12345678将把1234赋予a,而把5678赋予b。
4.长度
长度格式符为l和h,l表示输入长整型数据(如%ld) 和双精度浮点数(如%lf)。h表示输入短整型数据。
使用scanf函数还必须注意以下几点:
a. scanf函数中没有精度控制,如: scanf("%5.2f",&a); 是非法的。不能企图用此语句输入小数为2位的实数。
b. scanf中要求给出变量地址,如给出变量名则会出错。如 scanf("%d",a);是非法的,应改为scnaf("%d",&a);才是合法的。
c. 在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔则可用空格,TAB或回车作间隔。C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。
d. 在输入字符数据时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。

    1. 文件输入输出
      1. 打开模式

in:打开文件时做读操作;

out:打开文件时做写操作;

app:在每次写之前找到文件尾;

ate:打开文件后立即将文件定位在文件尾;(与ios::app存在区别)

trunc:打开文件时清空已存在的文件流;

binary:以二进制模式进行IO操作;(默认时采用的是 文本文件模式)

ios::out            写打开文件,无文件则创建,有则清空原文件

ios::in             读打开文件,无文件则打开失败,有则打开文件,不清空文件

ios::in|ios::out  读写打开文件,无则打开失败,有则不清空打开;文件指针在开头

ios::in|ios::app  读写打开文件,无则创建,有则打开,不清空文件指针在开头,只能在文件尾写

ios::out|ios::app 写打开文件,无则创建,有则打开,不清空,文件指针在开头,但只能在文件尾写,不能读

有效组合:

并不是所有的打开模式都可以同时制定,有些模式组合是没有意义的,例如:in和trunc,准备读取文件流,但是trunc清空了文件流。

out:打开文件时做写操作,删除已经存在的数据;

out  |  app:打开文件时做写操作,在文件尾写入,不清空已经存在的数据;

out  |  trunc:打开文件时做写操作,删除已经存在的数据,与out模式相同;(之所以相同 是因为默认的构造函数就是用  ios::out|ios|trunc)

in:打开文件时做读操作;

in  |  out打开文件时做读写操作,并定位于文件的开头处,不清空已经存在的数据;

in  |  out  |  trunc:打开文件时做读写操作,删除文件中已经有的数据;

当文件同时以in out模式打开时,不会清空已有数据;

如果只使用了out,而没有指定in模式,则会清空已有数据;

如果使用了trunc,不论是否使用了in,都会清空已有的数据(前提是有ios::out);

ifstream 对象 提供默认 文件模式 ios::in;

ofstream 对象提供默认 文件模式 ios::out|ios::trunc;

fstream 对象不提供默认的 文件模式  因此只能自己敲了;

      1. 写文件步骤

1包含头文件

#include <fstream>

2创建流对象

ofstream ofs;

3打开文件

ofs.open("文件路径",打开方式);

4写数据

ofs << "写入的数据";

5关闭文件

ofs.close();

      1. 读写操作
  1. put() 

put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。

  1. get() 

get()函数比较灵活,有3种常用的重载形式:

 1.一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。

2.另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。

3.还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='/n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'/n'。例如:

file2.get(str1,127,'A');//从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。

  1. 读写数据块 

  要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:

read(unsigned char *buf,int num); 

write(const unsigned char *buf,int num);

read()从文件中读取 num 个字节到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。

  例:

unsigned char str1[]="I Love You"; 

int n[5]; 

ifstream in("xxx.xxx"); 

ofstream out("yyy.yyy"); 

out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中 

in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换 

in.close();out.close();

      1. 检测文件
  1. 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
  2. 成员函数streampos tellg();   返回文件get指针绝对位置

streampos tellp();    返回文件put指针绝对位置

  1. C++的文件定位分为读位置和写位置的定位,对应的成员函数是 seekg()和 seekp(),seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:

istream &seekg(streamoff offset,seek_dir origin); 

ostream &seekp(streamoff offset,seek_dir origin);

streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:

ios::beg: 0 文件开头 

ios::cur: 1 文件当前位置 

ios::end: 2 文件结尾 

    1. 格式控制
      1. 输出精度

cout<<fixed<<setprecision(5)<<n<<endl;//输出n,保留小数点后5位;

需要包含头文件#include<iomanip>

cout << fixed;  //使用一般方式输出浮点数,避免系统使用E表示法,加了后精度变为小数点后几位

cout.precision(2);  //设置精度为2位,此精度为有效数字,作用域永久;

cout.setf(ios_base::showpoint);  //显示小数点后面的0,通常cout会自动删去小数点结尾的0

cout.unsetf( ios::fixed ); // 去掉了fixed,所以精度恢复成整个数值的有效位数

  1. string字符串
    1. 字符串大小写转换

//将字符串s转化为小写字母

transform(s.begin(), s.end(), s.begin(), ::tolower);

//将字符串s转化为大写字母

transform(s.begin(), s.end(), s.begin(), ::toupper);

    1. string转C串

string str="hello world!";

    char * ch=new char[str.size()+1];

strcpy(ch,str.c_str());

    1. string互转int
      1. string to int

a.采用标准库中atoi函数。(#include <stdlib.h>)

string s = "12";

int a = atoi(s.c_str());

对于其他类型也都有相应的标准库函数,比如浮点型atof(),long型atol()等等。

b.标准库stoi函数

  int stoi(const string & str)//将串按十进制转换为int

  还有double型stod,float型stof,long long型stoll等。

c.采用sstream头文件中定义的字符串流对象来实现转换。

istringstream is("12"); //构造输入字符串流,流的内容初始化为“12”的字符串

int i;

is >> i; //从is流中读入一个int整数存入i中

      1. int to string

a.采用标准库中的to_string函数。

int i = 12;

cout << std::to_string(i) << endl;

不需要包含任何头文件,应该是在utility中,但无需包含,直接使用,还定义任何其他内置类型转为string的重载函数,很方便。

b.采用sstream中定义的字符串流对象来实现。

ostringstream os; //构造一个输出字符串流,流内容为空

int i = 12;

os << i; //向输出字符串流中输出int整数i的内容

cout << os.str() << endl; //利用字符串流的str函数获取流中的内容

字符串流对象的str函数对于istringstream和ostringstream都适用,都可以获取流中的内容。

    1. 特性描述

int capacity()const;    //返回当前容量(即string中不必增加内存即可存放的元素个数)

int max_size()const;    //返回string对象中可存放的最大字符串的长度

int size()const;        //返回当前字符串的大小

int length()const;       //返回当前字符串的长度

bool empty()const;        //当前字符串是否为空

void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分

    1. 赋值 =、assign

string &operator=(const string &s);//把字符串s赋给当前字符串

string &assign(const char *s);//用c类型字符串s赋值

string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值

string &assign(const string &s);//把字符串s赋给当前字符串

string &assign(int n,char c);//用n个字符c赋值给当前字符串

string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串

string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部分赋给字符串

    1. 连接 +=、append、push_back

string &operator+=(const string &s);//把字符串s连接到当前字符串的结尾

string &append(const char *s);            //把c类型字符串s连接到当前字符串结尾

string &append(const char *s,int n);//把c类型字符串s的前n个字符连接到当前字符串结尾

string &append(const string &s);    //同operator+=()

string &append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串的结尾

string &append(int n,char c);        //在当前字符串结尾添加n个字符c

string &append(const_iterator first,const_iterator last);//把迭代器first和last之间的部分连接到当前字符串的结尾

    1. 比较 compare

bool operator==(const string &s1,const string &s2)const;//比较两个字符串是否相等

运算符">","<",">=","<=","!="均被重载用于字符串的比较;
int compare(const string &s) const;//比较当前字符串和s的大小

int compare(int pos, int n,const string &s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小

int compare(int pos, int n,const string &s,int pos2,int n2)const;//比较当前字符串从pos开始n个字符字符串与s中pos2开始n2个字符字符串的大小

int compare(const char *s) const;

int compare(int pos, int n,const char *s) const;

int compare(int pos, int n,const char *s, int pos2) const;

compare函数在>时返回1,<时返回-1,==时返回0

    1. 子串 substr

string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串

    1. 交换 swap

void swap(string &s2);    //交换当前字符串与s2的值

    1. 查找 find/rfind...

int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置

int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置

int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置

int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置

//查找成功时返回所在位置,失败返回string::npos的值

 

int rfind(char c, int pos = npos) const;//从pos开始从后向前查找字符c在当前串中的位置

int rfind(const char *s, int pos = npos) const;

int rfind(const char *s, int pos, int n = npos) const;

int rfind(const string &s,int pos = npos) const;

//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值

 

int find_first_of(char c, int pos = 0) const;//从pos开始查找字符c第一次出现的位置

int find_first_of(const char *s, int pos = 0) const;

int find_first_of(const char *s, int pos, int n) const;

int find_first_of(const string &s,int pos = 0) const;

//从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos

 

int find_first_not_of(char c, int pos = 0) const;

int find_first_not_of(const char *s, int pos = 0) const;

int find_first_not_of(const char *s, int pos,int n) const;

int find_first_not_of(const string &s,int pos = 0) const;

//从当前串中查找第一个不在串s中的字符出现的位置,失败返回string::npos

 

int find_last_of(char c, int pos = npos) const;

int find_last_of(const char *s, int pos = npos) const;

int find_last_of(const char *s, int pos, int n = npos) const;

int find_last_of(const string &s,int pos = npos) const;

int find_last_not_of(char c, int pos = npos) const;

int find_last_not_of(const char *s, int pos = npos) const;

int find_last_not_of(const char *s, int pos,  int n) const;

int find_last_not_of(const string &s,int pos = npos) const;

//find_last_of和find_last_not_of与find_first_of和find_first_not_of相似,只不过是从后向前查找

    1. 替换 replace

string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s

string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符

string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s

string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符

string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c

string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s

string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符

string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s

string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c

string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串

    1. 插入 insert

string &insert(int p0, const char *s);

string &insert(int p0, const char *s, int n);

string &insert(int p0,const string &s);

string &insert(int p0,const string &s, int pos, int n);

//前4个函数在p0位置插入字符串s中pos开始的前n个字符

 

string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c

iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置

void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符

void insert(iterator it, int n, char c);//在it处插入n个字符c

    1. 删除 erase、pop_back

iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置

iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置

string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串

s.pop_back()  //删除末尾一个字符

    1. 迭代器处理 const_iterator

string类提供了向前和向后遍历的迭代器iterator,迭代器提供了访问各个字符的语法,类似于指针操作,迭代器不检查范围。
用string::iterator或string::const_iterator声明迭代器变量,const_iterator不允许改变迭代的内容。常用迭代器函数有:

  1. const_iterator begin()const;
  2. iterator begin();                //返回string的起始位置
  3. const_iterator end()const;
  4. iterator end();               //返回string的最后一个字符后面的位置
  5. const_iterator rbegin()const;
  6. iterator rbegin();               //返回string的最后一个字符的位置
  7. const_iterator rend()const;
  8. iterator rend();                  //返回string第一个字符位置的前面

rbegin和rend用于从后向前的迭代访问,通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现

【"字符串流处理"】:
通过定义ostringstream和istringstream变量实现,<sstream>头文件中
例如:

  string input("hello,this is a test");

    istringstream is(input);

    string s1,s2,s3,s4;

    is>>s1>>s2>>s3>>s4;//s1="hello,this",s2="is",s3="a",s4="test"

    ostringstream os;

    os<<s1<<s2<<s3<<s4;

    cout<<os.str();

对于string 对象进行的操作非常多,在这里调用的成员函数中也包括由点操作符和函数名组成的对象名称,同时对象通过函数的参数列表来传递。如下所示:

#include <iostream>

#include <string>

using namespace std;

int main()

{

  string s1="string of many words.",s2="many"; //s1="string of many words.和"s1("string of many words.")等价。都调用了string类构造函数。

  int i;

  cout<<s1<<endl;

  i=s1.find(s2); //调用find函数,返回s2在s1中的位置。在这里返回10,因s1在s2起始位置是10

  s1.replace(i,4,"few");//调用replace函数用字符串few来替换s1中的4个字符。i的值就是find的返回值,

//many在字符串中的位置,并且表示替换从这该位置开始。

  cout<<s1<<endl;

  s1.erase(i,4);   //删除了s1字符串中从第10个开始的4个字符

  cout<<s1<<endl;

  s1.insert(i,"simple ");  //把字符串"simple"插入字符串s1的第10个字符的位置。

  cout<<s1<<endl;

 }


在调用find函数时,没有找到字符串s2将返回一个string类的数据成员npos(npos=-1),在string类中find函数被重载了,
重载后有两个参数ob1.find(ob2,index),index 是个整数值,表示从字符串ob1中开始搜索起始位置。

repace函数也可以重载,如ob1.replace(index1,num1,ob2,index2,num2);这里index1和num1是ob1中要替换的字符串和字符个数,
index2和num2是ob2中用于替换字符串下标和字符个数,replace函数返回一个引用给调用对象。

    1. 其他
  1. C字符串
    1. strcpy

strcpy()

#include <string.h>

char *strcpy(char *dest, const char *src);

功能:把src所指向的字符串复制到dest所指向的空间中,'\0'也会拷贝过去

参数

dest:目的字符串首地址

src:源字符首地址

返回值

成功:返回dest字符串的首地址

失败:NULL

注意:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。

strncpy()

#include <string.h>

char *strncpy(char *dest, const char *src, size_t n);

功能:把src指向字符串的前n个字符复制到dest所指向的空间中,是否拷贝结束符看指定的长度是否包含'\0'

参数

dest:目的字符串首地址

src:源字符首地址

n:指定需要拷贝字符串个数

返回值

成功:返回dest字符串的首地址

失败:NULL

    1. strcat

strcat()

#include <string.h>

char *strcat(char *dest, const char *src);

功能:将src字符串连接到dest的尾部,‘\0’也会追加过去

参数

dest:目的字符串首地址

src:源字符首地址

返回值

成功:返回dest字符串的首地址

失败:NULL

strncat()

#include <string.h>

char *strncat(char *dest, const char *src, size_t n);

功能:将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去

参数

dest:目的字符串首地址

src:源字符首地址

n:指定需要追加字符串个数

返回值

成功:返回dest字符串的首地址

失败:NULL

    1. strcmp

strcmp()

#include <string.h>

int strcmp(const char *s1, const char *s2);

功能:比较 s1  s2 的大小比较的是字符ASCII码大小

参数

s1:字符串1首地址

s2:字符串2首地址

返回值

相等:0

大于:>0 在不同操作系统strcmp结果会不同   返回ASCII差值

小于:<0

strncmp()

#include <string.h>

int strncmp(const char *s1, const char *s2, size_t n);

功能:比较 s1 和 s2 前n个字符的大小比较的是字符ASCII码大小

参数

s1:字符串1首地址

s2:字符串2首地址

n:指定比较字符串的数量

返回值

相等:0

大于: > 0

小于: < 0

    1. sprintf

sprintf()

#include <stdio.h>

int sprintf(char *str, const char *format, ...);

功能:根据参数format字符串来转换并格式化数据,然后将结果输出到str指定的空间中,直到出现字符串结束符 '\0'  为止。

参数

str:字符串首地址

format:字符串格式,用法和printf()一样

返回值

成功:实际格式化的字符个数

失败: - 1

    1. sscanf

sscanf()

#include <stdio.h>

int sscanf(const char *str, const char *format, ...);

功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。

参数

str:指定的字符串首地址

format:字符串格式,用法和scanf()一样

返回值

成功:参数数目,成功转换的值的个数

失败: - 1

    1. strchr

strchr()

#include <string.h>

char *strchr(const char *s, int c);

功能:在字符串s中查找字母c出现的位置

参数

s:字符串首地址

c:匹配字母(字符)

返回值

成功:返回第一次出现的c地址

失败:NULL

    1. strstr

strstr()

#include <string.h>

char *strstr(const char *haystack, const char *needle);

功能:在字符串haystack中查找字符串needle出现的位置

参数

haystack:源字符串首地址

needle:匹配字符串首地址

返回值

成功:返回第一次出现的needle地址

失败:NULL

    1. strtok

strtok()

#include <string.h>

char *strtok(char *str, const char *delim);

功能:来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时, 则会将该字符改为\0 字符,当连续出现多个时只替换第一个为\0

参数

str:指向欲分割的字符串

delim:为分割字符串中包含的所有字符

返回值

成功:分割后字符串首地址

失败:NULL

在第一次调用时:strtok()必需给予参数str,字符串往后的调用则将参数str设置成NULL,每次调用成功则返回指向被分割出片段的指针

char a[100] = "adc*fvcv*ebcy*hghbdfg*casdert";

char *s = strtok(a, "*");//"*"分割的子串取出

while (s != NULL)

{

printf("%s\n", s);

s = strtok(NULL, "*");

}

    1. atoi

atoi()

#include <stdlib.h>

int atoi(const char *nptr);

功能atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符('\0')才结束转换,并将结果返回返回值。

参数

nptr:待转换的字符串

返回值:成功转换后整数

类似的函数有:atof():把一个小数形式的字符串转化为一个浮点数。

atol():将一个字符串转化为long类型

    1. 内存操作函数

memset()

#include <string.h>

void *memset(void *s, int c, size_t n);

功能:将s的内存区域的前n个字节以参数c填入

参数

s:需要操作内存s的首地址

c:填充的字符,c虽然参数为int,但必须是unsigned char , 范围为0~255

n:指定需要设置的大小

返回值:s的首地址

memcpy()

#include <string.h>

void *memcpy(void *dest, const void *src, size_t n);

功能:拷贝src所指的内存内容的前n个字节到dest所值的内存地址上。

参数

dest:目的内存首地址

src:源内存首地址,注意:dest和src所指的内存空间不可重叠,可能会导致程序报错

n:需要拷贝的字节数

返回值:dest的首地址

memmove()

memmove()功能用法和memcpy()一样,区别在于:dest和src所指的内存空间重叠时,memmove()仍然能处理,不过执行效率比memcpy()低些。

    1. other
  1. 指针和引用
    1. 数组的指针 (*)[]

类型 (*变量名) [大小] = 初值;

例:

int b[3][4];

int (*pb)[4] = b;//定义pb指针,指向int[4];pb用法与b一样;

    1. 指针的数组   *[]

类型 * 数组名 [大小]={};

例:

int b[3][4];

int * p[]={b[0],b[1],b[2]};//定义一个指针数组,数组元素是指针;

    1. 向函数中传递二维数组

int arr[3][4];

//1.

void f(int * a,int row,int col)

{

for(int i=0;i<row;i++)

for(int j=0;j<col;j++)

cout<<a[i*col+j]; //a[i][j];

}

f((int*)arr,3,4);

//2.

void f2(int(*a)[4],int row)//void f2(int a[][4],int row)

{

for(int i=0;i<row;i++)

for(int j=0;j<4;j++)

cout<<a[i][j]; //a[i][j];

}

f2(arr,3);

//3.

void f3(int **a,int row,int col)

{

for(int i=0;i<row;i++)

for(int j=0;j<4;j++)

cout<<a[i][j]; //a[i][j];

}

int * p[]={arr[0],arr[1],arr[2]};

f3(p,3,4);

    1. 函数的指针    (* )()

返回类型 (*指针名) (形参表) = 函数名;

void testFunc(int a,int b){cout<<a<<b;}

void (*fun)(int,int)=testFunc; //定义指向testFun的函数指针

//为函数指针类型取别名:

typedef void (*F)(int ,int);

using F=void(*)(int ,int);

    1. 函数指针的数组 (* [])()

返回类型 (*数组名[大小])(形参)={函数1,...};

void (*funArr[])(int,int)={fun1,fun2.fun3};

//或先用using 说明函数指针的类型别名

using F=void (*)(int,int);

F funArr[]={fun1,fun2,...};

    1. 数组的引用 (&)[]

类型 (&引用变量名)[大小] = 数组名;

int a[]={1,2,3};

int (&ra)[3]=a;

auto & ra=a;//可用auto简化;

    1. 指针的引用 *&

类型 *&引用名 = 指针名;

int * p;

int *&rp = p;//rp是指针p的引用;

auto & rp=p;//可用auto简化;

注:引用的指针就是原变量的指针;

    1. 函数的引用 (& )()

返回类型 (& 引用名) (形参表) = 函数名;

    1. Lambda表达式

[捕获](形参表){函数体}

① 函数对象参数;

[],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:

    1. 空。没有使用任何函数对象参数。
    2. =。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
    3. &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
    4. this。函数体内可以使用Lambda所在类中的成员变量。
    5. a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
    6. &a。将a按引用进行传递。
    7. a, &b。将a按值进行传递,b按引用进行传递。
    8. =,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
    9. &, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

② 操作符重载函数参数;

标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。

③ 可修改标示符;

mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。

    1. other
  1. STL容器
    1. vector容器
      1. vector基本概念

功能:vector数据结构和数组非常相似,也称为单端数组

数组是静态空间,而vector可以动态扩展

动态扩展:并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间

vector容器的迭代器是支持随机访问的迭代器

      1. vector构造函数

vector<T> v;                   //采用模板实现类实现,默认构造函数

vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。

vector(n, elem);                      //构造函数将n个elem拷贝给本身。

vector(const vector &vec);        //拷贝构造函数。

      1. vector赋值操作

vector& operator=(const vector &vec);//重载等号操作符

assign(beg, end);       //将[beg, end)区间中的数据拷贝赋值给本身。

assign(n, elem);        //将n个elem拷贝赋值给本身。

      1. vector容量和大小

empty();                            //判断容器是否为空

capacity();                      //容器的容量

size();                              //返回容器中元素的个数

resize(int num);             //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

  ​       //如果容器变短,则末尾超出容器长度的元素被删除。

resize(int num, elem);  //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

  ​          //如果容器变短,则末尾超出容器长度的元素被删除

      1. vector插入和删除

push_back(ele);                                  //尾部插入元素ele

pop_back();                                       //删除最后一个元素

insert(const_iterator pos, ele);        //迭代器指向位置pos插入元素ele

insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele

insert(pos,beg,end);    //在pos位置插入[beg,end)区间的数据,无返回值。

erase(const_iterator pos);                     //删除迭代器指向的元素

erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素

clear();                                            //删除容器中所有元素

      1. vector数据存取

at(int idx);          //返回索引idx所指的数据

operator[];           //返回索引idx所指的数据

front();              //返回容器中第一个数据元素

back();               //返回容器中最后一个数据元素

      1. vector互换容器

swap(vec);//将vec与本身的元素互换

//收缩内存

vector<int>(v).swap(v); //匿名对象

      1. vector预留空间

reserve(int len);  //容器预留len个元素长度,预留位置不初始化,元素不可访问。

功能:          减少vector在动态扩展容量时的扩展次数

    1. deque容器
      1. deque基本概念

双端数组,可以对头端进行插入删除操作。

deque容器的迭代器也是支持随机访问的

deque与vector区别:

vector对于头部的插入删除效率低,数据量越大,效率越低。

deque相对而言,对头部的插入删除速度回比vector快。

vector访问元素时的速度会比deque快,这和两者内部实现有关。

      1. deque函数

与vector函数相同

特有:

push_front(elem);       //在容器头部插入一个数据

pop_front();                 //删除容器第一个数据

    1. stack容器
      1. stack基本概念

stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口

栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为,不支持迭代器

栈中进入数据称为  --- 入栈  push

栈中弹出数据称为  --- 出栈  pop

     

      1. stack常用接口

构造函数:

stack<T> stk;           //stack采用模板类实现,stack对象的默认构造形式

stack(const stack &stk);         //拷贝构造函数

赋值操作:

stack& operator=(const stack &stk);          //重载等号操作符

数据存取:

push(elem);         //向栈顶添加元素

pop();                //从栈顶移除第一个元素

top();                //返回栈顶元素

大小操作:

empty();          //判断堆栈是否为空

size();              //返回栈的大小

    1. queue容器
      1. queue基本概念

Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口。

队列容器允许从一端新增元素,从另一端移除元素

队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为,不支持迭代器

队列中进数据称为 --- 入队   push

队列中出数据称为 --- 出队   pop

      1. queue常用接口

构造函数:

queue<T> que;               //queue采用模板类实现,queue对象的默认构造形式

queue(const queue &que);                  //拷贝构造函数

赋值操作:

queue& operator=(const queue &que);          //重载等号操作符

数据存取:

push(elem);                           //往队尾添加元素

pop();                                    //从队头移除第一个元素

back();                                   //返回最后一个元素

front();                                  //返回第一个元素

大小操作:

empty();            //判断堆栈是否为空

size();              //返回栈的大小

    1. list容器
      1. list基本概念

功能:将数据进行链式存储

链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的

链表的组成:链表由一系列结点组成

结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

STL中的链表是一个双向循环链表

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器不支持随机访问

list的优点:

采用动态存储分配,不会造成内存浪费和溢出

链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

list的缺点:

链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大

List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。

      1. list插入与删除

* push_back(elem);//在容器尾部加入一个元素

* pop_back();//删除容器中最后一个元素

* push_front(elem);//在容器开头插入一个元素

* pop_front();//从容器开头移除第一个元素

* insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。

* insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。

* insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。

* clear();//移除容器的所有数据

* erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。

* erase(pos);//删除pos位置的数据,返回下一个数据的位置。

* remove(elem);//删除容器中所有与elem值匹配的元素。

      1. list数据存取

* front();        //返回第一个元素。

* back();         //返回最后一个元素。

//cout << L1.at(0) << endl;//错误 不支持at访问数据

//cout << L1[0] << endl; //错误  不支持[]方式访问数据

//list容器的迭代器是双向迭代器,不支持随机访问

//迭代器不可以跳跃访问,即使是+1,只能自增或自减

    1. set/multiset容器
      1. set基本概念

简介:所有元素都会在插入时自动被排序,不支持随机访问

本质:set/multiset属于关联式容器,底层结构是用二叉树实现。

set和multiset区别

set不允许容器中有重复的元素,multiset允许容器中有重复的元素.

      1. set构造与赋值

构造:

set<T> st; //默认构造函数:

set(const set &st); //拷贝构造函数

赋值:

set& operator=(const set &st); //重载等号操作符

      1. set大小与交换

size(); //返回容器中元素的数目

empty(); //判断容器是否为空

swap(st); //交换两个集合容器

      1. set插入与删除

insert(elem); //在容器中插入元素。

clear(); //清除所有元素

erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。

erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

erase(elem); //删除容器中值为elem的元素。

      1. set查找与统计

find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();

count(key); //统计key的元素个数,set中为0或1;

      1. set与multiset的区别

set不可以插入重复数据,而multiset可以

set插入数据的同时会返回插入结果,表示插入是否成功

multiset不会检测数据,因此可以插入重复数据

      1. pair对组创建

pair<type, type> p ( value1, value2 );

pair<type, type> p = make_pair( value1, value2 );

    1. map/multimap容器
      1. map基本概念

简介

map中所有元素都是pair

pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

所有元素都会根据元素的键值自动排序

本质:

map/multimap属于关联式容器,底层结构是用二叉树实现。

优点

可以根据key值快速找到value值

map和multimap区别

map不允许容器中有重复key值元素,multimap允许容器中有重复key值元素

      1. map构造和赋值

构造:

map<T1, T2> mp; //map默认构造函数:

map(const map &mp); //拷贝构造函数

赋值:

map& operator=(const map &mp); //重载等号操作符

      1. map插入和删除

insert(elem); //在容器中插入元素。m.insert(pair<int, int>(1, 10));

emplace(键,值) //在容器中添加一个元素,等同 m[键]=值

clear(); //清除所有元素

erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。

erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

erase(key); //删除容器中值为key的元素。

      1. map查找和统计

find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();

count(key); //统计key的元素个数

    1. 其他
  1. STL算法
    1. 遍历
      1. for_each

功能描述:

  • 实现遍历容器

函数原型:

  • for_each(iterator beg, iterator end, _func);

// 遍历算法 遍历容器元素

// beg 开始迭代器

// end 结束迭代器

// _func 函数名或者函数对象的实例

      1. tansform

功能描述:

  • 搬运容器到另一个容器中。
  • 搬运的目标容器必须要提前开辟空间,否则无法正常搬运

函数原型:

  • transform(iterator beg1, iterator end1, iterator beg2, _func);

//beg1 源容器开始迭代器

//end1 源容器结束迭代器

//beg2 目标容器开始迭代器

//_func 函数名或者函数对象的实例

    1. 查找
      1. find

函数原型:

  • find(iterator beg, iterator end, value);

// 按值查找元素,找到返回指定位置迭代器找不到返回结束迭代end()

// beg 开始迭代器

// end 结束迭代器

// value 查找的元素

      1. find_if

功能描述:

  • 按条件查找元素

函数原型:

  • find_if(iterator beg, iterator end, _Pred);

// 按条件查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 函数或者谓词(返回bool类型的仿函数)

      1. adjacent_find

功能描述:

  • 查找相邻重复元素

函数原型:

  • adjacent_find(iterator beg, iterator end);

// 查找相邻重复元素,返回相邻元素的第一个位置的迭代器

// beg 开始迭代器

// end 结束迭代器

      1. binary_search

功能描述:

  • 查找指定元素是否存在

函数原型:

  • bool binary_search(iterator beg, iterator end, value);

// 查找指定的元素,查到 返回true 否则false

// 注意: 在无序序列中不可用

// beg 开始迭代器

// end 结束迭代器

// value 查找的元素

      1. count

功能描述:

  • 统计元素个数
  • 统计自定义数据类型时候,需要配合重载 operator==

函数原型:

  • count(iterator beg, iterator end, value);

// 统计元素出现次数

// beg 开始迭代器

// end 结束迭代器

// value 统计的元素

      1. count_if

功能描述:

  • 按条件统计元素个数

函数原型:

  • count_if(iterator beg, iterator end, _Pred);

// 按条件统计元素出现次数

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词

    1. 排序
      1. sort

功能描述:

  • 对容器内元素进行排序

函数原型:

  • sort(iterator beg, iterator end, _Pred);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词

      1. random_shuffle

功能描述:

  • 洗牌 指定范围内的元素随机调整次序
  • 使用时记得加随机数种子

函数原型:

  • random_shuffle(iterator beg, iterator end);

// 指定范围内的元素随机调整次序

// beg 开始迭代器

// end 结束迭代器

      1. merge

功能描述:

  • 两个容器元素合并,并存储到另一容器中
  • 目标容器需要提前开辟空间

函数原型:

  • merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 容器元素合并,并存储到另一容器中

// 注意: 两个容器必须是有序的

// beg1 容器1开始迭代器         // end1 容器1结束迭代器

// beg2 容器2开始迭代器         // end2 容器2结束迭代器

// dest 目标容器开始迭代器

      1. reverse

功能描述:

  • 将容器内元素进行反转

函数原型:

  • reverse(iterator beg, iterator end);

// 反转指定范围的元素

// beg 开始迭代器

// end 结束迭代器

    1. 拷贝和替换
      1. copy

功能描述:

  • 容器内指定范围的元素拷贝到另一容器中
  • 目标容器记得提前开辟空间

函数原型:

  • copy(iterator beg, iterator end, iterator dest);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// dest 目标起始迭代器

      1. replace

功能描述:

  • 将容器内指定范围的旧元素修改为新元素
  • replace会替换区间内满足条件的元素

函数原型:

  • replace(iterator beg, iterator end, oldvalue, newvalue);

// 将区间内旧元素 替换成 新元素

// beg 开始迭代器

// end 结束迭代器

// oldvalue 旧元素

// newvalue 新元素

      1. replace_if

功能描述: 

  • 将区间内满足条件的元素,替换成指定元素

函数原型:

  • replace_if(iterator beg, iterator end, _pred, newvalue);

// 按条件替换元素,满足条件的替换成指定元素

// beg 开始迭代器

// end 结束迭代器

// _pred 谓词

// newvalue 替换的新元素

      1. swap

功能描述:

  • 互换两个容器的元素
  • 注意交换的容器要同种类型

函数原型:

  • swap(container c1, container c2);

// 互换两个容器的元素

// c1容器1

// c2容器2

    1. 算数生成
      1. accumulate

功能描述:

  • 计算区间内 容器元素累计总和
  • accumulate使用时头文件注意是 numeric

函数原型:

  • accumulate(iterator beg, iterator end, value);

// 计算容器元素累计总和

// beg 开始迭代器

// end 结束迭代器

// value 起始值,为0;

      1. fill

功能描述:

  • 向容器区间中覆盖指定的元素

函数原型:

  • fill(iterator beg, iterator end, value);

// 向容器中填充元素

// beg 开始迭代器

// end 结束迭代器

// value 填充的值

    1. 集合算法
      1. set_intersection

功能描述:

  • 求两个容器的交集

函数原型:

  • set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的交集

// 注意:两个集合必须是有序序列,//取两个里面较小的值给目标容器开辟空间

//set_intersection返回值既是交集中最后一个元素的位置

// beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

      1. set_union

功能描述:

  • 求两个集合的并集

函数原型:

  • set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的并集

// 注意:两个集合必须是有序序列 //取两个容器的和给目标容器开辟空间

// beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

      1. set_difference

功能描述:

  • 求两个集合的差集

函数原型:

  • set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的差集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器 // end1 容器1结束迭代器 // beg2 容器2开始迭代器 // end2 容器2结束迭代器 // dest 目标容器开始迭代器

    1. other
  1. Class
    1. 类和对象
      1. 类的定义

class 类名{ 访问权限: 属性 / 行为 };

class缺省是私有private;struct中缺省公有public

三部分次序随意,但private只有在第一部分才可省略;

对复杂的成员函数,在类中先给出原型定义,在类外再说明具体实现:

返回类型 类名::成员函数名(形参表){  函数体 }

      1. 类成员的可见性

private:只允许本类成员函数访问,数据变量往往说明为私有

protected:能被本类和子类成员访问,其他类不能访问

public:对外可见,成员函数一般作为公有成员

      1. 类的数据成员

类中的数据成员可以是任意类型,除了自身类,但自身类的指针可作为该类的成员。

类中可对数据成员直接初始化。C11支持。

多个数据变量之间不能重名。

类定义在前,使用在后。如果类A中使用了类B,而且类B也使用了类A,就需要“前向引用说明” ,即类的原型说明,“class A;”

      1. 类的成员函数

如果一个数据成员可以改变,往往用一个setXxx(一个形参)函数来实现,“xxx”就是数据成员的名字,而且形参类型往往与数据成员的类型一致。

如果一个数据成员可读,往往用一个getXxx()函数来返回这个数据成员,“xxx”就是数据成员的名字,返回类型往往与数据成员的类型一致。

如果希望一个数据成员是只读的(read only),即不能改变,那么该数据成员应设为私有,再设计一个公有的getXxx()函数来读取它。

如果要从已有数据成员中计算并返回一个值,往往用一个getXxx()函数来实现。如果函数返回bool类型,往往用isXxx()函数来实现。

      1. 对象的创建

Per p1; //默认构造

Per p2(10); //有参构造

Per p3(p2); //拷贝构造

Per p4=Per(p2); //显式调用拷贝构造

Per(); //匿名对象

      1. 类与对象的关系,this指针

在运行时刻,类是静态的,不能改变的。一个类的标识就是类的名称。一个对象就是某个类的一个实例,对象是动态的,具有一定的生存周期。

一个类的多个对象分别持有自己的数据成员,相互独立,但成员函数的空间有多个对象共享,并没有独立的拷贝。

每个非静态成员函数都隐含持有指向当前对象的一个指针,即this指针

如果函数形参与数据成员重名,就需要this指针来区别。

如果函数要返回当前对象的引用,就需要return *this;

    1. 类的成员
      1. 构造函数

构造函数: 类名 (形参表):成员初始化表{   };

委托构造函数: 类名 (形参表):类名(实参表){   }; //本函数将构造委托给 类名(实参表);

拷贝构造函数: 类名 (const 类名&对象名):成员初始化表{   };

拷贝赋值函数: 类名& operator= (const 类名&对象名){函数体;return *this; };

移动构造函数: 类名 (类名&&对象名):成员初始化表{   };

移动赋值函数: 类名& operator= (类名&&对象名){函数体;return *this; };

析构函数: ~类名(){}; //若类的数据成员含有指针,且构造函数中用new动态申请,此时就需要自定义析构函数,用delete回收。

      1. 构造函数的用法

构造函数调用规则如下:

* 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造

* 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

调用移动构造函数 A a2 = move(a1);

调用移动赋值函数 a2 = move(a1);  //若移动函数不存在,这调用拷贝函数;

特殊成员函数的显式控制:

A () = default; //显式要求编译器生成默认缺省构造函数;

A (const A &) = delete;

A& operator=(const A&) = delete;  //显式要求编译器不生成拷贝构造、赋值函数

      1. 复合类

创建一个符合对象时,先调用成员对象的构造函数,再调用复合对象的构造函数。若有多个成员对象时,其构造函数的执行顺序与成员对象的说明顺序有关,而与成员初始化列表中的顺序无关。

析构函数的执行顺序与构造函数严格相反,即先执行复合对象的析构,再执行成员对象的析构。

      1. 静态成员

静态成员变量

  *  所有对象共享同一份数据

  *  在编译阶段分配内存

  *  类内声明,类外初始化

静态成员函数

  *  所有对象共享同一个函数

  *  静态成员函数只能访问静态成员变量

*  若静态成员函数在类外实现,就不能加static和访问控制修饰符;

class AA{

static int a; //类内声明

};

int AA::a; //类外初始化,默认为0;

      1. const修饰成员函数

常函数:

* 成员函数后加const后我们称为这个函数为常函数

* 常函数内不可以修改成员属性,只能调用const成员函数

* 成员属性声明时加关键字mutable后,在常函数中依然可以修改

*若在类外实现const成员函数,应保持const,否则编译器认为是定义重载函数

常对象:

* 声明对象前加const称该对象为常对象

* 常对象只能调用常函数

*常对象不能修改成员变量的值,但是可以访问,可以修改mutable修饰成员变量。

*形参带const限定也被作为函数基调的一部分,可以用来定义重载函数

      1. 类成员的指针

数据成员指针:

类型 类名::*指针变量名 = &类名::数据成员名

通过指针访问数据成员:

对象指针 ->* 数据成员指针变量名

对象引用 .* 数据成员指针变量名

成员函数指针:

返回类型 (类名::*指针变量名)(形参表) = 类名::成员函数名

通过指针调用成员函数:

对象指针 ->*成员函数指针变量名 (实参表);

对象引用 .* 成员函数指针变量名 (实参表);

例:

class A{

public:

int a;

void fun(int a){cout<<a<<end;}

};

A a1{10};

int A::*pa1 = &A::a; //定义数据成员指针 pa1 指向 A::a;

cout << a1 .* pa1 << endl; //通过数据成员指针访问该成员;

void (A::*pf)(int) = A::fun; //定义成员函数指针 pf 指向 A::fun

a1.*pf (5); //通过成员函数指针调用该函数

    1. 类的继承
      1. 继承的定义

class 子类名 : 继承方式1 父类1,继承方式2 父类2  {子类扩展成员};

继承方式缺省为 private, 但最常用为 public;

公有继承时,父类私有、保护、公有成员在子类中仍是私有、保护、公有成员。

保护继承时,父类的保护、公有在子类中为保护,私有仍为私有。

私有继承时,父类的公有、保护、私有在子类中全为私有。

      1. 派生类的构造和析构

派生类的构造函数的一般格式为:

子类名 (形参表): 基类名(实参表), ... , 成员名(实参表), ... {构造函数体};

如果派生类自定义拷贝构造或移动构造,应在初始化列表中显式调用基类的拷贝构造或移动构造函数。如果没有显式调用,就会隐式调用基类的缺省构造函数。派生类缺省实现的拷贝构造函数和移动构造函数分别调用各基类的拷贝函数和移动函数(递归理解这个过程)。

初始化列表中调用基类的函数格式如下:

  • 拷贝构造函数: 基类名 (被拷贝对象)
  • 移动构造函数: 基类名(move(被拷贝对象))

赋值函数体中调用基类函数格式如下:

  • 拷贝赋值函数: 基类名::operator= (被拷贝对象);
  • 移动赋值函数: 基类名::operator=(move(被拷贝对象));

C++11允许派生类“继承”基类的构造函数以避免重复代码。派生类中使用一种using 说明语句: using 基类名::基类名; 继承基类的带参构造函数。

派生类构造过程:

①先逐层先上调用父类构造函数,执行完成顺序相反,最上层的基类先执行完。

②再调用各成员对象的构造函数(按成员对象的说明顺序),若成员对象是继承来的,则进入第(1)步。

③最后执行派生类自己的构造函数。

派生类的析构过程与构造过程正相反。派生类的析构函数仅对自己扩展的数据成员负责。

      1. 继承同名问题

* 访问子类同名成员   直接访问即可

* 访问父类同名成员   加作用域限制

成员访问表达格式如下:

对象或引用.类名::数据成员

对象或引用.类名::成员函数(实参表);

支配规则:

支配规则确定了基类和派生类之间的同名成员的访问规则,查找定位成员的过程是从派生类到基类查找,即向上查找

导入基类中指定成员:

using 基类名::成员名;

被导入成员因为非私有成员;被导入的数据成员不能与本类成员重名;被导入的成员函数只需说明函数名,无需说明形参,以导入该函数名所有的重载形式;

      1. 菱形继承

虚基类说明格式:

class 派生类名: virtual 继承方式 基类名 {};

关键字virtual与继承方式的位置无关,但必须位于基类名之前,且virtual只对紧随其后的一个基类起作用,该基类无论经过多少次派生,在其派生对象中只有该基类的一个子对象。

例:

class A{public:int a;};

class B1:virtual public A{};

class B2:public virtual A{};

class C:public B1,public B2{public:A };

注意,上面对类A的两个派生关系都要加virtual;而类C的继承关系就不需要加virtual,这是因为虚基类可以继承

从虚基类直接或间接派生出的派生类中的构造函数成员初始化列表中都要列出对其虚基类构造函数的调用(若未列出,就隐含调用该基类的缺省构造函数);但只有当前派生类的构造函数真正执行了虚基类的构造函数,保证对虚基类的子对象只初始化一次。

派生类不能从其虚基类中继承构造函数。

    1. 多态
      1. 多态的基本概念

多态分为两类

* 静态多态: 函数重载 和 运算符重载 属于静态多态,复用函数名

* 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

* 静态多态的函数地址早绑定  -  编译阶段确定函数地址

* 动态多态的函数地址晚绑定  -  运行阶段确定函数地址

多态满足条件

* 有继承关系

* 子类重写父类中的虚函数

多态使用条件

* 父类指针或引用指向子类对象

重写:函数返回值类型  函数名 参数列表 完全一致称为重写

      1. 虚函数

虚函数是用virtual修饰的成员函数,说明该函数可以被派生类重写。

构造函数、静态成员函数和友元函数不能修饰为虚函数。

含有虚函数的类称为多态类

非多态类:无虚函数

多态类:有虚函数

is_polymorphic<Ty>::value==false

is_polymorphic<Ty>::value==true

只能静态转换,编译期执行,可取代传统C转换。

static_cast<目标类型>(被转换指针或引用)

静态转换的源和目标没有限制必须为多态类

①向上转换:标准转换或隐式转换

②向下转换:静态转换或代传统C转换。

静态转换或动态转换,但动态转换更安全

dynamic_cast<目标类型>(被转换指针或引用)

动态转换的源必须是多态类,对目标则无限制。

①向上转换:标准转换或隐式转换

②向下转換:静态转换或动态转换

typeid(指针)  得到指针类型,即使用类型

typeid(引用)得到所引用对象实际类型

typeid(指针)得到指针类型,即使用类型

成员函数中调用虚函数,执行改写后的虚函数;(多态)

构造函数、析构函数中调用虚函数,执行本类自己的虚函数,(静态绑定)

      1.  虚析构和纯虚析构

如果用”delete 基类指针;”来撤销一个派生类对象时,就只执行基类的析构函数,而不执行派生类的析构函数。

解决方式:将基类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:

*可以解决父类指针释放子类对象

*都需要有具体的函数实现

虚析构和纯虚析构区别:

*如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

基类中的虚构函数虽可定义为纯虚函数,但类外必须提供一个实现。

定义纯虚函数的一般格式为:

virtual 返回类型 函数名 (形参表) = 0;

如果一个类含有纯虚函数,那么此类就称为抽象类,抽象类不能直接实例化创建对象,其派生类应该以改写形式提供纯虚函数的具体实现。纯虚函数可以定义指针或引用,通过这些指针或引用能调用纯虚函数。

      1. override、final、abstract

派生类如果明确要改写某个虚函数,C++11建议应显式说明,对该函数添加 override 修饰,让编译器检查是否合法有效。

virtual void fun(int) override {};

显式说明抽象,即在类名后用 abstract 说明,显式说明的类无论其是否有纯虚函数,都作为抽象类。例: class base abstract{ };

如果一个虚函数修饰为 final ,派生类就不能再改写它。

纯虚函数和非虚函数不能修饰为final。

virtual void fun(int) final {};

如果一个类修饰为final,该类就不能再说明派生类。例:  class base final{ };

    1. 运算符重载
      1. 友元friend

友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的三种实现:

*全局函数做友元

*类做友元

*成员函数做友元

例:

class A;

class B{public:int visit(A *aa);};

class A{

    int a;

public:

    friend void PUT(A *aa) { cout << aa->a; };//全局函数做友元

    friend class C;//类做友元,C的所有成员函数都可视为A的友元;

    friend int B::visit(A *aa);//成员函数做友元

};

int B::visit(A*aa){return aa->a;}

      1. 友元运算符

只能用全局函数来实现,双目运算符中右操作数为对象,左操作数为非同类。

friend ostream& operator<< (ostream &out ,类名&obj);//cout<<obj;

friend istream& operator>> (istream &in, 类名&obj);//cin>>obj;

friend 类名 operator + (int i,类名&obj)// i+obj;

      1. 普通运算符

成员函数和全局函数都可实现

例:

class A{

    int a;

public:

    A(){};

    A(int i):a(i){};

//成员函数

    A& operator++(){a++;return*this;}//前置自增

    A operator++(int){A tp=*this;a++;return tp;}//后置自增

    A operator +(const A&aa){return A(this->a+aa.a); }

    bool operator >(const A&aa){return a>aa.a;}

    A& operator+=(const A&aa){a+=aa.a;return*this;}

//全局友元函数

    friend A& operator++(A&aa){aa.a++;return aa;}//前置自增

    friend A operator++(A&aa,int){A tp=aa;aa.a++;return tp;}//后置自增

    friend A operator +(const A&a1,const A&a2){return A(a1.a+a2.a); }

    friend bool operator >(const A&a1,const A&a2){return a1.a>a2.a;}

    friend A& operator+=(A&a1,const A&a2){a1.a+=a2.a;return a1;}    

    friend ostream& operator<<(ostream&out,A&aa){

        out<<aa.a;

        return out;}

    friend istream& operator>>(istream&in,A&aa){

        in>>aa.a;

        return in;}

};

      1. 特殊运算符

只能成员函数来实现,当前对象作为单目运算符的操作数或双目运算符的左操作数。

拷贝赋值: 类名& operator= (const 类名&对象名){函数体;return *this; };

移动赋值: 类名& operator= (类名&&对象名){函数体;return *this; };

类型转换 operator 目标类型 (){return 目标类型;};//目标类型就是返回类型;

下标运算符:返回类型 & operator[](形参){ };

仿函数: 返回类型 operator()(形参表){ };

例:

class INT

{

    int d;

public:

    INT (int i):d(i){}

    operator string(){return to_string(d);}//类型转换

    int operator[](int i){return d+i;}//下表访问

    void operator()(string s){cout<<"仿函数"<<s;}//仿函数

};

int main()

{

    INT in(10);

    cout<<string(in)<<endl;

    cout<<in[10]<<endl;

in("sd");

}

  1. 其他
    1. 复制

int a[5]={1,2,3,4,5};

    int b[5]={6,7,8,9,0};

将数组b复制到数组a中:

memcpy(a,b,sizeof(a));//方法1,#include <string.h>

memmove(a,b,sizeof(a));//方法2,#include <string.h>

std::copy(b,b+sizeof(a),a);//方法3

    1. 控制台操作
      1. 检测键盘输入

可以用kbhit()函数和或getch()函数。

kbhit()的用法:

#include <coio.h>

程序执行到kbhit()时,等待输入,但是不会停止而是继续运行,有输入时kbhit()才就返回一个非零值,否则返回0。

      1. 设置光标位置

SetConsoleCursorPosition函数

#include <coio.h>    #include <Windows.h>

typedef struct _COORD {

    SHORT X;

    SHORT Y;

  } COORD

COORD coord;

coord.X=10;

coord.Y=20;

SetConsoleCursorPosition( GetStdHandle(STD_OUTPUT_HANDLE),coord);

//将控制台光标移到(x,y)处;

      1. 设置光标信息

SetConsoleCursorInfo函数

ypedef struct _CONSOLE_CURSOR_INFO {

    DWORD dwSize;

    WINBOOL bVisible;

  } CONSOLE_CURSOR_INFO

CONSOLE_CURSOR_INFO cci;

cci.dwSize=sizeof  cci;

cci.bVisible=FALSE;//可见

SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cci);

//设置光标信息  大小,,可见,

      1. sleep

#include <windows.h>

函数原型

void Sleep(DWORD dwMilliseconds);

参数为毫秒

    1. system()

头文件”stdlib.h”

  

带路径的要使用绝对路径,用”/”或者”\\”分隔;带中文名的要使用GBK编码

例:

System(“D:/DEV/devcpp.exe”)://打开D:/DEV中的devcpp.exe

 如果正确执行会0;否知返回其它非0数;

    1. 防止头文件重复包含

为了避免同一个文件被include多次,C/C++中有两种方式,一种是 #ifndef 方式,一种是 #pragma once 方式。

方法一:

#ifndef __SOMEFILE_H__

#define __SOMEFILE_H__

// 声明语句

#endif

方法二:

#pragma once

// 声明语句

    1. #include <time.h>

time_t mktime(struct tm * timeptr); //将tm类型的指针转换为time_t类型

char * asctime(const struct tm * timeptr);

char * ctime(const time_t *timer);//通过time_t类型的指针返回一个日期,时间的字符串

struct tm * gmtime(const time_t *timer); //将日历时间(time_t)转化为世界标准时间(即格林尼治时间),并返回一个tm结构体来保存这个时间

struct tm * localtime(const time_t * timer);// 将time_t指针转化为tm指针;

tm结构包括:

tm_year:从1900开始; tm_mon:0-11,1月为0;

tm_day:1-31; tm_hour:0-23;

tm_min:0-59; tm_sec:0-59;

tm_wday:0-6,周日为0; tm_yday:0-365,1月1日为0;

time_t l_t=time(NULL);

tm * pt=localtime(&l_t);

hour=pt->tm_hour;

min=pt->tm_min;

sec=pt->tm_sec;

    1. #include <cctype>

加入这个头文件就可以调用以下函数:

1、isalpha(x) 判断x是否为字母

2、isdigit(x) 判断x是否为数字

3、islower(x) 判断x是否为小写字母

4、isupper(x) 判断x是否为大写字母

5、isalnum(x) 判断x是否为字母或数字

6、ispunct(x) 判断x是否为标点符号

7、isspace(x) 判断x是否为空格

对于以上函数,如果x符合条件的话,均会返回true,否则返回false

还有以下函数:

1、toupper(x) 如果x是小写字母,将其转换成大写字母

2、tolower(x) 如果x是大写字母,将其转换成小写字母

    1. 小知识

正数 原码,反码,补码相同

对于负数,反码符号位不变,其他位取反。  补码:反码+1;

while(cin.get()!=’\n’);

cin.sync() ;  清空输入缓存区;

system(“pause”);  按任意键继续

system(“cls”);     清屏

swap(a,b);//交换数据或数组a.b;

字符大小写转换:  ch=ch^32;

C语言字符串’\’续行;

    1. other
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值