cpp1
from c to c++
预处理
#include<iostream>
using namespace std;
c++标准输入输出头文件不带后缀.h
。c++头文件都不再带有扩展名。
若包含stdio.h
还是可以使用printf,scanf
等函数。
提前声明using
,或者在引用函数时使用前缀std::
,std::cout<<std::endl;
。
在main()函数中声明命名空间,则用户自定义函数不能使用该空间。
data type
bool: true/false;
字符函数库
#include<cctype>
isalpha();
isspace();
islower();
......
string
char dog[8] = { 'a','y','d',' ','o','k','h','h' };
char cat[8] = { 'a','y','u',' ','o','k','h','\0' };
cout << dog << endl;
cout << cat << endl;
dog[]
is not a string; when printing this, it will continue outputing until encountering a '\0'.
char cat[]="cat";
string constant(字符串常量),自动在结尾加上空字符。
cout
输出时,任何两个由空白(空格,制表,换行)分隔的字符串常量都将自动拼接,中间不加空格。
<cstring>
处理字符串的标准库。
字符串输入
cin>>cat;//cin使用空白(空格,换行,制表)确定字符串的结束位。
cin.getline(name,20); //面向行的字符串输入
//读取到换行符并将换行符丢弃,或指定字符数(20-1)结束
cin.get(name,size);
cin.get(score,size);//a problem
//cin.get()可以有与getline相同的参数,读到换行或指定字符,
//但是会把换行符滞留在缓冲区,因此第二个get()将永远读取不到数据
cin.get(name,size);
cin.get();//不带任何参数可读取下一个字符,包括换行符
cin.get(score,size);//因此中间插入不带参数的get()解决换行符滞留
cin.get(name,size).get();//也可以解决换行符滞留,<*crazy*>
空行与失效位
字符串与数字混合输入
cin>>
也会滞留换行,因此cin之后的输入会被阻塞,因此要丢弃缓冲区中的换行符。
cin>>year;
cin.get();
(cin>>year).get();//这是一个神奇而有效的方法,后面续接的.get()可以看成最后的清扫
string class
#include<string>
using namesapce std;
string str1;
string str2="pants";//字符串初始化string对象
//cin输入
//cout输出,数组表示访问字符
str1 +=str2; //拼接
#include<cstring>
strcpy(str1,str2);//copy str2 to str1
strcat(str1,str2);//append str2 to str1
int len1=str1.size();//str1是一个对象,size是方法,不能用strlen试图获取string对象的长度
int len2=strlen(charr1);//c-style
//string在应付字符数组超空间方面有优势
//string行输入
getline(cin,str1);
cout<<R"(Jim "king" i)"<<endl;
//原生字符串,以避免符号转义的过度复杂
struct
c++允许在声明变量时省略struct
;
定义时是分号,初始化是逗号;
student stu {"yee",345,0.9};//列表初始化
共用体union
枚举enum
指针
int * ptr;//*两边空格可选
int* ptr1,ptr2;//ptr1是指针,而ptr2是整形变量,要对每一个变量使用*
new分配内存
int *ptr=new int;
*ptr=23;
delete ptr;//释放内存,而不是删除ptr本身
delete ptr;//不能释放已释放的内存块
//compared to c: malloc()/free()
int *ptr1=new int;
int *ptr2=ptr1;
delete ptr2;//ok,delete的关键是释放由new所分配的内存
cin>>len;
int *ptr=new int[len];
delete []ptr;//the style is cute
指针与数组
数组是常量,指针是变量
int tell[10];//数组地址
cout<<tell<<endl;//display &tell[0]
cout<<&tell<<endl;//display adress of whole array
//对数组取地址,数组名不会被单纯地解释为地址,与指针不同
//数值上看两者结果一样
//概念上(tell+1)地址加1,而(&tell+1)地址加10
指针与字符串
给cout一个指针,它将打印指针指向的地址。如果指针是char *
,cout将打印整个字符串。因此要强制转换为另一种指针类型(int *)ptr
来显示指针所指向的字符串的地址。
char *ps;
char animal[]="fox";
ps=animal;//这样做只是把地址赋值给ps
//深度复制
ps=new char[strlen(animal)+1];//分配足够的内存空间
strcpy(ps,animal);
语句结构
循环
do
{}
while();
逻辑操作符
&&,||
优先级低于算术操作符,而!
高于关系和算术操作符,因此取反时要用括号将表达式括起来。and操作符高于or.
条件操作符
exp1 ? exp2:exp3;
int c= a>b ? a:b;//取最大值
文件读写
#include<fstream>
using namespace std;
ofstream outfile; //
outFile.open("edit.txt");
cout << "write to file:" << endl;
outFile << "year:" << year << endl;
outFile << "name:" << s << endl;
cout << "done\n";
outFile.close();//与cout一致
//方法
outfile.precision(2);//设置精确度
//read
函数
使用数组区间
int sum(const int *start,const int *end){
int * pt;
for(pt=start;pt<end;pt++)
{}
}
函数名既是函数地址。
double pam(int);//this is a function
double (*pf)(int);//a pointer to a function
pf==pam;
(*pf)(5);//函数调用
double *pf(int);//括号优先级较高,本语句是生命了一个返回指针的函数,注意区别
内联函数
固定一块内存,执行函数。若为执行改函数而做的前期准备工作比较耗时,则内联函数以占用内存为代价节省一部分时间。多习惯把内联函数的定义也放在函数声明处。
内联函数不能递归。
c++新增特性。c中的宏定义是内联的原始形式。
inline double square(double x);//原型和定义都要使用关键字inline
引用变量
引用变量旨在创建一个别名的副本,与原变量有相同的值和地址。
int rats=20,dogs=30;
int &rodents=rats;//引用变量,必须在定义时初始化。
rodents=dogs; //引用一旦创建,不可再改变为其他的引用,
//因为任何的重新改变引用对象的操作实际上都是赋值操作
//rodents和rats都变成20,并且地址相同,而与dogs地址不同
因此引用变量的实质是给相同的地址取一个别名。这经常被用在函数参数上以改变变量的值,而不必借用于指针。将引用作为函数参数实质是按值传递,不需要另外定义引用变量。
void square(int &a);//引用,相同地址,传递地址
void squera(int a);//传递值
对于任何具有更改值的参数都可以使用const
限定词保护数值不变。
结构作为参数使用引用。
默认参数
char * left(const char *str,int n=1);
left("thesift",3);;//调用时n=3覆盖原来的默认值
left("thesift");//调用时n默认设置为1
默认参数必须放在参数列表的右边。若有多个默认参数,则实参按照从左到右的顺序依次赋给对应的值,中间不可以跳过不赋值。默认参数在函数原型里面声明即可。
int hargo(int n,int m=1,int p=2);
hargo(2);//valid
hargo(2,3);//valid
hargo(2, ,3);//invalid
函数重载
同一个函数名不同的功能。函数重载的关键是函数的参数列表,即函数特征标识(function signature),即参数的数目和类型。c++允许函数名相同而特征标识不同的函数。
即便是强制类型转换后不与任何标识匹配,或与多个标识匹配的函数调用将被视为错误。
有些特征表是不能共存的:引用,const
double cube(double x);
double cube(double &x);//invalid
void drib(char *bits);
void drib(const char *bits);//valid
特征标识不包括函数类型。重载函数的返回类型可以不同,但与此同时特征标识也必须不同。(本就如此嘛)
函数执行相同的任务,而参数类型不一样时多食用重载。
函数模板
template <typename AnyType>
void swap(AnyType &a, AnyType &b);
int main(void){
return 0;
}
template <typename AnyType> //声明建立模板,类型名自定义,如T;typename可以换 //成class,旧式写法
//函数原型和函数定义都需要模板声明
void swap(AnyType &a, AnyType &b) {
AnyType c;
c = a;
a = b;
b = c;
}//调用函数时可以用int,float,string等
模板不创建函数,当需要交换数据时,编译器再按模板模式创建这样的函数实例(specialization)。
重载模板
//重载模板,也需要标识不同
template <typename T>
void Swap(T &a,T &b);
template <typename T>
void Swap(T *a,T,*b,int n);
//第二个模板函数的第三个参数没有使用泛型
模板有其局限性,并不是所有的数据类型都有某一种相似的操作。
显式具体化
多用于结构,类的特殊操作。
void Swap(job &,job &);//非模板函数
template <typename T>//模板函数
void Swap(T &,T &);
template <> void Swap<job>(job &,job &);//显式具体化模板函数
template <> void Swap(job &,job &);//即可以去掉<job>
/*
优先级:非模板函数>显式具体化>模板函数
*/
显式实例化
未深究
template <typename T>
T Add(T a,T b);
int m=6;
double x=10.2;
Add<double>(x,m);//将强制把m转换为double
//<double>声明了专门的类型
内存管理
静态变量
int global://static ,external
static int flit;//static internal
int main(){
for(;;){
static int t=0;//static,no linkage
}
}
未初始化的静态变量所有位被设置为0
外部静态变量
单定义(one definition);
所有的引用都需要声明;
两种声明方式:定义声明(definition declaration),即初始时的定义;引用声明(referencing declaration),即外部声明。
extern int cats;//外部声明必须使用extern关键字
extern int dogs=20;//定义时可以省略extern
内部静态变量
同名将覆盖其他文件中的外部静态变量。外部变量实现不同文件间的数据共享,内部静态实现同一文件内不同函数的数据共享。
说明符和限定符
存储说明符(storage class specifer)
- auto
- register
- static
- extern
- thread local
- mutable
cv-限定符(cv-qualifier)
- const
- volatile
在c++(not in c) const对全局变量的作用使其链接性变为内部。因此倘若在头文件中定义了一个全局常量const int t=8
则有多个源文件包含头文件时并没有违反“单定义”规则。
函数链接性
c++不允许在函数内部定义函数。与变量一样,函数默认为静态,具有外部链接,即可以在文件间共享函数。当然可以在函数原型中使用extern表示函数在另一个文件中定义,但一般不需要这样做。可以使用static定义内部函数拒绝外部文件访问该函数。
动态分配
int *ptr=new int[10];
delete(ptr);
//初始化
int *pd=new int (6);
int *ar=new int[4] {2,4,6,7};//对于数组或结构需要使用大括号,当然大括号也可用于单值
int *ptr=new int;
int *pd=new int [10];
//equal to
int *ptr=new(sizeof(int));
int *pd=new(sizeof(int)*10);
定位运算符
定制内存块