#include<iostream>
int main(){
using namespace std;//可以写在main外,为全局
//using std:cin;
//using std:cout;
//using std:endl;
int n;//声明变量
cout<<"how are you"<<endl;//输出how are you并换行
cin>>n;//输入
cout<<"how are you"<<n*2<<endl;//输出how are you和变量n*2的值 变换行
return 0;
}
/*
cout是一个类的对象
endl是换行,不加不换行
using是一个编译指令,std里面所有的名称都加载一遍,就可以使用了
也可以不用using namespace std;
直接
using std:cin;
using std:cout;
using std:endl;
using namespace std;声明cout,cin,endl
using namespace std在头文件iostream中,预处理
*/
x=sqrt(4);//sqrt(double x)开根号函数,返回double类型
double sqrt(double x);//这是一个数学函数
cmath头文件(老系统为math.h)无需声明,直接使用sqrt()
基本类型,复合类型(数组,字符串,指针,结构)
_开头定义变量,不会报错,但是有可能会调用复合类型比如_Complex
简单变量:
(0~255)8个bit,两个字节
整形:short(16)、int(>=short)、long(32)、long long(64)
#include<climits>//符号常量
可以调用INT_MAX、SHRT_MAX、LONG_MAX、LLONG_MAX等符号常量即int型的最大值如int n_int=INT_MAX;
sizeof(int)//返回int类型所占的字节数量//sizeof()判断类型所占内存大小
int n=5;//5为字面值常量
区别于c语言的另外的初始化方式
int a(5);//int a=5;
int a={5};//int a=5;
无符号类型
unsigned 本身是 unsigned int 的缩写
无符号类型表示的值更大
short(-32768~32767)
unsigned short(0~65535)
改变第一位符号位
无符号的最大值在SHRT_MAX等前面加个U,即为 USHRT_MAX等
进制
八进制,第一位为0开头
十六进制,以0x或0X开头,A~F为10~15
想要输出不同进制的数,需要在输出前声明dec、hex、oct
cout<<dec; //十进制
cout<<hex; //十六进制
cout<<oct; //八进制
hex位于名称空间std中
如果省略编译指令using,而使用作用解析符std::cout,std::endl,std::hex,std::oct,可将hex用作变量名,但不建议使用
cout<<
cin>>
流向不同
数值没有后缀,默认为int型
unsigned long --->ul
long ---> L
long long ---> LL/ll
unsigned long long --->ull/uLL/ULL
char类型
每个字符都有"数值编码"
0~256,一个字节就足够表示所有字符
A65,a97
字符串""
字符''
成员函数 cout对象
cout.put(字符)
输出一个字符
.成员运算符
以前cout不能打印不出来字符只能打印出字符的数值,当时需要cout.put()才能打印出
有些字符不能直接通过键盘输入
\a振铃字符
char a=\a;
cout<<a会发出振铃报警铃声
使用endl比\n更容易
'\032'得到相应的字符常量
\b退格键
char类型在默认情况下既不是有符号,也不是没有符号
unsigned char类型的表示范围通常为0~255
signed char类型的表示范围为-128~127
wcha_t 宽字符类型,可以表示扩宽字符集
wchar_t是一种整型类型,可以表示系统使用的最大扩展字符集
underlying类型 底层类型也是一种整型'
对底层类型的选择取决于实现,在一个系统中。可能是unsigned short,另一个系统中,则可能是int
cin和cout将输入和输出看作char(字节)流,因此不适于用来处理wchar_t类型
iostream最新版中wcin和wcout,可用于处理wchar_t流
加上前缀L,指示宽字符常量和宽字符串
wchar_t bob=L'p';
wcout<<L"tall"<<endl;
国际编程使用Unicode或ISO 10646
bool类型,true/false
预定义的字面值true/false表示真假
true/false可以赋值int类型,1/0
任何数字值或指针值都被隐形转换为bool值 ,非零转换为true,零转换为false
当多个地方需要使用同一个变量,可以用#define
const限定符
固定变量的值,防止它被修改
const int a;不允许在赋值了
const比#define更好,因为const明确指定了类型
浮点数
分为两部分来存储
一部分表示值,一部分用于对值进行放大或缩小
34.1245 0.3412545(基准值) 100(缩放因子)
E6 10^6 1000000
2.52e+8 +号代表小数点向右移
2.52e-8 -号代表小数点向左移
浮点类型
float,double,long double
<cfloat> <float.h>
整数部分:10
10.25
除数 被除数 余数
2 10 0
2 5 1
2 2 0
2 1 1
二进制为1010
小数部分:0.25
0.25*2=0.5-->0
0.5*2=1.0-->1
二进制为01
科学计数法的方式为 1.01001*2^3
单精度有效位32位
第一位为符号位,0为正,1为负
八个比特位为指数位2^8=256
0~127表示正指数的二进制,127~255表示负指数的二进制
2^3为127+3的二进制数表示10000010
符号位 指数位 尾数(小数点后面的)
0 10000010 01001000...0
默认状态下通常cout会将小数点最后的0删掉
cout_setf(ios_base::fixed,ios_base::floatfield);覆盖掉默认模式
输出时小数位后面所有的0被保留
有效位只显示6位
float
系统确保7位是精确的,至少有6位
double至少有13位有效
#include<iostream>
int main(){
using namespace std;
float hats;
cout.setf(ios_base::fixed,ios_base::floatfield);//定点模式
cin>>hats;
cout<<hats;
//顶点模式,小数点6位后面全部显现
return 0;
}
//浮点型默认为double型浮点型转整形,结果是不确定的
缩窄(narrowing)
int x=66;
char c4={x};//初始化列表
强制类型转换符
static_cast<long>(thorn);//将thorn转为long型
auto n=100;//auto将变量设置为与初始值相
auto x=1.5;
std::vector<double>across;
std::vector<double>::iterator pv=across.begin();
转换为 auto pv=across.begin();更简单
复合类型
数组
sizeof(int)//int的空间大小
只有在定义时才能使用成员初始化列表
short thing[]={1,2,3};//自动记录元素个数;
int num=sizeof things/sizeof(int);//具体的元素个数
int a[3] {1,2,3};//=可省略
int a[3]={};//所有的元素都设置为0
取值范围大的变成一个取值范围小的,缩窄
字符串
'\0'结尾
char a[]="";//根据字符串长度来定义a的长度
'\0'后面都为'\0'
双引号实际上表述的是一个地址
拼接字符串常量安排
空格、制表符、换行符分隔的两个字符串都将自动拼接成一个
cout<<"I love you" "are you ok";
char a[10];
cin>>a;//给字符串赋值
strlen(a);//有多少个实际字符,不包括'/0'
cout里也能用'\n'换行
cin把空白符(空格,制表符,换行符)作为就结束标志
字符串以/0作为结束标志
cout以空字符'/0'作为结束标志
面向行的读入:getline(),get()
istream类中的getline()成员函数
cin.getline(存储输入行的数组的名称,读入字符的个数)
字符串一定要有'/0'
通过换行符确定行尾,会丢弃回车换行符,存储字符串时用空字符('/0')替换换行符
面向行的读入:get()
get()不会丢弃回车换行符
cin.get(name,13)去捕获内容的时候,回车换行符会被留在缓存区里面
get(name,13)读取空行的时候,会设置一个失效位,cin就不能用了
重载函数get()可以读取换行符,看可以用get()来去掉这个失效位
cin.get(name,13);
cin.get();//读取下一个字符
cin.get(name,13)返回一个cin对象,该对象随后将被用来调用get()函数
cin.getline(name,13).getline(dessert,13);//链式编程,getline可以这样写,get不行,因为会产生失效位
get可以知道是读取了整行还是数组填满
cin.clear();//可以将失效位复位
如果输入行包含的字符出比指定的多,getline和get会把余下的字符留在输入队列中
cin读取年份,即将回车键生成的换行符留在了队列中,cin.getline()看到换行符后,将认为是一个空行,并将空字符串赋给address数组,解决:读取地址之前先读取并丢弃换行符
没有参数的get()和使用接受一个char参数的get()
(cin>>year).get();将换行符读取读取丢弃
(cin>>year).get(ch);可以将换行符读到ch中
string是保存在std里的
using namespace std;
或者std::string;
char ch[20]="junar";
string str="aa";
可以str[]来提取字符串中的字符
string对象可以字符的给予空间
也可以用初始化列表赋值{}
不能把数组赋值给另一个数组,因为数组是地址
可以把string对象赋给另一个对象
+拼接字符串
cstring头文件中
strcpy(a1,a2)可以将字符串复制到另一个字符数组中
a1需要比a2大,或是把报警系统关了
strcat() 将字符串添加到字符数组末尾
size()是string类的成员函数 str1.size(),计算字符串的长度
c风格字符串成员函数:strlen(char1)
对象不能作为函数参数
string类的I/O
只有带/0的才是c风格的字符串,不然只是char数组
char charr[20];
string str;
cin.getline(charr,20);大于19个字符,会设置一个失效位
getline(cin,str); 将cin输入流里的内容放到str里
cin>>x是istream类的一个成员函数
istream没有处理string对象的方法
cin>>str;处理string对象的代码使用string类的一个友元函数
结构简介
结构是一种复合类型
struct inflatable{
...
};
c语言:struct inflatable goose
c++ :inflatable goose
两种风格都好
inflatable guest={
"Glorious Gloria",
1.88,
29.99
};// =可有可无
结构体可以赋值给另一个结构体
struct perks{
int x;
}a,b;
结构定义和变量声明可以写在一起
结构数组
inflatable gift[100];
cin>>gifts[0].volume;
可以初始化列表
inflatable guests[2]={
{"ada",0.2,12,44}.//guess[0]
{"sdfaf",0,3,123,33}//guess[1]
};
共用体union
可以存储不同类型,但同时存储其中的一种类型
用哪个,表现哪个类型
结构体内可以嵌套匿名共用体
匿名共用体没有名称,变量的地址相同
枚举enum
enum spectrum{red,orange.yellow,green,blue};//0~3
可以显式的指定整数值来覆盖默认值
spectrum band;
可以将枚举量赋(如yellow)给枚举变量(band)
枚举变量可以进行计算++band
枚举量可以变为整型,整型不能变为枚举量,除非强制类型转换,且空间不能超过最大枚举量
band=spectrum(3);
band=spectrum(40003);//超出范围
enum bits{one=1,two=2,four=4};
enum bigstep{first,second=100,third}
可以创建多个值相同的枚举量
enum{zero,full=0,one,numero_uno=1};
最大值:大于最大枚举量的最小2次幂
如果枚举量为-6,下限的为-8+1为-7
OOP在运行阶段确定数组的长度
int* p指针
指向int的指针,地址不是int类型
p地址
*p地址所指向的值。解引用
地址是指定的量,值是派生量
通过解引用修改,该地址上的所有变量值也会修改
把地址强制类型转化,才可以赋值给指针
int * p;
p=(int *)0xB800000;
C语言中malloc()来分配内存
c++中,new分配内存,并返回该内存块的首地址,程序员并赋给一个指针
int *p= new int;
指向什么类型,new开辟什么类型
sizeof 打不打括号都一样
地址根据计算机64位,统一8个字节
new从堆heap或自由存储区free shore的内存区域分配内存
new 范返回值为0的指针为空指针null pointer
delete释放内存
int *p=new int;
delete p;
释放的是p指向的内存,指针p不会被删除掉
new和delete配对使用,否则发生内存泄漏memory leak
内存不要尝试重复释放,结果是不确定的
空指针使用delete是安全的
new来创建动态数组
在编译时给数组分配内存称为静态联编static binding
运行时选择数组的长度,动态联编,运行时创建的数组为动态数组dynamic array
int *psome=new int [10];//开辟
psome指向了首地址
delete [] psome;//释放
new带方括号,delete也带方括号,不带,都不带
psome指向动态数组第一个元素
psome可以当作数组名使用,psome[0],psome[1],psome[2]
psom=psome+1//psome[0]->psome[1],将首地址改为了下一个元素的地址,减1加1,首地址向左右移动
普通数组不能赋值,更改首地址,也可以加1减1,指向的值移动
stack[1]//c++编译器会看作*(stack+1)
c++不会将数组名作为地址来使用,sizeof(数组名),计算整个数组的地址大小
short psome[10];
psome=psome[0]//第一个元素的地址
&psome//数组名取地址是整个数组的地址
psome+1//加两个字节
&psome+1//加20个字节
short (*pas)[10]=&psome;//pas指向一个数组,且这个数组有10个元素
short* pas[10]//有一系列指向short类型的指针组成的数组
short (*pas)[10]//一个指针指向的数组
c风格字符串有\0
char flower[10]="rose";
字符串也是个地址cout<<"askdakl"<<endl;//""中也有隐式的\0
const char* bird="wren";//bird指向第一个字符的地址,w
字符串常量不能修改,不能对指向字符串常量的地址上修改字符串,可以修改指针,不能修改指针指向的值
cout只有在char类型,字符串,首地址才打印的是地址指向的值
(int*)animal//对地址int*类型转换,就不会打印字符串,而是打印地址
char *ps;
ps=new char[strlen(animal)+1]//strlen实际长度,1为\0
strcpy(ps,animal);//将animal里面的所有内容赋值到ps所指向的内存空间里
#pragma waring(disable:4996)
忽视警报
字符串常量是只读的,不能用来strcpy
strncpy(目的,源,长度)//指定cpy的长度
strncpy()结束后,给目的数组补上'\0'
string类型自动调节空间大小
new创建动态结构
inflatable * ps=new inflatable;
该结构没有名称,只有一个指向它的指针
-> 表示指向,访问成员、
(*ps).name
ps->name
先定义结构体inflatable,然后再inflatable *ps=new inflatable;
cin.get(ps->name,20);//读取一行,保留换行符
cin>>(*ps).volume;
delete ps;//delete与new配对
getname(),返回指向输入字符串的指针,将输入读入到一个大型的临时数组,用new []创建一个内存块并返回指针
char* getname(void);//声明getname函数
int main(){
char* name;
name=getname();
cout<<name<<" at "<<(int*)name<<"\n"
delete[] name;//delete掉动态数组
}
char* getname(){
char temp[80];//静态数组
cin>>temp;
char* pn=new char[strlen(temp)+1];//动态数组
strcpy(pn,temp);//将静态数组中的内容cpy到动态数组中
return pn;//返回那一块动态数组的指针
}
自动存储,静态存储,动态存储
自动变量,即局部变量,存储在栈中,先进后出被释放
静态存储,全局
动态存储,内存池内,new,delete,程序员控制,一个函数开辟,另一个函数释放,自由存储区并不连续。
结构体类型数组名->year=2003;
(数组名+1)->year=2004;
const years_ends *arp[3]={&sro1,&sro2.&sro3}
指向结构体的指针的数组,且值不可修改
const year_ends **ppa=arp; //指向结构体指针的指针
auto ppb=arp; //自动赋予变量类型
数组的代替品
模板类vector和array是数组的替代品
vector是一种动态数组,是new创建动态数组的替代品,new和delete自动完成
vector包含再std中,std::vector
using编译指令声明
vector<int> vi;
自动设置长度,末尾,中间插入数据
vector<typeName> vt(n_elem);
存储n_elem个类型为typeName的元素
array是长度固定的,使用栈(静态内存分配)
array<int,5> ad = {1,2,21,2.3,3.2,4.3};
array<type,n_elem>arr;
vector和array可用初始化列表
vector对象可以使用数组的方式对元素进行操作,a[0],a[1],a[2]
vector对象可以赋值给相同类型的vector对象
可以给未定义的位置进行越界赋值,中间的空白区域会被随机赋值
成员函数at()
a2.at(1)=2.3;//at()若越界会报错
cout<<setf(ios_base::boolalpha);判断表达式强制转化为bool类型
表达式加;可以转化为语句、
for()中声明的变量,不能在for外面使用
std::cout<<sda<<std::endl;
std::cout;
std::cin;
std::endl;
size()//计算string字符串长度的函数
自增,自减,顺序点sequence point,以分号为分隔
前缀格式效率更高
递增运算符可以用于指针
*++pt//pt=pt+1
++*pt//*pt=*pt+1
组合赋值运算符
i+=2;
局部可以看到外部,外部无法看到局部
局部的变量会隐藏全局的变量
逗号运算符,++j , --j 将两个表达式变成一个表达式
for(int j=0,i=5;j<i;--i,++j)
逗号运算符算是一个顺序点
cats=(12,88)括号的优先级最高,逗号表达式先看后面的值
word=="mate"//比较两个地址是否相同
strcmp()接受字符串地址作为参数
string类字符串,可以用关系运算符进行比较
编写延迟循环
clock()返回的单位不一定是秒
头文件ctime
CLOCKS_PER_SEC该常量等于每秒钟包含的系统时间单位数
系统时间除以这个值,可以得到秒数
colck_t作为clock返回类型的别名,编译器会将其转换为适合系统的其他类型
include<iostream>
include<ctime>
int main(){
using namespace std;
float secs;
cin>>secs;
clock_t delay=secs*CLOCKS_PER_SEC;//延迟的时间
clock_t start =clock();//当前系统时间
while(clock()-start<delay);//时间达到延迟时间为止
//依此来使系统延迟时间
return 0;
}
类型别名
typedef 类型名 别名
也可以使用#define声明别名
typedef更不容易出错
#define FLOAT_POINTER float *
FLOAT_POINTER pa,pb;
系统会将其转化为float * pa,pb;//pa使float *类型,pb则使float类型,#define取别名并不安全
基于范围的for循环
price[5]={1,2.3,4.5};
for(double x:price){
cout<<x<<endl;
}
for(int x:{1,2,3,4,5})
cin在读取时,空格会被忽略
char ch;
cin.get(ch)可以读取空格
cin.get(name,ArSize).get();
相当于
cin.get(name,ArSize);
cin.get();
检测文件尾(EOF)
重定向
eofbit和failbit都设置为1
eof()来查看eofbit是否被设置
如果监测到EOF,cin.eof()将返回true,否则false
如果eofbit或failbit被设置为1,fail()返回true
cin.get(ch);
while(cin.fail()==false){
cout<<ch;
++count;
cin.get(ch);
}
windows系统ctrl+z作为文件尾
ctrl+z一定要是在行首,才能作为文件尾
EOF结束输入
cin.get(ch)需要变为true和false时就会变为true和false
cin.get(ch);
while(cin)//直接捕获
while(!eof())
while(!fail())
EOF被定义为值-1
cout<<cin.get()<<endl;//输出97即第一个字符a
cin.get读取字符时,返回值是字符对应的ASCII码的十进制数,就是int
若成功读取字符,返回的都是正数,EOF是-1,所以EOF表示结束
cout.put(char(ch));//输出一个字符
cin.get(ch),字符true,结尾false
ch=cin.get(),字符int类型的字符编码,结尾EOF
while(ch=cin.get()!=EOF)
二维数组,初始化列表
int maxtemps[2][2]={
{1,2},
{2,3}
};
const int Cities=5;
const char* cities[Cities]={
"cajkhfjl".
"afjahfl",
"dafjkla",
"dfankf",
"dafaf"
};
//空间消耗过大
const char cities[Cities][25]={
"cajkhfjl".
"afjahfl",
"dafjkla",
"dfankf",
"dafaf"
};
const string cities[Cities]={
"cajkhfjl".
"afjahfl",
"dafjkla",
"dfankf",
"dafaf"
};//string类是自动修改
定义is_int(double x)函数判断是否位于int类型的范围内
x<=INT_MAX&&x>=INT_MIN
int(num)//强制类型转换
字符函数库cctype
isalpha(ch)如果是一个字符,则返回true
isspace(ch)是空格
i sdigit(ch)是数字
ispunct(ch)是标点符号
三目运算符
?:
cin输入的值与类型不匹配。n的值保持不变,不匹配的输入被留在输入队列中,cin对象中的一个错误标记被设置;
对cin方法的调用将放回false
clear()重置错误输入标记,也重置文件尾
输入错误和EOF都将导致cin返回false
简单文件输入/输出
文本I/O和文本文件
输入的是一系列的字节,解释为字符编码,输入一开始字符数据------文本数据
cin读到空白字符会终止
类型匹配,会设置失效位
写入到文本文件中
cout<<fixed;//设置定点模式
cout,precision(2);//设置精度
cout.setf(ios_base::showpoint)//显示小数点
文件输出
头文件fstream
输出ofstream
ofstream outFile;//必须自己创建一个对象
outFile.open("文件");//如果没有这个文件,系统会自动创建这个文件
写入文本文件
outFile<<fixed;
outFile<<precision(2);
outFile.setf(ios_base::showpoint);
outFile<<"afdaf"<<endl;//流入文件中
open会截断打开的文件,并且丢弃文件中原来的内容,输入新的内容
outFile.close();//关闭该文件
读取文本文件
ifstream
char filename[SIZE];
ifstream inFile;
cin.getline(filemame,SIZE);//数组存储文件名
inFile.open(filename);
if(!inFile.is_open())// 没有成功打开
{
cout<<"Could not open the file"<<filename<<endl;
exit(EXIT_FAILURE);//退出整个程序
}
//while(inFile>>value)//若读取成功,返回true,否则返回false
inFile>>value;//从文件中读取内容
while(inFile.good())//成功读取,inFile.good()返回true
{
//遇到空格,读取结束,光标移动到此处
}
if(inFIle.eof())//是否到文件尾
{
}else if(inFIle.fail()){//数据不匹配,导致中断
}else{
}
声明函数中,参数可以只写类型
如果参数类型不匹配,会自动转换为正确的类型
数组名作为参数传给函数
int num_arr(int* arr,int n)//数组。数组长度
arr实际上是一个指针,数组不能赋给数组
指针加const,就不会修改内容
cin>>temp;
if(!cin){//输入错误
cin.clear();
while(cin.get()!='\n')
continue;
cout<< "Bad input;input process terminated.\n"
break;
}
int sum=sum_arr(cookies,cookies+ArSize)//俩个指针作为参数
int sum_arr(const int* begin,const int* end)
{
const int* pt;
int total=0;
for(pt=begin;pt!=end;pt++)
total=total+ *pt;
return total;
}
int * const pt;//pt不能变,但pt所指向的值可以修改
字符串的函数原型是char* 类型
c风格字符串\0结尾
char mmm[15]="afhjka";
const char* wail="aijdiaj";//必须加const,因为字符串常量是只读的
char* buildstr(char c.int n){
char* pstr=new char[n+1];//第n+1个元素存的是\0
pstr[n]='\0';
while(n-- > 0)
pstr[n]=c;
return pstr;
}
结构体对象也可以用初始化列表
结构体可以按值传递,也可以按地址传递
按引用传递
string list[SIZE]
for(int i=0;i<SIZE;i++){
getline(cin,list[i]);//getline是一个函数,cin读取一行,存储到list[i]中
}
std::array<std::string,4>Snames={"Spring","Summer","Fall"."winter"}//有限长度的数组
若是地址传递array对象,(*p)[2]//需要先解引用在标明第几个元素
因为array不是真实的数组,p不能表示第一个元素,需要解引用后,在指明元素下标
包含多个递归的递归
函数也有地址。存储机器语言代码的内存的开始地址
estimate()
获取函数的地址
think(),think就是该函数的地址,函数作为参数进行传递,传递函数名,区分传递的是函数的地址还是函数的返回值
think作为参数
声明一个函数指针
指向函数的指针,必须指定指针指向的函数类型
使用函数指针来调用函数
double pam(int);
double (*pt)(int);//如果*pt是函数,pt就是函数指针
estimate(code,betsy); //函数作为参数
doule betsy(int lns){//作为参数的函数
return lns;
}
void estimate(int lines,double (*pf)(int))//函数指针作为参数,并使用该函数。
{
std:: cout<<(*pf)(lines)<<"hours\n";
}
const double* f1(const double* ar,int n){
return ar;//ar=ar+0=&ar[0]
}
const double* f2(const double ar[],int n){
return ar+1;//ar+1=&ar[1]
}
const double* (*p1)(const double*,int)=f1;//函数指针赋值
auto p2=f2;//自动获取函数指针类型
const double* (*p3[3])(const double*,int)={f1,f2.f3};//函数指针数组
p3[3]表示数组
*p3[3]表示指针数组
const double* *p3[3]表示类型为const double*的指针数组
p[1]存的的是函数地址
p=&p[0]是这个数组的首地址
函数的类型为double*
cout<<p[1](av, 3);//输出函数的返回值
p1(av,3)和(*(p1))(av,3),*p1(av,3)和*(*p1) (av,3)是等价的,但只限于函数指针
const double* (*(*pc)[3])(const double*,int)=&pa;
//*pc表示一个指针
//(*pc)[3]表示指向一个数组
//*(*pc)[3]表示是指针数组里的函数指针所指向的函数
//const double* 表示函数的类型
(*pc)[0](av,3)等价于(*((*pc)[0]))
typedef const double *(*p_fun)(const double *,int);//将p_fun声明为函数指针类型的别名
p_fun p1=f1;//将函数指针f1赋给p1
p_fun pa[3]={f1,f2,f3};//将数组f1,f2,f3初始化列表赋值给类型为p_fun的数组
p_fun (*pd)[3]=&pa;//pd=&pa;pa为数组首地址
内联函数比常规函数稍快,不需要跳转
内联函数用内联代码替换函数调用
声明和定义时加上关键字unliine
内联函数不能递归
inline double square(double x);
inline double square(double x){
return x*x;
}
#define SQUARE(X) X*X;
a=SQUARE(6.0) a=5.0*5.0;
b=SQUARE(4.5+7.5) b=4.5+7.5*4.5+7.5
宏不能按值传递
引用变量
int rates;
int & rodents = rats;//必须在声明引用变量时进行初始化
&不是地址运算符,而是类型标识符的一部分
rodents作为rats变量的别名
两个变量的地址和值都相同
引用作为参数,作为实参的别名,用的是同一个内存空间
引用变量作为参数
void swaper(int& a,int& b){
int temp;
temp=a;
a=b;
b=temp;
}
const double& ra;//ra不能修改
double cube(double a){//参数可以是常量
a *= a*a;
return a;
}
字符串常量可以取地址,字符常量不能取地址
const int& b=10;//加const赋值才能为右值
const int& b//作为参数,可以是右值
const string& b="abc";
int& d=a;//左值引用
int&& d='a'+2;//右值引用
结构的引用作为参数
free_throw& ft;
display(accumulate(team,one));//accumulate的返回值是free_throws& ,display的参数类型为const free_throws&
accumulate(accumulate(team,three),four);
void distplay(const free_throws& ft){
using std::cout;
}
free_throws& accumulate(free_throws& target,const free_throws& source){
return targat;
}
accumulate(dup,five)=four;
赋值语句,左边的子表达式必须标识一个可修改的内存块
string input;
getline(cin,input)//cin捕获到input里
引用类作为参数string& s1
ostream是基类,ofstream是派生类
派生类继承基类的方法
基类对象可以作为参数,派生类对象可以作为参数
oftream fout;
const char* fn="data,txt";
fout.open(fn);
if(!fout.is_open()){
cout<<Cant open:"<<fn<<"Bye.\n";
exit(EXIT_FAILURE);
}
double objective;
double eps[LIMIT];
file_it(cout,objective,eps,LIMIT);
void file_it(ostream& os,double fo,const double* fe,int n)
{
os<<"dafd";
}
参数默认值
若第一个赋了默认值,后面的也必须赋
int harpo(int n,int m=4,k=5)
harpo(2);//2,4,5
harpo(2,2);//2,2,5
harpo(4,5,6);//4,5,6
函数重载,同名函数
变量名相同,特征标不同
尝试使用强制类型转换
类型本身和类型引用视为同一个特征标
区分const和非const变量
double && r 右值引用
名称修饰
每个函数名进行加密
函数模板
使用泛型来定义函数
模板交换函数
template <typename AnyType>
void Swap(AnyType &a,AnyType &b)
{
AnyType temp;
temp=a;
a=b;
b-temp;
}
编译器根据类型生成有个具体的定义
显示具体化的原型和定义应以template<>打头 ,并通过名称指出类型
template <> void Swap<job>(job &,job &);
1.非模板函数
void Swap(job &.job &) //定义
2.模板函数
template <typename T>//模板
void Swap(T &,T &);
3.显示具体化模板函数
remplate<> void Swap<job>(job &,job &)//定义
优先级
非模板版本>显式具体化>模板生成的版本
实例化和具体化
Swap<int>(i,j)
//显式实例化//强制要求int
//隐式实例化,编译器自动 规定是int还是其他
template void Swap<int>(int,int);//显式实例化,加<>就是具体化
非模板>显示具体化>显示实例化> 实例
template<> void Swap(job&,job&);//显示具体化
template void Swap(job&,job&)//显示实例化
编译器有一个自主性,如果参数相同,且具体化在实例化前,则编译器自动放弃显示实例化
若是实例化在前,具体化在后,则编译器会报错,因为已经实例化,无法再具体化
隐式实例化,显式实例化,和显示具体化统称为具体化,使用具体类型的函数定义,而不是通用描述
模板都是在编译阶段完成的 具体化
完全匹配,常规函数优先于模板、
提升转换,(char和short自动转换为int,float自动转换为double)
标准转换,(int转换为char,long转换为double)
显式具体化和显示实例化同时出现的时候才会出现二义性
没有强调<>类型,选非模板
强调了,选模板函数
重载解析将寻找最匹配的函数
如果都是模板,则选择更具体的
int x;
decltype(x) y;//x是int类型,decltype就是int类型
long indeed(int);
decltype(indeed(3) ) m;//根据返回值
()并不会改变左值和左值性
auto h(int x,float y)->double//后置的返回类型
#表示预编译
#ifdef CON
#define CON
...
endif
#progma once可以替代上面三个#...
内联函数可以写在头文件里
翻译单元(translation unit)
自动存储持续性
自动变量,局部
静态存储持续性
static静态变量,全局
线程存储持续性
动态存储持续性
new自动变量,函数定义中定义的变量
作用域和链接
static 静态变量
默认情况下为0
定义声明,定义,开辟内存空间
double up;
引用声明,声明,不开辟内存空间
extern int blem;
使用外部变量,需要extern声明
自动变量放在栈中
静态变量放在静态区
::warning使用外部变量
在一块作用域内,谁在前用哪个
extern double warining;
double warning =0.8;
auto 自动变量
register 寄存器存储,变量是自动的
extern 引用声明,声明引用在其他地方定义的变量
thread_local 线程
volatile声明,没有对内存单元进行修改,值也可能发生变化
改善编译器的优化能力
查找两次,这个值缓存到寄存器中,若是不声明volatile,将进行这种优化
mutable
即使结构变量为const,某个成员也可以被修改
默认情况下全局变量的连接性为外部的,但const全局变量的链接性为内部的
由于外部定义的const数据的链接性为内部的,可以在所有文件中使用相同的声明
extern const int states =50;//const 为内部,加上extern又变成外部的
一个文件extern声明一个const变量,另一个文件extern声明,就可以使使用另一个文件的该变量
可在函数原型中使用关键字extern来指出函数是在另一个文件中定义的
static将函数的连接性设置为内部的,只能在一个文件中使用
在一个文件中定义函数,另一个文件可以调用,若另一个文件内部也定义一个该函数,则会冲突,可以使用static,使该函数称为内部链接的
重载函数生成不同的符号名称
spiff(int) _spiff_i
spiff(double,double) _spiff_d_d
使用c库函数中预编译的函数
c库文件中的符号名称为_spiff,c++查询约定是查找符号名称_spiff_i
可以用函数原型来指出要使用的约定
extern "c" void spiff(int);
extern void spoff(int);
extern "c++" void spaff(int);
new要初始化常规结构或数组,大括号的列表初始化
struct where{double x;double y;double x;};
where * one = new where{2.5,5.3,7.2};
int *ar=new int[4]{2,4,5,6};
也可用于单值常量
int *pin=new int {12};
int *pi=new int (6);
new失败返回空指针,引发异常std::bad_alloc
size_t a=10;
size_t,X64 8个字节,X86 4个字节
int * pi=new int;
int *pa=new int[40];
被转换为
int * pi=new(sizeof(int));
int *pa=new(40*sizeof(int));
delete pi;
转换为delete (pi);
定位(placement)new特性
使用定位运算符时,变量后面可以有方括号,也可以没有
char buffer1[50];//外部变量,静态变量在静态区里面
char buffer2[500];
int main(){
chaff *p1,*p2;
int *p3,*p4;
p1=new chaff;
p3=new int[20];
p2=new (buffer1) chaff; //在buffer1内开辟chaff类型大小的空间
p4=new (buffer2) int[20];
}
(*void)强制类型转换,求地址
定位new,buffer1的值会被覆盖掉
delete只能释放堆内存,不能释放静态内存
new (buffer+N*sizeof(double)) double[N];//从buffer+N*sizeof(double)开始开辟double[N]大小的内存
名称冲突
名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中
全局名称空间(global namespace)
不同名称空间中的名称不会冲突
namespace
访问给定名称空间中的名称
作用域解析运算符::,使用名称空间来限定该名称
Jack::fetch();
未被装饰的名称称为未被限定的名称(unqualified name)
包含名称空间的名称称为限定的名称(qualified name)
using声明
简化对名称空间中名称的使用
using声明将特定的名称添加到它所属的声明区域中
using声明将名称添加到局部声明区域中
在函数外面使用后using声明时,将把名称添加到全局名称空间中
using 使一个名称空间可用,而using编译指令使所i有的名称空间都可用using namespace
全局声明区域使用using编译指令,名称空间里的名称全局可用
namespace elements
{
namespace fire{
int flame;
...
}
float water;
}
element::fire::flame
也可以在名称空间里使用using编译指令和using声明
可以using该名称空间,使用该名称空间里的using的变量
可以给名称空间创建别名
namespace mvft=my_very_favorate_things;
未命名的名称空间
namespace
{
int ice;
}
不能显式地使用using编译指令或using声明
只能在当文件中使用
OOP面向对象
用户与数据交互:初始化,更新,显示
接口由公共方法组成
#ifndef STOCK00_H_
#define STOCK00_H_
#include<string>
class Stock
{
private:
std:: string company;
long shares;
double share_val;
double total_val;
void set_tot(){total_val=shares*share_val;}
public:
void acquire(const std::string& co,long n,double pr);
void buy(long num,double price);
void sell(long num,double price);
void update(double price);
void show();
}
#endif
公有成员函数是程序和对象地私有成员之间的桥梁
共有接口表示设计的抽象组件,称为封装,将实现的细节隐藏在私有部分中,也是一种封装、
类成员可以是数据也可以是函数
私有成员函数来处理不属于共有接口的实现细节
private是类对象的默认访问控制
结构体里面可以放函数
struct成员默认为public
定义成员函数,使用::来标识函数所属的类
类方法可以访问类的private属性
void Buffoon::update(double price);
将update()标识为成员函数
可以将另一个类的成员函数也命名为update()
void Buffoon::update();
定义位于类声明里的自动成为内联函数,使用iline限定符
函数声明在类中,函数定义在类外,用inline,也可以直接定义在类中
公有成员可以访问私有成员
可以在类声明中定义一个函数
单独提供函数定义,需要使用作用域解析运算符来指出成员函数属于哪个类
类对象不能直接初始化成员属性
Stock类构造函数Stock().构造对象,将值赋给它们地数据成员
默认提供,也可自己定义
Stock::Stock(const string &co,long n,double pr){
}
Sotck food= Stock("daf",12,1,22);//显式初始化
隐式初始化,默认的构造函数 Stock::Stock(){}
也可以用new开辟
Stock stock1;//需要自定义一个默认构造函数
系统会提供一个隐式的默认构造函数
若是定义了非默认构造函数,则不能在声明一个没有参数的类对象
对象的参数可以有默认值
只能有一个默认构造函数
Stock first=Stock();//显示的使用默认构造函数
Stock first{"daf"};//隐式的调用构造函数
析构函数
若Stock类对象没有new开辟,就不需要析构函数,只需要提供一个什么都没有的析构函数就好
Stock::~Stock(){
}
析构函数一定没有参数
类对象过期时自动调用析构函数
构造函数被用来创造对象,而对象不能调用构造函数
默认构造函数和非默认构造函数可以同时存在
Stock first=Stock();会调用析构函数,相当于创建一个临时的对象,然后赋值给first对象,临时对象生命周期结束,自动调用析构函数。
类之间可以互相赋值
有些编译器会延迟析构函数的调用
初始化效率更高
const放在函数的括号后面,保证函数不会修改调用对象
构造函数也可以重载
一个参数的构造函数可以使用赋值语句
Bozo tubby=32;
this指针
一个对象调用另一个对象作为参数
const Stock & topval(const Stock & s) const;//后面加const,不能调用topval对象里面的所有成员数据
this指针设置为调用成员函数的对象的地址
stock1.topval(stock2);//this设置为stock1对象的地址
*this//对象
函数括号后面使用const,将this限定为const,这样将不能使用this来修改对象的值
*this//可作为调用对象的别名
对象数组
Stock stocks[SIZE]={
Stock{"aaa",12,23},
Stock("bbb",13,24),
Stock("ccc",14,15),
Stock("ddd",15,23)
};
析构函数后进先出执行
定义成员函数,需要使用作用域解析运算符
类声明的时候可以直接用。
const int Months=12;
double cost[Months];//12只有在创建对对象的时候才能确定
可以用枚举
enum{Months=12};//12是确定的,创建的符号常量
double costs[Months];
static const int Months=12;//可以使用static定义常量
enum class egg{Small,Medium};
enum class t_shirt{Small,Medium};//枚举量的作用域为类
egg choice = egg::Small;//也可使用关键字struct代替class,无论哪种方式,都需要枚举名来限定枚举量
作用域内,枚举不能隐式转换为整型
enum egg_old{small,medium};
未加限定,枚举常量可以被提升
if(king<medium)
加了限定,不能被提升
if(king<egg_old::medium)
必要时可显式类型转换
int Frodo= int(t_shirt::small);
默认情况下,作用域内枚举的底层类型为int
enum class : short pizza{small,medium};
:short将底层类型指定为short,必须是(短,长,普通)整型
抽象数据类型
栈来管理自动变量,添加到堆顶
isalpha(ch);//是否为字母字符
toupper(ch);//转换为大写
Item& 引用可以避免复制大型变量,提高效率
表示已存在变量的别名