1、helloworld
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;// 以std::cout<<开始 以<< std::endl结束,中间打印出来。
//std是标准的意思c-out,读作standard-c-out
return 0;
}
2、输出加减乘和空格
#include <iostream>
using namespace std;
int main()
{
int x = 9;
int y = 6;
cout << endl;
cout<<x-y<<" "<<x*y<<x+y;//3, ,54,15
cout<<endl;
return 0;
}
3、预处理器编译指令#include
预处理器编译指令是向预处理器发出的命令,总是以#打头。#include<filename>是让预处理器获取指定文件,并将它放在编译指令所在的位置。iostream是一个标准的头文件,这里包含他是因为使用了std::cout将文字打印到屏幕上,而改头文件包含了std::cout的定义。
专业人员编写的c++应用程序中,包含的文件并非都是标准头文件。编写复杂的应用程序时,通常将其代码放在多个文件中,这使得需要在某些文件中包含其他文件。比如
#include "...路径\文件名"
这里使用引号而不是尖括号来包含自己创建的头文件,尖括号(<>)通常用于包含标准头文件。
4、程序主体main()
执行c++程序总是从main开始。声明main()时,总是在它的前面加上int,这是一种标准化约定,表示main()函数的返回类型位int。
在很多c++应用程序中都是用了类似这样的变种:
int main(int argc,char* argv[])
这符合标准且可以接受,因为其返回类型为int。括号内的内容是提供给程序的参数。该程序可能允许用户执行时提供命令行参数,如:
program.exe/DoSomethingSpecific
其中/DoSomethingSpecific是操作系统传递给程序的参数,以便在main中处理。
5、控制台输出
cout,读作c-out,是(conlse-out)的意思,将文字打印到屏幕上。cout是在标准名称空间中定义的一个流,因此这里使用了std::cout。这里使用流插入运算符<<将文本放到这个流中。std::endl用于换行,将其插入流中相当于插入回车。
6、c++流的优点
c++流的优点是,将类是的语义用于另一种类型的流时,将执行不同的操作,如插入到文件而不是控制台。因此流的用法非常直观,使用过一种流后,其他流(比如帮助将文本文件写入磁盘的fstream)使用起来就非常容易。
7、main的返回值
main返回一个整数给操作系统,根据应用程序的性质,这可能很有用,因为大多数操作系统都提供了查询公跟那个,让您能够获悉正常终止的应用程序的返回值。在很多情况下,一个应用程序被另一个应用程序启动,而父应用程序(启动者)想知道子应用程序(被启动者)是否成功地完成了其任务,程序员可以使用main()的返回值向父应用程序传递成功或错误状态。
根据约定,程序员在程序运行成功时返回0,并在出现错误时返回-1。然而,返回值为整数,程序员可以利用整个整数范围,指出众多不同的成功或失败状态。
8、名称空间
使用std::cout而不是cout,原因在于cout位于标准std名称空间中。名称控件有助于降低命名冲突的风险。
std名称空间用来调用获得ISO标准委员会批准,并在该名称空间中声明的函数、流和工具。
为了避免繁琐地在每个函数前面添加名称空间,可以使用声明:
#include <iostream>
int main()
{
using namespace std;
cout << "Hello World" << endl;
return 0;
}
9、std::cin输入(2.6)
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout<<"Enter an integer:";
int InputNumber;
cin>>InputNumber;
cout<<"Enter your name:";
string InputName;
cin>>InputName;
cout<<InputName<<" entered "<<InputNumber<<endl;
return 0;
}
10、c++变量类型的长度
#include <iostream>
//short,int,long,long long
//这里的单位是bit,也就是位,一个bit就是一个0或1
//8个bit是一个字节byte
//1个byte可以存一个英文字母,2个byte可以存一个汉字
int main()
{
using namespace std;
cout<<"Computing the size of some c++ inbuilt variable types"<<endl;
cout<<"Size of bool:"<<sizeof(bool)<<endl;//1
cout<<"Size of char:"<<sizeof(char)<<endl;//1
cout<<"Size of short int:"<<sizeof(short)<<endl;//2
cout<<"Size of unsigned short int:"<<sizeof(unsigned short)<<endl;//2
cout<<"Size of int:"<<sizeof(int)<<endl;//4
cout<<"Size of unsigned int:"<<sizeof(unsigned int)<<endl;//4
cout<<"Size of long:"<<sizeof(long)<<endl;//4
cout<<"Size of unsigned long int:"<<sizeof(unsigned long)<<endl;//4
cout<<"Size of long long:"<<sizeof(long long)<<endl;//8
cout<<"Size of unsigned long long:"<<sizeof(unsigned long long)<<endl;//8
cout<<"Size of float:"<<sizeof(float)<<endl;//4
cout<<"Size of double:"<<sizeof(double)<<endl;//8
cout<<"The output changes with compiler,hardware and OS"<<endl;
return 0;
}
11、auto,编译器的类型推断功能
#include <iostream>
using namespace std;
//编译的时候要加上"-std=c++11"
int main()
{
auto Flag=true;
auto Number=2500000000000;
cout<<"Flag="<<Flag;
cout<<",sizeof(Flag)="<<sizeof(Flag)<<endl;
cout<<"Number="<<Number;
cout<<",sizeof(Number)="<<sizeof(Number)<<endl;
return 0;
}
12、常量
这样声明:
const int 常量名 = 1;
13、枚举
enum RainbowColors
{
Violet = 0;// 可以定义值也可以不定义。如果不定义则会自动从0开始,每个item累加1。也可以对每个item设置值。
Indigo,
Blue,
Green,
Yellow,
Orange,
Red
};
14、静态数组
// 静态数组
int MyNumbers[5] = {0};//定义数组,5个元素,每个都为5
char MyCharacters[5];// 定义5个元素的数组但是没有赋值
int MyNumbers[5] = {20,30};// 给前2个赋值
int MyNumbers[] = {1,2,3};// 直接赋值可以不指定长度
15、动态数组
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> DynArrNums(3);// 原定义的数组长度为3
// DynArrNums[0] = 365;// 赋值,即使没有赋值,位置也一直留着
// DynArrNums[1] = -421;
// DynArrNums[2] = 789;
cout<< "Number of integers in array:"<<DynArrNums.size()<<endl;// 数组原长度
cout<< "Enter another number for the array"<<endl;
int AnotherNum = 0;
cin>>AnotherNum;
DynArrNums.push_back(AnotherNum);
cout<<"Number of integers in array:"<<DynArrNums.size()<<endl;
cout<<"Last element in array: ";
cout<< DynArrNums[DynArrNums.size()-1]<<endl;
return 0;
}
16、字符串字面量-c风格字符串
#include <iostream>
int main()
{
char SayHello[] = {'H','e','l','l','o',' ','W','o','r','l','d','\0'};// \0不能少,否则打印出来也有问题,少了这个,打印会跨越边界,导致程序崩溃
// std::cout<<"Hello World";// 这两种是等价的,
std::cout<<SayHello<<std::endl;
return 0;
}
c风格字符串充斥着危险性。
17、安全的标准c++字符串string
#include <iostream>
#include <string>
using namespace std;
int main()
{
string Greetings ("Hello std::string!");// 标准c++字符串
cout << Greetings << endl;//
cout << "Enter a line of text: "<< endl;
string FirstLine;
getline(cin,FirstLine);// 输入第一行数据
cout << "Enter another: " << endl;
string SecLine;
getline(cin,SecLine);// 输入第二行数据
cout << "Result of concatenation: " << endl;
string Concat = FirstLine+" "+SecLine;// 连接第一行和第二行
cout << Concat << endl;// 输出连接后的字符串
cout << "Copy of concatenation: " << endl;
string Copy;
Copy = Concat;
cout << Copy << endl;// 输出拷贝的连接后的字符串
cout << "Length of concat string: "<< Concat.length() << endl;// 统计连接后的字符串长度
return 0;
}
18、指针和引用
指针是一个变量,这个变量也占内存空间,指针存放的值指向内存地址。指针是一种指向内存单元的特殊变量。
(1)声明指针
通常将指针声明位指向特定的类型,如果int,这意味着指针包含的地址对应的内存单元存储了一个整数。
也可以将指针声明为指向一个内存块,这种指针被成为void指针。
声明:
指针类型 * 指针变量名;
与大多数变量一样,除非对指针进行初始化,否则它包含的值将是随机的。如果不初始化一个值,应该将指针初始化为NULL。
int * pInteger = NULL;
注意:除非对指针进行初始化,否则它包含的将是垃圾值。对指针来说,这种垃圾值是非常危险的,因为指针包含的值被视为地址。未初始化的指针可能导致程序访问非法内存单元,进而导致程序崩溃。
(2)引用运算符
变量,能够让您处理内存中的数据;
指针,存放的是内存的地址,而不是内存中的数据本身;
如果Varname是一个变量,那么&Varname将是存储该变量的内存地址。
比如声明:
int Age = 30;
那么&Age将是存储该变量的值(30)的内存的地址。
#include <iostream>
using namespace std;
int main()
{
int Age=30;
const double Pi=3.1416;
cout<<"Integer Age is at:"<< hex <<&Age<<endl;// Age存放在内存中,地址为:0x28ff20
cout<<"Double Pi is located at:"<< hex <<&Pi<<endl;// Pi存放在内存中,地址为:0x28ff20
// cout<<"test age:"<< dec << Age <<endl;//30
cout<<"test age2:"<< Age << endl;// 30
return 0;
}
(3)使用指针存储地址
指针这样使用:
先定义变量,再通过&获取变量的内存地址,再赋值给指针。
#include <iostream>
using namespace std;
int main()
{
int Age=30;// 变量赋值
int* pInteger=&Age;// 获取变量的指针
cout<<"Integer Age is at:"<<pInteger<<endl;
return 0;
}
(4)用解除引用运算符(*)访问指向的数据
#include <iostream>
using namespace std;
int main()
{
int Age = 30;
int DogsAge = 9;
cout<<"Integer Age="<<Age<<endl;
cout<<"Integer DogsAge="<<DogsAge<<endl;
int* pInteger = &Age;
cout<<"pInteger points to Age"<<endl;
cout<<"pInteger(16)="<<hex<<pInteger<<endl;// 指针的值(内存地址)为0x28ff28
cout<<"pInteger(10)="<<dec<<pInteger<<endl;// 指针的值(内存地址)为0x28ff28
cout<<"*pInteger(16)="<<hex<<*pInteger<<endl;// 对内存地址用星号则取出其值(16进制):1e
cout<<"*pInteger(10)="<<dec<<*pInteger<<endl;// 对内存地址用星号则取出其值(10进制):30
pInteger=&DogsAge;
cout<<"pInteger points to DogsAge now"<<endl;// 指针指向狗的年龄
cout<<"pInteger="<<hex<<pInteger<<endl;// 指针的值0x28ff24
cout<<"*pInteger="<<dec<<*pInteger<<endl;// 9
return 0;
}
(5)使用解除引用赋值
#include <iostream>
using namespace std;
int main()
{
int DogsAge=30;
cout<<"Initialized DogsAge="<<DogsAge<<endl;
int* pAge=&DogsAge;// 获得内存地址
cout<<"pAge points to DogsAge:"<<pAge<<endl;// 显示内存地址(第一次)0x28ff28
cout<<"Enter an age for your dog:";
cin>>*pAge;// 注意这上下两行是等价的,即:*pAge与*&DogsAge是等价的,他们都是指向内存相同的地方的值,修改之
// cin>>*&DogsAge;// 修改内存地址对应的值,输入15
cout<<"Input stored using pAge at "<<pAge<<endl;// 指针发生变化了没,没有0x28ff28
cout<<"Integer DogsAge="<<dec<<DogsAge<<endl;// 变量发生变化了没,变量变为输入值15
return 0;
}
(6)sizeof用于指针
#include <iostream>
using namespace std;
int main()
{
int Age=30;
double Pi=3.1416;
char SayYes='y';
int* pInt=&Age;
double* pDouble=&Pi
char* pChar=&SayYes;
cout<<"sizeof fundamental types -"<<endl;
cout<<"sizeof(int)="<<sizeof(int)<<endl;//4
cout<<"sizeof(double)="<<sizeof(double)<<endl;//8
cout<<"sizeof(char)="<<sizeof(char)<<endl;//1
//指针的sizeof与变量类型无关,这是显而易见的,因为这个指向的是地址的头,而不是整个物理地址
cout<<"sizeof pointers to fundamental types -"<<endl;
cout<<"sizeof(pInt)="<<sizeof(pInt)<<endl;//4
cout<<"sizeof(pDouble)="<<sizeof(pDouble)<<endl;//4
cout<<"sizeof(pChar)="<<sizeof(pChar)<<endl;//4
return 0;
}
指针的sizeof总是4字节,这是因为不管指针指向的内存单元是1字节还是8字节,存储指针所需的内存量都相同。如果使用32位编译器编译代码得到的,都是4字节;如果使用的是64位的编译器,并在64位系统上运行该程序,可能为8字节。
(7)动态内存分配
int Numbers[100];
此声明有问题,1:无法存储100个以上的元素;2、如果只存了1个数字,却预留了100个数字的存储空间,将降低系统的性能。
因此必须使用动态内存分配才可以提供系统的性能。
(8)使用new和delete动态分配和释放内存
Type * Pointer = new Type;//使用new来分配新的内存块,如果成功,将返回一个指针
需要为多个元素分配内存,还可以指定要为多少个元素分配:
Type * Pointer = new Type[NumElements];//请求为NumElements个元素的分配内存
int * pNumber = new int;// 获得一个整型的指针
int * pNumbers = new int[10];// 获取一个指向10个整型的内存块的指针
使用new分配的内存最终都需要使用对应的delete进行释放:
Type * Pointer = new Type;
delete Pointer;//释放内存
这种规则也适用于为多个元素分配的内存:
Type * Pointer = new Type[NumElements];
delete[] Pointer;//释放整个内存块
#include <iostream>
using namespace std;
int main()
{
int* pAge=new int;// new一个指针,指针名称为pAge
cout<<"Enter your dog's age:";
cin>>*pAge;// 为此指针赋值,10
cout<<"Age="<<*pAge<<" is stored at "<<hex<<pAge<<endl;// Age的值为10,他的指针是0x5d1580
delete pAge;//只能delete new产生的指针,而非所有指针,删除此指针
cout<<"test Age="<<dec<<*pAge<<" is stored at "<<pAge<<endl;//地址还在但是值已经变了,删了之后,值已经变为6099224,但是指针还是一样0x5d1580
return 0;
}
(9)拷贝到指针指定的地址里面
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main()
{
cout<<"Enter your name:";
string Name;
cin>>Name;//输入一个字符串
int CharsToAllocate=Name.length()+1;//计算这个字符串的长度并+1
char* CopyOfName=new char[CharsToAllocate];//创建一个指针,指向一个元素类型为char的内存地址块,并指定了长度为上一步所计算出来的长度
strcpy(CopyOfName,Name.c_str());// 将字符拷贝放到此地址内
cout<<"Dynamically allocated buffer contains:"<<CopyOfName<<endl;//buffer就是内存
delete[] CopyOfName;
return 0;
}
(10)、通过移动指针赋值,以及通过移动指针读取值
#include <iostream>
using namespace std;
int main()
{
cout<<"How many integers you wish to enter?";
int InputNums=0;
cin>>InputNums;// 输入数字
int* pNumbers=new int [InputNums];// 初始化一个数组并返回指针
int* pCopy=pNumbers;// 定义另一个指针并让其等于上面那个指针
cout<<"Successfully allocated memory for "<<InputNums<<" integers"<<endl;// 成功初始化n个整型
for(int Index=0;Index<InputNums;++Index)
{
cout<<"Enter numbers "<<Index<<":";// 输入的数字序号:n
cin>>*(pNumbers+Index);//指针在加index,就是在移动内存块的位置
}
cout<<"Displaying all numbers input: "<<endl;
for(int Index=0;Index<InputNums;++Index)
{
//cout<<*(pCopy++)<<" ";
cout<<*(pNumbers++)<<" ";//此处会修改指针,如果不用copy的指针,而直接用那个new的指针,它已经变化,delete也已经不同...
}
cout<<endl;
// 注意指针操作:1、申请时是数组,删除时也是数组;2、申请的地址是a,删除的地址也必须是a,否则内存泄漏,如须移动请用copy
//delete[] pNumbers;//这个要不要delete都是一样的,因为指针已经被移动。之所以上面要移动指针拷贝,而不用移动这个指针本身,是因为在delete的时候,希望delete的是一个不变的值
cout<<"after delete:\n";
cout<<"addr:"<<pNumbers<<"\n";//指针是还存在的,就是说内存地址是存在的,但是内存中并没有值
cout<<"value:"<<dec<<*pNumbers<<endl;//此时指针指向已经没有值,是0
return 0;
}
(11)、const用于指针
<1>常量指针:在星号前加const,即不能通过*p修改指针指向的内存的值。
#include <iostream>
using namespace std;
int main()
{
int HoursInDay = 24;// 定义一个变量
int const * pInteger = &HoursInDay;// 变量的指针地址,这里最奇怪的是,*pInteger是常量不可修改,但是HoursInDay可以修改
cout<< pInteger <<endl;// 0x28ff24
cout<< *pInteger <<endl;// 24
//________________________第一次修改:修改变量然后看指针指向的值有没有变化____________________
HoursInDay = 25;
cout<< pInteger <<endl;// 0x28ff24,指针的地址没有变化
cout<< *pInteger <<endl;// 25,指针的值是有变化的,就是直接操作*pInteger来修改值是不可以的,但是修改变量是可以的
//________________________第二次修改:修改指针的指向___________________________
int MonthsInYear = 12;// 定义另一个变量
pInteger = &MonthsInYear;// ok,将指针指向另一个地址
// *pInteger = 13;// 这个赋值不会成功,因为*pInteger是一个常量
// int * pAnotherPointerToInt = pInteger;// 这个赋值不会成功,因为不能将一个常量指针赋值给变量指针
//int const * pAnotherPointerToInt = pInteger;// ok
cout<< pInteger <<endl;// 0x28ff20 地址已经发生了变化
cout<< *pInteger <<endl;// 12,值也发生变化,但是这个值发生变化是通过修改指向发生的,而非*pInteger直接修改原地址的值
}
<2>指针常量:在星号后加const,不能修改指针地址,即此指针不可以指向别的地址
#include <iostream>
using namespace std;
int main()
{
int DaysInMonth = 30;
int * const pDaysInMonth = &DaysInMonth;
*pDaysInMonth = 30;//ok
int DaysInLunarMonth = 28;
pDaysInMonth = &DaysInLunarMonth;// 不可以,此指针常量不可修改指针地址
}
<3>双常量
#include <iostream>
using namespace std;
int main()
{
int HoursInDay = 24;
int const * const pHoursInDay = &HoursInDay;
// *pHoursInDay = 25;// 不可以
int DaysInMonth = 30;
// pHoursInDay = &DaysInMonth;// 不可以
return 0;
}
(12)、指针传递给函数
#include <iostream>
using namespace std;
// void CalcArea(const double * const pPi,//pi指针值和地址都不能改变
// const double * const pRadius,//半径指针值和地址都不能改变
// double * const pArea)//面积指针值可以改变地址不能改变
// {
// if (pPi && pRadius && pArea)
// {
// *pArea = (*pPi) * (*pRadius) * (*pRadius);
// }
// }
void CalcArea(double const * pPi,double * pRadius,double * pArea)
{
if (pPi && pRadius && pArea)// 检查有效性
{
*pArea = (*pPi) * (*pRadius) * (*pRadius);
}
}
int main()
{
const double Pi = 3.1416;//因为这里是常量,所以他的指针的值不能改(而非指针变量)
cout << "Enter radius of circle: ";
double Radius = 0;
cin >> Radius;
double Area = 0;
CalcArea(&Pi, &Radius, &Area);
cout << "Area is = " << Area << endl;
return 0;
}
(13)、数组和指针的相似之处
<1>数组的引用可以直接赋值给指针
#include <iostream>
using namespace std;
int main()
{
int MyNumbers[5];// 可以说这个MyNumbers就是一个指针
int * pNumbers = MyNumbers;//这个引用他返回了第一个元素的指针地址
cout << "pNumbers=" << hex << pNumbers << endl;// 0x28ff18
cout << "&MyNumbers[0]=" << &MyNumbers[0] << endl;// 0x28ff18
}
<2>分别用数组下标和指针访问数组的值
#include <iostream>
using namespace std;
int main()
{
const int ARRAY_LEN = 5;
int MyNumbers[ARRAY_LEN]={24,-1,365,-999,2011};
// int * pNumbers = MyNumbers;
// cout << "Displaying array using pointer syntax,operator*" << endl;
// for(int Index = 0; Index < ARRAY_LEN;++Index)
// cout << "Element " << Index << " = " << * (MyNumbers + Index) << endl;
// cout << "Displaying array using pointer with array syntax,operator[]" << endl;
// for(int Index = 0; Index < ARRAY_LEN;++Index)
// cout << "Element " << Index << " = " << pNumbers[Index] << endl;
int * pNumbers = &(MyNumbers[1]);
cout << "Displaying array using pointer syntax,operator*" << endl;
for(int Index = 0; Index < ARRAY_LEN-1;++Index)
cout << "Element " << Index << " = " << * (MyNumbers + Index) << endl;// 24,-1,365,-999
cout << "Displaying array using pointer with array syntax,operator[]" << endl;
for(int Index = 0; Index < ARRAY_LEN-1;++Index)
cout << "Element " << Index << " = " << pNumbers[Index] << endl;// -1,365,-999,2011使用下标取出来就是值
}
(14)、无效指针
#include <iostream>
using namespace std;
int main()
{
int * pTemperature;// 没有初始化一个指针(这样不好),在这里仅仅是定义,但是没有完成初始化
cout << "Is it sunny (y/n)?" << endl;
char UserInput = 'y';
cin >> UserInput;
if (UserInput == 'y')
{
pTemperature = new int;// 初始化
*pTemperature = 30;
}
cout << "Temperature is: " << *pTemperature;// 如果按的是n,则指针还未初始化,程序崩溃
delete pTemperature;// 如果一个指针没有new,也是不可以delete的,另外指针多个拷贝只需delete一个,应避免指针有很多拷贝
return 0;
}
(15)、指针编程最佳实践
<1>务必初始化指针变量,否则它将包含垃圾值。这些垃圾值被解读为地址。如果不能将指针初始化为new返回的有效地址或其他有效变量,可将其初始化为NULL;
<2>使用指针前,务必检查它是否为NULL,这样,如果指针声明后未赋给有效地址,但声明时将其初始化为NULL了,就不会引起无效指针的问题了;
<3>务必仅在指针有效时才使用它,否则程序可能崩溃;
<4>对于使用new分配的内存,一定要记得使用delete进行释放,否则应用程序将泄漏内存,进而降低系统的性能;
<5>使用delete释放内存块或指针后,不要访问它;
<6>不要对同一个内存地址调用delete多次;
<7>使用动态分配的内存块后,不要忘了对其调用delete,以免内存泄漏。
#include <iostream>
using namespace std;
int main()
{
cout << "Is it sunny(y/n)? ";
char UserInput = 'y';
cin >> UserInput;
if (UserInput == 'y')
{
int * pTemperature = new int;
* pTemperature = 30;
//____________delete前调用_______________
cout << "pTemperature is: " << pTemperature << endl;// 0x3f1840
cout << "Temperature is: " << * pTemperature << endl;// 30
delete pTemperature;
//____________delete后调用_______________
cout << "pTemperature is: " << pTemperature << endl;// 0x3f1840,指针删除后,他包含的这个地址还是在的,但是地址指向的值已经不在,内存已经释放
cout << "Temperature is: " << * pTemperature << endl;// 4157184,这是一个垃圾值
delete pTemperature;// 再次调用删除并不会引起什么后果
}
return 0;
}
(16)、处理new失败
<1>异常处理
#include <iostream>
using namespace std;
int main()
{
try
{
int * pAge = new int [53687000009101];
delete [] pAge;
}
catch(bad_alloc)
{
cout << "Memory allocation failed. Ending program" << endl;
}
return 0;
}
<2>用nothrow会返回空指针
#include <iostream>
using namespace std;
int main()
{
int * pAge = new(nothrow) int[234254350044534];//在mac下还是抛出异常
if (pAge)
{
delete [] pAge;
}else
{
cout << "Memory allocation failed. Ending program" << endl;
}
return 0;
}
(17)、引用
<1>引用,就是值类型的变量,通过添加&可以变成引用传递;对引用添加&则可以取到对应的内存地址
#include <iostream>
using namespace std;
int main()
{
int Original = 30;// 等同于 *pOriginal
cout << "Original = " << Original << endl;// 30,值
cout << "Original is at address: " << hex << &Original <<endl;// 0x28ff24,地址,加&相当于给*pOriginal去掉星号
int & Ref = Original;// 注意这个加了个引用标志,表示此Ref与Original的引用相同,因为int是值类型,如果没这个标志则值相同,但是它变成一个新值,有自己的引用
// int Ref = Original;
cout << "Ref is at address: " << hex << &Ref << endl;// 0x28ff24,地址,
int & Ref2 = Ref;
cout << "Ref2 is at address: " << hex << &Ref2 << endl;// 0x28ff24,地址
cout << "Ref2 gets value, Ref2 = " << dec << Ref2 << endl;// 30,值
return 0;
}
<2>传递引用
传递引用在c#里也有类似的,比如一个局部变量,传递引用至一个函数里,经过一番计算,都不用return一个值回来,这个局部变量可能已经改变,我们使用这个新值即可
引用传递最大的好处是避免形参复制,极大提高性能(传递一个数字过去,在新函数那里会重新自动new那些数字)
#include <iostream>
using namespace std;
void ReturnSquare(int & num)
{
num *= num;
}
int main()
{
cout << "Enter a number you wish to square: ";
int Number = 0;
cin >> Number;
ReturnSquare(Number);
cout << "Square is: " << Number << endl;
return 0;
}
<3>引用加const
#include <iostream>
int main()
{
int Original = 30;
int const & ConstRef = Original;
ConstRef =40;//not allowed.引用被加上const,则不可被赋值
int & Ref2 = ConstRef;//not allowed.被加上const的引用不可被赋值给没有加const的新引用
int const & ConstRef2 = ConstRef;//ok.但是可以被赋值给同样加了const的新引用
}
<4>通过添加const控制传递参数可被修改以及不可被修改
#include <iostream>
using namespace std;
void CalculateSquare(const int & Number,int & Result)
{
Result = Number * Number;// Number不可被改变,Result可以被改变
}
int main()
{
cout << "Enter a number you wish to square: ";
int Number = 0;
cin >> Number;
int Square = 0;
CalculateSquare(Number,Square);
cout << Number << "^2 = " << Square << endl;
return 0;
}
19、STL(standard template library)标准模版库
(1)迭代器访问向量数组
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector <int> vecIntegerArray;// 定义数组(向量)
vecIntegerArray.push_back(50);
vecIntegerArray.push_back(2991);
vecIntegerArray.push_back(23);
vecIntegerArray.push_back(9999);
cout<<"The contents of the vector are:"<<endl;
// vector <int>::iterator iArrayWalker = vecIntegerArray.begin();// 用迭代器访问
auto iArrayWalker = vecIntegerArray.begin();// 可以简化为这样
while(iArrayWalker != vecIntegerArray.end())
{
cout<<*iArrayWalker<<endl;
++iArrayWalker;
}
}
(2)初始化字符串
#include <iostream>
#include <string>
using namespace std;
int main()
{
const char * constCStyleString = "Hello String!";// 初始化一个c语言风格的字符串
std::string strFromConst (constCStyleString);// 这样可以
//std::string strFromConst = constCStyleString;// 这样也可以
std::string str2 ("HelloString!");//一句话代替就这样
// stl string类构造函数自动完成字符串长度的设定和内存分配
cout<<str2<<endl;
}
#include <string>
#include <iostream>
int main()
{
using namespace std;
const char * constCStyleString = "Hello String!";
cout << "Constant string is: " << constCStyleString << endl;
std::string strFromConst (constCStyleString);
cout << "strFromConst is: " << strFromConst << endl;
std::string str2 ("Hello String!");
std::string str2Copy (str2);// 从已有的string生成string
cout << "str2Copy is: " << str2Copy << endl;
std::string strPartialCopy (constCStyleString,5);// 取前5个字符
cout << "strPartialCopy is: " << strPartialCopy << endl;
std::string strRepeatChars (10,'a');// 生成10个重复的a,即"aaaaaaaaaa"
cout << "strRepeatChars is: " << strRepeatChars << endl;
return 0;
}
(3)访问字符串
#include <string>
#include <iostream>
int main()
{
using namespace std;
string strSTLString("Hello String");
// 用下标法访问
cout<<"Displaying the elements in the string using array-syntax:"<<endl;
for(size_t nCharCounter = 0;nCharCounter<strSTLString.length();++nCharCounter)
{
cout<<"Character ["<<nCharCounter<<"] is: ";
cout<<strSTLString[nCharCounter]<<endl;
}
cout<<endl;
cout<<"Displaying the contents of the string using iterators: "<<endl;
int charOffset = 0;
string::const_iterator iCharacterLocator;
for(iCharacterLocator = strSTLString.begin();iCharacterLocator!=strSTLString.end();++iCharacterLocator)
{
cout<<"Character ["<<charOffset++<<"] is:";
cout<<*iCharacterLocator<<endl;
}
cout<<endl;
}
(4)连接字符串
#include <string>
#include <iostream>
int main()
{
using namespace std;
string strSample1("Hello");
string strSample2(" String!");
strSample1 += strSample2;//用+连接字符串
cout<<strSample1<<endl<<endl;
string strSample3(" Fun is not needing to use pointers!");
strSample1.append(strSample3);// 用append连接字符串
cout<<strSample1<<endl<<endl;
const char*constCStyleString = " You however still can!";
strSample1.append(constCStyleString);// append也可以用于c风格字符串
cout<<strSample1<<endl;
return 0;
}
(5)查找字符串
#include <string>
#include <iostream>
int main()
{
using namespace std;
string strSample("Good day String! Today is beautiful!");
cout<<"The sample string is: "<<endl;
cout<<strSample<<endl<<endl;
size_t charPos = strSample.find("day",0);
// 根据返回的值来进行判断,如果是string::npos即-1,没中找到;否则找到
if (charPos!=string::npos)
cout<<"First instance of \"day\" was found at position "<<charPos;
else
cout<<"Substring not found."<<endl;
cout<<endl<<endl;
cout<<"Locating all instances of substring \"day\""<<endl;
size_t SubstringPos = strSample.find("day",0);
while(SubstringPos!=string::npos)
{
cout<<"\"day\"found at position "<< SubstringPos<<endl;
// 找到之后再将定位往前移继续寻找
size_t nSearchPosition = SubstringPos+1;
SubstringPos = strSample.find("day",nSearchPosition);
}
return 0;
}
(6)擦除,删除
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
using namespace std;
//擦除,删除
string strSample("Hello String! Wake up to a beautiful day!");
cout<<"The Original sample string is: "<<endl;
cout<<strSample<<endl<<endl;
cout<<"The Original sample addr is: "<<endl;
cout<<&strSample<<endl<<endl;//0x28fefc
cout<<"Truncating the second sentence: "<<endl;
strSample.erase(0,5);// 删除从a开始删除b个
cout<<strSample<<endl<<endl;
cout<<"Truncated the smaple addr is: "<<endl;
cout<<&strSample<<endl<<endl;//0x28fefc,地址是不变的
// 擦除指定字符
string::iterator iCharS = find(strSample.begin(),strSample.end(),'S');
cout<<"Erasing character 'S' from the sample string: "<<endl;
if (iCharS!=strSample.end())// 这个即使是最后一个字符也是可以删掉的,因为这里的end指的是\0
strSample.erase(iCharS);
cout<<strSample<<endl<<endl;
// 擦除所有
cout<<"Erasing a range between begtin() and end(): "<<endl;
strSample.erase(strSample.begin(),strSample.end());
if (strSample.length()==0)
cout<<"The string is empty"<<endl;
return 0;
}
(7)字符串反转
#include <string>
#include <iostream>
#include <algorithm>
int main()
{
using namespace std;
string strSample("Hello String! We will reverse you!");
cout<<"The original sample string is: "<<endl;
cout<<strSample<<endl<<endl;
reverse(strSample.begin(),strSample.end());
cout<<"After applying the std::reverse algorithm: "<<endl;
cout<<strSample<<endl;
return 0;
}
(8)转大小写
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
cout<<"Please enter a string for case-convertion:"<<endl;
cout<<"> ";
string strInput;
getline(cin,strInput);
cout<<endl;
transform(strInput.begin(),strInput.end(),strInput.begin(),::toupper);
cout<<"The string converted to upper case is: "<<endl;
cout<<strInput<<endl<<endl;
transform(strInput.begin(),strInput.end(),strInput.begin(),::tolower);
cout<<"The string converted to lower case is: "<<endl;
cout<<strInput<<endl<<endl;
return 0;
}
20、vector
(1)实例化
#include <vector>
int main()
{
std::vector <int> vecIntegers;// 用默认构造函数实例化
std::vector <int> vecWithTenElements(10);// 实例化包含10个元素,注意并没有限制最终大小只能为10
std::vector <int> vecWithTenInitializedElements(10,90);//
std::vector <int> vecArrayCopy(vecWithTenInitializedElements);// 复制
std::vector <int> vecSomeElementsCopied(vecWithTenElements.cbegin(),vecWithTenElements.cbegin()+5);// 复制前5个元素
return 0;
}
(2)push_back在末尾插入
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int> vecIntegers;
// 通过push_back初始化
vecIntegers.push_back(1);
vecIntegers.push_back(34);
vecIntegers.push_back(53);
vecIntegers.push_back(77);
// // 直接初始化1
// vector <int> vecIntegers = {23,45,3,45};
// 直接初始化2
// vector <int> vecIntegers{33,56,76,5};
cout<<"The vector contains ";
cout<<vecIntegers.size()<<" Elements"<<endl;
return 0;
}
(3)insert在指定位置插入
#include <vector>
#include <iostream>
using namespace std;
void DisplayVector(const vector<int>& vecInput)
{
for(auto iElement = vecInput.cbegin();iElement!=vecInput.cend();++iElement)
{
cout<<*iElement<<' ';
}
cout<<endl;
}
int main()
{
vector <int> vecIntegers(4,90);//90,90,90,90
cout<<"The initial contents of the vector: ";
DisplayVector(vecIntegers);
vecIntegers.insert(vecIntegers.begin(),25);//在头部插入一个25
vecIntegers.insert(vecIntegers.end(),2,45);//在尾部插入2个45
cout<<"Vector after inserting elements at beginning and end: ";
DisplayVector(vecIntegers);
vector <int> vecAnother(2,30);//30,30
vecIntegers.insert(vecIntegers.begin()+1,vecAnother.begin(),vecAnother.end());// 在开头的第2个元素的位置,插入另一个数组的从头到尾所有元素
cout<<"Vector after inserting contents from another vector: ";
cout<<"in the middle:"<<endl;
DisplayVector(vecIntegers);
return 0;
}
(4)访问元素
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector <int> vecIntegerArray;
vecIntegerArray.push_back(4);
vecIntegerArray.push_back(6);
vecIntegerArray.push_back(80);
vecIntegerArray.push_back(34);
for(size_t Index = 0;Index < vecIntegerArray.size();++Index)
{
cout<<"Element["<<Index<<"]= ";
//cout<<vecIntegerArray[Index]<<endl;
cout<<vecIntegerArray.at(Index)<<endl;
}
vecIntegerArray[2] = 2011;// 直接用下标设置值
cout<<"After replacement: "<<endl;
// cout<<"Element[2]= "<<vecIntegerArray[2]<<endl;
// 也可以用at()取元素值,他会判断是否越界
cout<<"Element[2]= "<<vecIntegerArray.at(2)<<endl;
return 0;
}
(5)使用指针访问
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector <int> vecIntegers;
vecIntegers.push_back(34);
vecIntegers.push_back(54);
vecIntegers.push_back(59);
vecIntegers.push_back(23);
auto iElementLocator = vecIntegers.begin();
while(iElementLocator != vecIntegers.end())
{
size_t Index = distance(vecIntegers.begin(),iElementLocator);// 从0开始,计算他在什么位置
cout<<"Element at position ";
cout<<Index<<" is: "<<*iElementLocator<<endl;
++iElementLocator;
}
return 0;
}
(6)删除元素
#include <iostream>
#include <vector>
using namespace std;
template <typename T>// 如果这个参数用了T,则要声明这个template;如果定义为int则不需要
void DisplayVector(const vector<T>& vecInput)
{
for(auto iElement = vecInput.cbegin();iElement != vecInput.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
vector <int> vecIntegers;
vecIntegers.push_back(34);
vecIntegers.push_back(45);
vecIntegers.push_back(65);
vecIntegers.push_back(33);
cout<<"Vector contains "<<vecIntegers.size()<<" elements: ";
DisplayVector(vecIntegers);//34 45 65 33
vecIntegers.pop_back();// 删除最后一个
cout<<"After a call to pop_back()"<<endl;
cout<<"Vector contains "<<vecIntegers.size()<<" elements: ";
DisplayVector(vecIntegers);//34 45 65
return 0;
}
(7)长度和容量
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector <int> vecIntegers(5);
// 初始化的时候,他的长度和容量都等于初始值
cout<<"Vector of integers was instantiated with "<<endl;
cout<<"Size: "<<vecIntegers.size();//5
cout<<", Capacity:"<<vecIntegers.capacity()<<endl;//5
vecIntegers.push_back(666);
// push之后,长度+1,容量翻倍
cout<<"After inserting an additional element..."<<endl;
cout<<"Size: "<<vecIntegers.size();//6
cout<<", Capacity: "<<vecIntegers.capacity()<<endl;//10
vecIntegers.push_back(777);
// 继续push,长度+1,容量在还够用的情况下不变
cout<<"After inserting yet another element..."<<endl;
cout<<"Size: "<<vecIntegers.size();//7
cout<<", Capacity: "<<vecIntegers.capacity()<<endl;//10
return 0;
}
21、deque(17.4)
(1)在开头插入和删除
#include <deque>
#include <iostream>
#include <algorithm>
int main()
{
using namespace std;
deque<int>dqIntegers;
dqIntegers.push_back(3);
dqIntegers.push_back(4);
dqIntegers.push_back(5);
dqIntegers.push_front(2);
dqIntegers.push_front(1);
dqIntegers.push_front(0);
cout<<"The contents of the deque after inserting elements ";
cout<<"at the top and bottom are:"<<endl;
for(size_t nCount = 0;nCount<dqIntegers.size();++nCount)
{
cout<<" Element ["<<nCount<<"]=";
cout<<dqIntegers[nCount]<<endl;// 0 1 2 3 4 5
}
cout<<endl;
dqIntegers.pop_front();// 从头删除一个
dqIntegers.pop_back();// 从尾删除一个
cout<<"The contents of the deque after erasing an element ";
cout<<"from the top and bottom are:"<<endl;
for(auto iElementLocator = dqIntegers.begin();iElementLocator != dqIntegers.end();++iElementLocator)
{
size_t Offset = distance(dqIntegers.begin(),iElementLocator);
cout<<"Element["<<Offset<<"]="<<*iElementLocator<<endl;// 1 2 3 4
}
return 0;
}
22、list
(1)初始化list
#include <list>
#include <vector>
int main()
{
using namespace std;
list <int> listIntegers;// 初始化一个空列表
list<int>listWith10Integers(10);// 初始化一个有10个int的列表
list<int>listWith4IntegerEach99(4,99);// 初始化一个有4个int的列表并赋值每个值为99
list<int>listCopyAnother(listWith4IntegerEach99);// 从一个已存在的list拷贝
vector<int>vecIntegers(10,2011);// 一个vector,10个元素,值都为2011
list<int>listContainsCopyOfAnother(vecIntegers.cbegin(),vecIntegers.cend());// 从vector拷贝到list
return 0;
}
(2)在开头或末尾插入元素
#include <list>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
{
cout<<*iElement<<' ';
}
cout << endl;
}
int main()
{
std::list<int>listIntegers;
listIntegers.push_front(10);
listIntegers.push_front(2011);
listIntegers.push_back(-1);
listIntegers.push_back(9999);
DisplayContents(listIntegers);
return 0;
}
(3)insert
#include <list>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
list<int>listIntegers1;
listIntegers1.insert(listIntegers1.begin(),2);//在list1的头部插入2
listIntegers1.insert(listIntegers1.begin(),1);//在list1的头部插入1
listIntegers1.insert(listIntegers1.end(),3);//在list1的尾部插入3
cout<<"The contents of list 1 after inserting elements:"<<endl;
DisplayContents(listIntegers1);// 1 2 3
list<int>listIntegers2;
listIntegers2.insert(listIntegers2.begin(),4,0);//在list2的头部插入4个元素,值都为0
cout<<"The contents of list 2 after inserting '";
cout<<listIntegers2.size()<<"' elements of a value:"<<endl;
DisplayContents(listIntegers2);// 0 0 0 0
list<int>listIntegers3;
listIntegers3.insert(listIntegers3.begin(),listIntegers1.begin(),listIntegers1.end());// 在list3的头部插入所有list1的元素
cout<<"The contents of list 3 after inserting the contents of ";
cout<<"list 1 at the beginning:"<<endl;
DisplayContents(listIntegers3);// 1 2 3
listIntegers3.insert(listIntegers3.end(),listIntegers2.begin(),listIntegers2.end());// 在list3的尾部插入所有list2的元素
cout<<"The contents of list 3 after inserting ";
cout<<"the contents of list 2 at the beginning:"<<endl;
DisplayContents(listIntegers3);//1 2 3 0 0 0 0
return 0;
}
(4)删除
#include <list>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
list<int>listIntegers;
listIntegers.push_back(4);
listIntegers.push_front(3);
listIntegers.push_back(5);
auto iValue2 = listIntegers.insert(listIntegers.begin(),2);// 2 3 4 5,返回index:0
cout<<"Initial contents of the list:"<<endl;
DisplayContents(listIntegers);
listIntegers.erase(listIntegers.begin(),iValue2);// 这个相当于删除范围0-0
cout<<"Contents after erasing a range of elements:"<<endl;
DisplayContents(listIntegers);// 2 3 4 5
cout<<"After erasing element '"<<*iValue2<<"':"<<endl;
listIntegers.erase(iValue2);// 删除index:0
DisplayContents(listIntegers);// 3 4 5
listIntegers.erase(listIntegers.begin(),listIntegers.end());
cout<<"Number of elements after erasing range: ";
cout<<listIntegers.size()<<endl;// 全删,size为0
return 0;
}
(5)反转
#include <list>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
list<int>listIntegers;
listIntegers.push_front(4);
listIntegers.push_front(3);
listIntegers.push_front(2);
listIntegers.push_front(1);
listIntegers.push_front(0);
listIntegers.push_back(5);
cout<<"Initial contents of the list:"<<endl;
DisplayContents(listIntegers);// 012345
listIntegers.reverse();
cout<<"Contents of the list after using reverse():"<<endl;
DisplayContents(listIntegers);//543210
return 0;
}
(6)排序
#include <list>
#include <iostream>
using namespace std;
bool SortPredicate_Descending(const int&lsh,const int&rsh)
{
return (lsh>rsh);// 升序还是降序取决于这个是大于号还是小于号,如果>则降序,因为左边大
}
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
list<int> listIntegers;
listIntegers.push_front(444);
listIntegers.push_front(2011);
listIntegers.push_front(-1);
listIntegers.push_front(0);
listIntegers.push_back(-5);
cout<<"Initial contents of the list are:"<<endl;
DisplayContents(listIntegers);//0 -1 2011 444 -5
listIntegers.sort();
cout<<"Order of elements after sort():"<<endl;
DisplayContents(listIntegers);// -5 -1 0 444 2011 升序排列
listIntegers.sort(SortPredicate_Descending);
cout<<"Order of elements after sort() with a predicate:"<<endl;
DisplayContents(listIntegers);//2011 444 0 -1 -5 降序排列
return 0;
}
(7)对包含对象的list进行排序和删除
#include <list>
#include <string>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<endl;
cout<<endl;
}
struct ContactItem
{
string strContactsName;
string strPhoneNumber;
string strDisplayRepresentation;
// 此构造函数把名字跟电话连接起来
ContactItem(const string&strName,const string&strNumber)
{
strContactsName = strName;
strPhoneNumber = strNumber;
strDisplayRepresentation = (strContactsName+": "+strPhoneNumber);
}
// 此等于运算符是用来删除的
bool operator == (const ContactItem&itemToCompare) const
{
return (itemToCompare.strContactsName == this->strContactsName);
}
// sort 会检查是否定义小于运算符
bool operator < (const ContactItem&itemToCompare) const
{
return (this->strContactsName<itemToCompare.strContactsName);
}
operator const char*() const
{
return strDisplayRepresentation.c_str();// 这个相当于tostring?
}
};
bool SortOnPhoneNumber(const ContactItem& item1,const ContactItem&item2)
{
return (item1.strPhoneNumber<item2.strPhoneNumber);// 降序
}
int main()
{
list<ContactItem>Contacts;
Contacts.push_back(ContactItem("Jack Welsch","+1 3454 433 567"));
Contacts.push_back(ContactItem("Bill Gates","+1 3455 555 745"));
Contacts.push_back(ContactItem("Angela Meerkel","+1 4355 456 256"));
Contacts.push_back(ContactItem("Vladimir Putin","+1 3455 533 952"));
Contacts.push_back(ContactItem("Manmohan Singn","+1 5433 694 230"));
Contacts.push_back(ContactItem("Barack Obama","+1 6445 244 866"));
cout<<"List in initial order: "<<endl;
DisplayContents(Contacts);// 初始列表"Jack Welsch:+1 3454 433 567"...
Contacts.sort();
cout<<"After sorting in alphabetical order via operator:"<<endl;
DisplayContents(Contacts);// 默认排序之后就用首字母的顺序排列:A B B J M V
Contacts.sort(SortOnPhoneNumber);
cout<<"After sorting in order of phone numbers via predicate:"<<endl;
DisplayContents(Contacts);// 按电话号码排序就是:3454,3455,3455,4355,5433,6445
cout<<"After erasing Putin from the list:";
Contacts.remove(ContactItem("Vladimir Putin",""));
DisplayContents(Contacts);// 删除之后就剩5个
return 0;
}
(8)forward_list
#include <forward_list>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
forward_list<int> flistIntegers;
flistIntegers.push_front(0);
flistIntegers.push_front(2);
flistIntegers.push_front(2);
flistIntegers.push_front(4);
flistIntegers.push_front(3);
flistIntegers.push_front(1);
cout<<"Contents of forward_list: "<< endl;
DisplayContents(flistIntegers);// 134220
flistIntegers.remove(2);
flistIntegers.sort();
cout<<"Contents after removing 2 and sorting: "<<endl;
DisplayContents(flistIntegers);//0134
return 0;
}
20、STL集合类
(1)实例化set、multiset
#include <set>
template<typename T>
struct SortDescending
{
bool operator()(const T&lhs,const T&rhs) const
{
return (lhs>rhs);
}
};
int main()
{
using namespace std;
set<int> setIntegers1;// 简单的int集合(默认排序),默认升序
multiset<int> msetIntegers1;
set<int,SortDescending<int>> setIntegers2;//用户定义的排序,此为降序
multiset<int,SortDescending<int>> msetIntegers2;
set<int> setIntegers3(setIntegers1);// 从另一个集合复制过来
multiset<int> msetIntegers3(setIntegers1.cbegin(),setIntegers1.cend());
return 0;
}
(2)插入元素
#include <set>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
set<int> setIntegers;
multiset<int> msetIntegers;
setIntegers.insert(60);
setIntegers.insert(-1);
setIntegers.insert(3000);
cout<<"Writing the contents of the set to the screen"<<endl;
DisplayContents(setIntegers);//-1,60,3000
msetIntegers.insert(setIntegers.begin(),setIntegers.end());
msetIntegers.insert(3000);
cout<<"Writing the contents of the multiset to the screen"<<endl;
DisplayContents(msetIntegers);//-1,60,3000,3000
cout<<"Number of instances of '3000' in the multiset are:'";
cout<<msetIntegers.count(3000)<<"'"<<endl;//统计有多少个3000,2个
return 0;
}
(3)查找
#include <set>
#include <iostream>
using namespace std;
int main()
{
set<int> setIntegers;
setIntegers.insert(43);
setIntegers.insert(78);
setIntegers.insert(-1);
setIntegers.insert(124);
for(auto iElement = setIntegers.cbegin();iElement!=setIntegers.cend();++iElement)
cout<<*iElement<<endl;//-1,43,78,124
auto iElementFound = setIntegers.find(-1);// 寻找-1
if (iElementFound != setIntegers.end())
cout<<"Element "<<*iElementFound<<" found!"<<endl;// 找到
else
cout<<"Element not found in set!"<<endl;
auto iAnotherFind = setIntegers.find(12345);
if(iAnotherFind != setIntegers.end())
cout<<"Element "<<*iAnotherFind<<" found!"<<endl;
else
cout<<"Element 12345 not found in set!"<<endl;// 没找到
return 0;
}
(4)删除
#include <set>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
typedef multiset<int> MSETINT;
int main()
{
MSETINT msetIntegers;
msetIntegers.insert(43);
msetIntegers.insert(78);
msetIntegers.insert(78);
msetIntegers.insert(-1);
msetIntegers.insert(124);
cout<<"multiset contains "<<msetIntegers.size()<<" element.";//5个
cout<<" These are: "<<endl;
DisplayContents(msetIntegers);// -1,43,78,78,124
cout<<"Please enter a number to be erased from the set"<<endl;
int nNumberToErase = 0;
cin>>nNumberToErase;// 43
cout<<"Erasing "<<msetIntegers.count(nNumberToErase);// 1个
cout<<" instances of value "<<nNumberToErase<<endl;// 43
msetIntegers.erase(nNumberToErase);// 删除
cout<<"multiset contains "<<msetIntegers.size()<<" elements.";
cout<<" These are: "<<endl;
DisplayContents(msetIntegers);// -1,78,78,124
return 0;
}
(5)应用
#include <set>
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<endl;
cout<<endl;
}
struct ContactItem
{
string strContactsName;
string strPhoneNumber;
string strDisplayRepresentation;
ContactItem(const string & strName,const string& strNumber)
{
strContactsName = strName;
strPhoneNumber = strNumber;
strDisplayRepresentation = (strContactsName+": "+strPhoneNumber);
}
bool operator == (const ContactItem & itemToCompare) const
{
return (itemToCompare.strContactsName == this->strContactsName);
}
bool operator < (const ContactItem & itemToCompare) const
{
return (this->strContactsName < itemToCompare.strContactsName);// 按名字字母降序排列
}
operator const char*() const
{
return strDisplayRepresentation.c_str();
}
};
int main()
{
set<ContactItem> setContacts;
setContacts.insert(ContactItem("Jack Welsch","+1 3443 566 764"));
setContacts.insert(ContactItem("Bill Gates","+1 3345 544 656"));
setContacts.insert(ContactItem("Angela Merkel","+1 5456 645 456"));
setContacts.insert(ContactItem("Vladimir Putin","+1 6567 364 675"));
setContacts.insert(ContactItem("Manmohan Singh","+1 3564 333 668"));
setContacts.insert(ContactItem("Barack Obama","+1 3567 656 754"));
DisplayContents(setContacts);
cout<<"Enter a person whose number you wish to delete: ";
string NameInput;
getline(cin,NameInput);// 输入要删除的人的名字
auto iContactFound = setContacts.find(ContactItem(NameInput,""));
if(iContactFound != setContacts.end())
{
setContacts.erase(iContactFound);
cout<<"Displaying contents after erasing: "<<NameInput<<endl;
DisplayContents(setContacts);
}
else
cout<<" Contact not found"<<endl;
return 0;
}
(6)unorder_set
#include <unordered_set>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T&Input)
{
cout<<"Number of elements, size()="<<Input.size()<<endl;// 8,元素的数量
cout<<"Max bucket count = "<<Input.max_bucket_count()<<endl;// 536870911
cout<<"Load factor: "<<Input.load_factor()<<endl;// 0.727273
cout<<"Max load factor = "<<Input.max_load_factor()<<endl;// 1
cout<<"Unordered set contains: "<<endl;// -1000,989,1000,300,111,-300,-3,2011
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<*iElement<<' ';
cout<<endl;
}
int main()
{
unordered_set<int> usetInt;
usetInt.insert(1000);
usetInt.insert(-3);
usetInt.insert(2011);
usetInt.insert(300);
usetInt.insert(-1000);
usetInt.insert(989);
usetInt.insert(-300);
usetInt.insert(111);
DisplayContents(usetInt);// -1000,989,1000,300,111,-300,-3,2011
usetInt.insert(999);
DisplayContents(usetInt);// -1000,989,1000,300,111,-300,-3,999,2011
// find
cout<<"Enter int you want to check for existence in set: ";
int key = 0;
cin>>key;
auto iPairThousand = usetInt.find(key);//999
if(iPairThousand != usetInt.end())
cout<<*iPairThousand<<" found in set"<<endl;// 存在
else
cout<<key<<" not available in set"<<endl;
return 0;
}
21、STL映射类
(1)实例化
#include <map>
#include <string>
template<typename KeyType>
struct ReverseSort
{
bool operator()(const KeyType & key1,const KeyType & key2)
{
return (key1 > key2);
}
};
int main()
{
using namespace std;
map<int,string> mapIntToString1;
multimap<int,string> mmapIntToString1;
map<int,string> mapIntToString2(mapIntToString1);
multimap<int,string> mmapIntToString2(mmapIntToString1);
map<int,string> mapIntToString3(mapIntToString1.cbegin(),mapIntToString1.cend());
multimap<int,string> mmapIntToString3(mmapIntToString1.cbegin(),mmapIntToString1.cend());
map<int,string,ReverseSort<int>> mapIntToString4(mapIntToString1.cbegin(),mapIntToString1.cend());
multimap<int,string,ReverseSort<int>> mmapIntToString4(mapIntToString1.cbegin(),mapIntToString1.cend());
return 0;
}
(2)插入
#include <map>
#include <iostream>
#include <string>
using namespace std;
typedef map<int,string> MAP_INT_STRING;
typedef multimap<int,string> MMAP_INT_STRING;
template<typename T>
void DisplayContents(const T & Input)
{
for(auto iElement = Input.cbegin();iElement != Input.cend();++iElement)
cout<<iElement->first<<"->"<<iElement->second<<endl;
cout<<endl;
}
int main()
{
MAP_INT_STRING mapIntToString;
// 这些插入方式都是等价的
mapIntToString.insert(MAP_INT_STRING::value_type(3,"Three"));
mapIntToString.insert(make_pair(-1,"Minus One"));
mapIntToString.insert(pair<int,string>(1000,"One Thousand"));
mapIntToString[1000000] = "One Million";
cout<<"The map contains "<<mapIntToString.size();
cout<<" key-value pairs. They are: "<<endl;
DisplayContents(mapIntToString);//-1->Minus One,3->Three,1000->One Thousand,1000000->One Million
MMAP_INT_STRING mmapIntToString(mapIntToString.cbegin(),mapIntToString.cend());// 从上面那个map拷贝过来
mmapIntToString.insert(make_pair(1000,"Thousand"));// 然后再插入一个值对
cout<<endl<<"The multimap contains "<<mmapIntToString.size();
cout<<" key-value pairs. They are: "<<endl;
cout<<"The elements in the multimap are: "<<endl;
DisplayContents(mmapIntToString);// -1->Minus One,3->Three,1000->One Thousand,1000->Thousand,1000000->One Million
cout<<"The number of pairs in the multimap with 1000 as their key: "
<<mmapIntToString.count(1000)<<endl;// 1000有2个,所以这个count是2
return 0;
}
(3)查找
#include <map>
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void DisplayContents(const T & Input)
{
for(auto iElement = Input.cbegin();iElement != Input.cend();++iElement)
cout<<iElement->first<<" -> "<<iElement->second<<endl;
cout<<endl;
}
int main()
{
map<int,string> mapIntToString;
mapIntToString.insert(make_pair(3,"Three"));
mapIntToString.insert(make_pair(45,"Forty Five"));
mapIntToString.insert(make_pair(-1,"Minus One"));
mapIntToString.insert(make_pair(1000,"Thousand"));
cout<<"The multimap contains "<<mapIntToString.size();
cout<<" key-value pairs. They are: "<<endl;
DisplayContents(mapIntToString);// -1->Miuns One,3->Three,45->Forty Five
cout<<"Enter the key you wish to find: ";
int key = 0;
cin>>key;// 输入想要查找的key:45
auto iPairFound = mapIntToString.find(key);
if(iPairFound != mapIntToString.end())
{
cout<<"key "<<iPairFound->first<<" points to value: ";// 值为Forty Five
cout<<iPairFound->second<<endl;
}
else
cout<<"Sorry, pair with key "<<key<<" not in map"<<endl;
return 0;
}
(4)删除
#include <map>
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void DisplayContents(const T& Input)
{
for(auto iElement = Input.cbegin();iElement!=Input.cend();++iElement)
cout<<iElement->first<<" -> "<<iElement->second<<endl;
cout<<endl;
}
int main()
{
multimap<int,string> mmapIntToString;
mmapIntToString.insert(make_pair(3,"Three"));
mmapIntToString.insert(make_pair(45,"Forty Five"));
mmapIntToString.insert(make_pair(-1,"Minus One"));
mmapIntToString.insert(make_pair(1000,"Thousand"));
// 插入重复的key
mmapIntToString.insert(make_pair(-1,"Minus One"));
mmapIntToString.insert(make_pair(1000,"Thousand"));
cout<<"The multimap contains "<<mmapIntToString.size();
cout<<" key-value pairs. "<<"They are: "<<endl;
DisplayContents(mmapIntToString);// -1->Minus One,-1->Minus One,3->Three,...,1000->Thousand 按升序排列
auto NumPairsErased = mmapIntToString.erase(-1);
cout<<"Erased "<<NumPairsErased<<" pairs with -1 as key."<<endl;// 2,删除了2个
auto iPairLocator = mmapIntToString.find(45);
if(iPairLocator!=mmapIntToString.end())
{
mmapIntToString.erase(iPairLocator);// 删除45
cout<<"Erased a pair with 45 as key using an iterator"<<endl;
}
cout<<"Erasing the range of pairs with 1000 as key."<<endl;//通过范围查找删除1000
mmapIntToString.erase(mmapIntToString.lower_bound(1000),mmapIntToString.upper_bound(1000));
cout<<"The multimap now contains "<<mmapIntToString.size();
cout<<" key-value pair(s)."<<"They are: "<<endl;
DisplayContents(mmapIntToString);// 最后只剩下3->Three
return 0;
}
(5)自定义排序
#include <map>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
template<typename T>
void DisplayContents(const T & Input)
{
for(auto iElement = Input.cbegin();iElement != Input.cend();++iElement)
cout<<iElement->first<<" -> "<<iElement->second<<endl;
cout<<endl;
}
struct PredIgnoreCase
{
bool operator()(const string & str1,const string & str2) const
{
string str1NoCase(str1),str2NoCase(str2);
std::transform(str1.begin(),str1.end(),str1NoCase.begin(),tolower);// 这两行为什么编译不过
std::transform(str2.begin(),str2.end(),str2NoCase.begin(),tolower);
return (str1NoCase<str2NoCase);
};
};
typedef map<string,string> DIRECTORY_WITHCASE;
typedef map<string,string,PredIgnoreCase> DIRECTORY_NOCASE;
int main()
{
DIRECTORY_NOCASE dirCaseInsensitive;
dirCaseInsensitive.insert(make_pair("John","2345764"));
dirCaseInsensitive.insert(make_pair("JOHN","2345764"));
dirCaseInsensitive.insert(make_pair("Sara","42367236"));
dirCaseInsensitive.insert(make_pair("Jack","32435348"));
cout<<"Displaying contents of the case-insensitive map:"<<endl;
DisplayContents(dirCaseInsensitive);
DIRECTORY_WITHCASE dirCaseSensitive(dirCaseInsensitive.begin(),dirCaseInsensitive.end());
cout<<"Displaying contents of the case-senstive map:"<<endl;
DisplayContents(dirCaseSensitive);
cout<<"Please enter a name to search:"<<endl<<"> ";
string strNameInput;
cin>>strNameInput;
auto iPairInNoCaseDir = dirCaseInsensitive.find(strNameInput);
if(iPairInNoCaseDir != dirCaseInsensitive.end())
{
cout<<iPairInNoCaseDir->first<<"'s number in the case-insensitive";
cout<<" directory is: "<<iPairInNoCaseDir->second<<endl;
}else
{
cout<<strNameInput<<"'s number not found ";
cout<<"in the case-insensitive directory"<<endl;
}
auto iPairInCaseSensDir = dirCaseSensitive.find(strNameInput);
if(iPairInCaseSensDir != dirCaseSensitive.end())
{
cout<<iPairInCaseSensDir->first<<"'s number in the case-senstive";
cout<<" directory is: "<<iPairInCaseSensDir->second<<endl;
}else
{
cout<<strNameInput<<"'s number was not found ";
cout<<"in the case-senstive directory"<<endl;
}
return 0;
}
(6)散列表unorder_map
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
template<typename T1,typename T2>
void DisplayUnorderedMap(unordered_map<T1,T2>&Input)
{
cout<<"Number of pairs,size(): "<<Input.size()<<endl;
cout<<"Max bucket cout = "<<Input.max_bucket_count()<<endl;
cout<<"Load factor: "<<Input.load_factor()<<endl;
cout<<"Max load factor = "<<Input.max_load_factor()<<endl;
cout<<"Unordered Map contains: "<<endl;
for(auto iElement = Input.cbegin();iElement != Input.cend();++iElement)
cout<<iElement->first<<" -> "<<iElement->second<<endl;
}
int main()
{
unordered_map<int,string> umapIntToString;
umapIntToString.insert(make_pair(1,"One"));
umapIntToString.insert(make_pair(45,"Forty Five"));
umapIntToString.insert(make_pair(1001,"Thousand One"));
umapIntToString.insert(make_pair(-2,"Minus Two"));
umapIntToString.insert(make_pair(-1000,"Minus One Thousand"));
umapIntToString.insert(make_pair(100,"One Hundred"));
umapIntToString.insert(make_pair(12,"Twelve"));
umapIntToString.insert(make_pair(-100,"Minus One Hundred"));
DisplayUnorderedMap<int,string>(umapIntToString);// size 8,134217727,0.727273,1
cout<<"Inserting one more element"<<endl;
umapIntToString.insert(make_pair(300,"Three Hundred"));
DisplayUnorderedMap<int,string>(umapIntToString);
cout<<"Enter key to find for: ";
int key = 0;
cin>>key;
auto iElementFound = umapIntToString.find(key);
if(iElementFound != umapIntToString.end())
{
cout<<"Found!key "<<iElementFound->first<<" points to value ";
cout<<iElementFound->second<<endl;
}else
{
cout<<"Key has no corresponding value in unordered map!"<<endl;
}
return 0;
}
22、类
(1)一个类的例子,并且 在main里调用
#include <iostream>
#include <string>
using namespace std;
class Human
{
private:
string Name;
int Age;
public:
void SetName(string HumansName)
{
Name = HumansName;
}
void SetAge(int HumansAge)
{
Age = HumansAge;
}
void IntroduceSelf()
{
cout<<"I am "+Name<<" and am ";
cout<<Age<<" years old"<<endl;
}
};
int main()
{
Human FirstMan;
FirstMan.SetName("Adam");
FirstMan.SetAge(30);
Human FirstWoman;
FirstWoman.SetName("Eve");
FirstWoman.SetAge(28);
FirstMan.IntroduceSelf();
FirstWoman.IntroduceSelf();
}
(2)构造函数的声明及实现
class Human
{
public:
Human();//声明构造函数
};
class Human
{
public:
Human()
{
// 在类中声明构造函数并实现
}
};
// 在类中声明构造函数并在类外实现
class Human
{
public:
Human();
};
Human::Human()
{
// code here.
}
(3)当提供重载构造函数时,系统不会自动生成默认(无参)构造函数
(4)析构函数声明及实现
class Human
{
~Human();// 定义析构函数
};
class Human
{
public:
~Human()
{
// 定义析构函数并实现
}
};
// 定义析构函数并在类外实现
class Human
{
public:
~Human();
};
Human::~Human()
{
// 实现
}
(5)std:string等类都可以自动分配内存,c风格的char缓冲区则要自己管理内存分配
凡是手动分配内存的,都需要手动去删除他
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class MyString
{
private:
char* Buffer;
public:
MyString(const char* InitialInput)
{
if(InitialInput != NULL)
{
Buffer = new char [strlen(InitialInput)+1];
strcpy(Buffer,InitialInput);
}else
Buffer = NULL;
}
~MyString()
{
cout<<"Invoking destructor,clearing up"<<endl;
if(Buffer!=NULL)
delete [] Buffer;
}
int GetLength()
{
return strlen(Buffer);
}
const char* GetString()
{
return Buffer;
}
};
int main()
{
MyString SayHello("Hello from String Class");
cout<<"String buffer in MyString is "<<SayHello.GetLength();
cout<<" characters long"<<endl;
cout<<"Buffer contains: ";
cout<<"Buffer contains: "<<SayHello.GetString()<<endl;
}
(6)深层复制
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class MyString
{
private:
char * Buffer;
public:
MyString(const char * InitialInput)
{
cout<<"Constructor: creating new MyString"<<endl;
if(InitialInput != NULL)
{
Buffer = new char [strlen(InitialInput)+1];
strcpy(Buffer,InitialInput);
cout<<"Buffer points to:"<<hex;
cout<<(unsigned int*)Buffer<<endl;
}else
Buffer = NULL;
}
MyString(const MyString & CopySource)
{
cout<<"Copy constructor: copying form MyString"<<endl;
if(CopySource.Buffer!=NULL)
{
Buffer = new char [strlen(CopySource.Buffer)+1];
strcpy(Buffer,CopySource.Buffer);
cout<<"Buffer points to:"<<hex;
cout<<(unsigned int*)Buffer<<endl;
}else
Buffer = NULL;
}
~MyString()
{
cout<<"Invoking destructor, clearing up"<<endl;
if(Buffer != NULL)
delete [] Buffer;
}
int GetLength()
{
return strlen(Buffer);
}
const char * GetString()
{
return Buffer;
}
};
void UseMyString(MyString Input)// 注意,参数在此即完成实例化
{
cout<<"String buffer in MyString is "<<Input.GetLength();
cout<<" characters long"<<endl;
cout<<"Buffer contains: "<<Input.GetString()<<endl;
return;
}
int main()
{
MyString SayHello("Hello from String Class");
UseMyString(SayHello);// 调用此函数的时候,此函数会自动去调用MyString(const MyString & CopySource)进行深层赋值
UseMyString(SayHello);
return 0;
}
注意:按值传递的类必须实现深层复制构造函数,这是一个特殊的构造函数,只有实现了这个构造函数,才能真正的按值传递(值和值存储在不同的位置)
MyString(const MyString & CopySource)
(7)禁止在栈上实例化
即禁止 ClassName instanceName;这样实例化,这样实例化是在栈上实例化。如果是一个数据库对象,那么数据量会很大,应该在堆上实例化;
禁止栈上实例化的方法是,析构函数声明为private。但是这种做法导致无法在main函数中调用析构函数,那么应该再添加一个静态公开函数,在次函数里调用析构函数。
26、函数
(1)按引用传递参数
如果是引用型参数,则本身就会按引用传递;如果是数值型参数,在函数的形参定义上加上引用标志,则会将引用传递进去,在函数里面改变定义在外部的引用的值。
void Area(double Radius,double & Result)
{
Result = Pi * Radius * Radius;
}
int main()
{
cout<<"Enter radius:";
double Radius = 0;
cin>>Radius;
double AreaFetched = 0;
Area(Radius,AreaFetched);
cout<<"The area is:"<<AreaFetched<<endl;
return 0;
}
注意:按指针传递其实与按引用传递有一样的效果,他们都区别于按值传递。即:加了&和加了*都是一样的效果。
(2)参数可以不要变量名
函数的定义及实现,可以只有变量类型,以及引用或指针标识,但没有变量名。
(3)void参数
//此两者相同,void只是为了增加可读性
//void是一个语法性的类型而非数据类型
void func(void);
void func();
//调用相同,都是没有传入参数
func();
//此函数在调用时还可以在前面加上void:
(void)func();
(4)void*参数
void*表示任意类型的一个指针。只要是一个指针就可以,类型不重要。
比如:
void func(int,void*);
第一个参数是一个int,第二个参数是一个指针,类型是任意的。