C++ primer(5th)一~三章
第一章
- for循环和while循环的区别
在for循环中,循环控制变量的初始化和修改都放在语句头部分,形式较简洁,且特别适用于循环次数已知的情况。在while循环中,循环控制变量的初始化一般放在while语句之前,循环控制变量的修改一般放在循环体中,形式上不如for语句简洁,但它比较适用于循环次数不易预知的情况(用某一条件控制循环)。两种形式各有优点,但它们在功能上是等价的,可以相互转换。
第二章
2.1基本内置类型
-
一个字(word)由4或8字节(byte)构成,一个字节由8比特(bit)构成;
-
字符串实际是由常量字符构成的数组,编译器在字符串结尾加“\0”,所以实际长度比本身内容多1,例字符串“A”包含两个字符
2.2变量 -
对象(object)是一块能存储数据并具有某种数据类型的内存空间;
-
默认初始化:如果定义变量时未指定初值,则变量会被默认初始化
默认初始化的三条性质:
(1)定义在任何函数体外的变量会被初始化为0;
(2)定义在函数体内部的变量不会被初始化;
(3)类的对象未被初始化,则初值由类决定 -
声明与定义
声明:声明确定变量名字和类型,使用变量前必须先声明
定义:申请存储空间,可能会赋予初始值
extern int i; //声明不定义extern int pi=3; //定义int j; //声明且定义
变量可多次声明,但只能一次定义; -
新建的局部变量可以覆盖同名的全局变量,::reused可以显式的访问全局变量
2.3复合类型:引用和指针
引用(reference):定义引用时,程序会把引用及其初始值绑定在一起,而不是将初始值拷贝给引用(引用即别名)
例:
int &refval = ival; //refval指向ival(refval是ival的另一个名字)refval = 2; //把2赋给refval指向的对象,即赋给ivalint ii = refval //与ii = ival一样int &ref3 = refval; //ref3与refval绑定,ref3与ival绑定
*注意:*引用的类型与绑定对象一致,引用所绑定的初始值必须是对象,不能是值;
指针(pointer):指向另外一种类型的复合类型,指针存放某个对象的地址
指针的类型必须与其所指对象的类型一致
例:
int*ip1,*ip2,ip5; // ip1和ip2都是指向int 型对象的指针,ip5是int;int ival=42;int *p=&ival; //p存放ival的地址,或说p是指向变量ival的指针,或说初始值是int 型对象的地址;cout<<*p; //由解引用符“*”得到指针p所指的对象,输出42;int *p3=p; //初始值为int类型对象的指针,也就是指针的指针*p=0; //为p所值的对象赋值cout<<*p;//输出0;int *p2=p; //初始值是指向int型对象的指针;p2=&ival; //p2指向ival;*p2=0; //ival的值被改变为0,指针p2没有改变,
指针和引用的区别::(1)指针本身是一个对象,允许对指针赋值和拷贝,可先后指向不同的对象;
(2) 引用本身并非一个对象,引用只能绑定一次对象;
(3)指针无需在定义时赋初值;
空指针:不指向任何对象
例:
int *p1=nullptr;int *p2=0;int *p3=NULL;
void*指针:可存放任意类型对象的地址
指向指针的指针:
int ival =1024;int *pi=&ival; //pi指向一个int型的数,pi是指向int型数的指针int **ppi=π //ppi指向一个int型的指针,ppi是指向int型指针的指针cout<<ival;//输出1024;cout<<*pi; //输出1024;cout<<**ppi; //输出1024;//**
指向指针的引用:
int i=42;int *p; //p是一个int型指针int *&r=p; //r是一个对指针p的引用r=&i; //令p指向i;*r=0; //将i值改为0;
2.4 const:把变量定义成常量,const对象必须初始化
const int i=9; // 编译时初始化const int j=getsize(); //运行时初始化
默认状态下const对象只在文件内有效,若想多文件共享const对象,需要加extern
如: extern const int butsize=fcn(); //定义并初始化一个常量,该常量能被其他文件访问到
8.1const的引用:
对常量的引用(reference to const):把引用绑定在const对象上
const int ci=1024;const int &ri=ci; //引用及其对象都是常量,允许将const int &绑定在一个普通int对象上ri=42; //错误,ri是对常量的引用,不可修改值int r2=&ci;//错误,非常量引用不可指向常量对象
**指向常量的指针(pointer to const):**不能改变其所指对象的值,但未规定所指对象必须是常量
const double pi=3.14;
double *ptr=&pi; //错,ptr是普通指针
const double *ptr=&pi; //正确
*ptr=42; //错,不能给pi赋值
double dval=3.14;
cptr=&dval; //正确,但不能通过cptr改变dval的值
**常量指针(const pointer) :**必须初始化,初始化后存放在该指针中的地址不能改变,不变的是指针本身的值,不是指向的那个值
int err=0;
int *const cur=&err; //cur是常量指针 cur将一直指向err;
*cur=10; //正确,err的值可以改变
const double pi=3.14;
const double *const pip=&pi; //pip是一个指向常量对象的常量指针 (从右往左看类型)
顶层const:指针本身是常量
底层const:指针所指的对象是常量
int i=0;int *const pi=&i; //不能改变pi的值,是顶层constconst int ci=42; //不能改变ci的值,是顶层constconst int *p2=&ci; //允许改变p2的值,不能改变ci的值,是底层constconst int *const p3=p2; //左边是底层const,右边是顶层constconst int &r=ci; //用于声明引用的是底层const
顶层const拷贝不受限制
底层const的拷贝的对象必须有底层const的资格
非常量可以赋值给常量
8.2 常量表达式:值不改变,在编译过程中能得到计算结果的表达式
**constexpr变量:**若认定变量是一个常量表达式,就将其声明为constexpr类型。
在constexpr声明中若定义指针,则仅对指针有效,与指针所指值无关。
const int *p=nullptr; //p是一个指向整型常量的指针
constexpr int *q=nullptr; //q是一个指向整数的常量指针
2.5处理类型
2.5.1类型别名
2.5.1.1使用typedef
typedef double wages; //wages是double的同义词
typedef wages base,*p; // base是double的同义词,p是double*的同义词
2.5.1.2使用别名声明: using SI=sale; //SI是sale的同义词;
typedef char * ps; //ps是char*的同义词,ps是指向char的指针,ps是一个指针
const ps cstr=0; //cstr是指向char的**常量**指针,而非指向常量字符的指针
const ps *ps; //ps是一个指针,它的对象是指向char的常量指针;
2.5.2auto类型说明符
a.编译器会自动判别类型
b.auto语句中类型必须一致
c.auto会自动忽略顶层const,保留底层const
d.auto定义的变量必须有初始值
auto i=0;*p=&i; //i是整数,p是整型指针
int j=0,&r=j;
auto a=r; //a是整数
2.5.3decltype类型提示符
decltype(f())sum=x; //sum的类型就是函数f的返回类型
decltype((variable))的结果是引用(如int&类型),decltype(variable)结果只有当variable是引用时才是引用。
赋值的表达式语句本身就是一种引用:如int a=3,b=4; decltype(a=b)d=a; //d是int&类型
2.5.4auto与 decltype的区别:如果使用引用类型,auto识别为其所指对象的类型, decltype识别为引用的类型
2.6自定义数据结构
第三章
3.2标准库类型string(表示可变长的字符序列)
3.2.1定义和初始化string对象
string s4(10,'c'); //s4的内容是ccccccccccc
string s2(s1); //s2是s1的副本 等价于string s2=s1;
string s3("value"); //直接初始化 //等价于string s3="value";
string s4="value" //拷贝初始化
3.2.2string对象上的操作
//输入输出
string s; //空字符串
cin>>s; //将string对象(自动忽略开头的空白,即空格,转换,制表符等,从第一个字符开始到空白结束)读入s,遇到空白停止
cout<<s<<endl; //输出s;string s1,s2;
cin>>s1>>s2; //第一个输入读到s1中,第二个输入读到s2中//使用getline读取一整行
string line;
//每次读入一整行,遇到换行符为止,直至到达文件末尾
while(getline(cin, line))cout<<line<<endl; //line中不包含换行符//empty
string line;
//每次读入一整行,遇到空行直接跳过
while(getline(cin, line))
if(!line.empty()) //s.empty()为空返回true,否则返回false
cout<<line<<endl;//size()
string line;
while(getline(cin, line))
if(line.size()>80)//返回string中字符个数(无符号整型数),返回size_type类型的值
cout<<line<<endl;//比较string对象
相等:长度相同且所包含字符全部相同
例:a<b<c
string a="hello";
string b="hello world";
string c="hiya"//赋值
st1=st2;//相加
string s1="hello" s2="world\n";
string s3=s1+s2; //s3的内容是helloworld\n
s1+=s2;
//每个加号左右至少有一个是string
string s4=s1+","; //正确: 把一个string对象和一个字面值相加
string s5="hello"+","; // 错误,两个对象都不是string
string s6=s1+","+"world"; //正确
string s7="hello"+","+s2; //错误,字面值不能直接相加//处理每个字符
string str("some string");
//每行输出str中的一个字符
for(auto c:str) //对于str中的每个字符
cout<<c<<endl; //输出当前字符,后面紧跟一个换行符;//使用范围for语句改变字符串中的字符(变量定义为引用类型)
string s("Hello world\n");
for( auto &c:s)
c=toupper(c);// C是引用,所以改变的是s的值
cout<<s<<endl; //输出结果为"HELLO WORLD"//处理部分字符
1.使用下标[],返回的是该位置上字符的引用,string对象下标从0计起,s[s.size()-1]是最后一个字符,下标是string::size_type()类型
2.使用迭代器
3.3标准库类型vector:同类型对象的集合
#include
using std::vector;//编译器根据模板vector生成两种不同类型
vector<int> ivec; //ivec保存int 类型的对象
vector<vector<string>>file; //该向量的元素是vector对象
3.3.1定义和初始化vector对象
vector<int> ivec; //初始状态为空
vector<int>ivec2(ivec); //把ivec的元素拷贝给ivec2;同ivec2=ivec
//列表初始化
vector<string>arc={"a","an","the"}; //vector对象包含三个元素//创建指定数量的元素
vector<int>ivec(10,-1); //10个int型元素,每个都被初始化为-1//值初始化
vector<int>ivec(10); //10个元素,每个都初始化为0;
vector<int>ivec{10}; //1个元素,初始值为10;
vector<string>svec(10); //10个元素,每个都是空string 对象
vector<int>vi=10; //错误,必须使用直接初始化的形式指定向量大小
vector<int>ivec{10,-1}; //2个int型元素,初始值为10,-1
vector<string>v7{10}; //10个默认初始化的元素//添加元素
vector<int>v2; //空vector对象
for(int i=0;i!=100;++i)
v2.push_back(i); //依次把整数值放到v2末端
string word;
vector<string>text;
while(cin>>word){text.push_back(word); //把word添加到text后面
}
//其他操作
v.empty(); //v不含元素返回真
v.size() //返回v中的元素个数
v[n]; //返回v中第n个位置的引用vector<int>{1,2,3,4,5,6};
for(auto &i:v) //i是v的引用,可通过i给v赋值
i*=i;
for(auto i:v)
cout<<i<<endl;//计算索引
vector对象下标从0开始,下标运算符可以访问已存在的元素,而不能用于添加元素
3.4迭代器iterator
3.4.1使用迭代器
auto b=v.begin(),e=v.end(); //b表示v的第一个元素,e表示v尾元素的下一个元素
//begin负责返回指向第一个元素的迭代器
//若容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器
//若两迭代器指向元素相同,则他们相等
*iter; //返回迭代器iter所指元素的引用
iter->mem; //解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem;
++iter; //令iter指示容器中的下一个元素//迭代器类型
vector<int>::iterator it; //it能读写vector的元素
string::iterator it2; //it2能读写string对象中的字符
vector<int>::const_iterator it3; //it3只能读不能写(不能修改它所指的元素值)vector的元素
//若对象是常量,begin和end返回const_iterator
//若对象不是常量,返回iterator
//所有vector和string对象返回值都是const_iterator;(*it).empty() //解引用it,然后调用结果对象的empty成员
但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
3.4.2迭代器运算
//算数运算
//计算得到最接近vi中间元素的一个迭代器
auto mid=vi.begin()+vi.size()/2; //假设vi.size()==10,则mid==vi[10]//使用迭代器完成二分搜索
auto beg=text.begin(),end=text.end();
auto mid=text.begin()+(end-beg)/2;
while(mid!=end && *mid!=sought) {
if(sought<*mid)
end=mid;
else
beg=mid+1;
mid=beg+(end-beg)/2;
}
3.5 数组 数组大小确定不变,vector大小可变
3.5.1定义及初始化
int arr[10]; //含有十个整数的数组
int si=32;
int *p[si]; //含有32个整型指针的数组
//不允许使用auto推断数组类型;
//不存在引用的数组;
int a3[5]={0,1,2}; //等价于a3[5]={0,1,2,0,0};
string as[3]={"hi","wolld"}; //等价于as[3]={"hi","wolld",""};
int a5[2]={0,1,2}; //错误,初始值过多
//字符数组的特殊性
char a1[]={‘x’,‘a’,‘b’}; //维度为3
char a2[]={‘x’,‘a’,‘b’,‘\0’}; //维度为4
char a3[]=“c++”; //维度为4
//不允许拷贝和赋值
int a[]={0,1,2};
int a2=a; //错误
a2=a; // 错误
//复杂的指针声明
//从右往左看
int *ptrs[10]; //ptrs是含有10个整型指针的数组
int &res[10]=; //错误,不存在引用的数组
//从内往外看,先右后左
int (*par)[10]=&arr; //par指向一个含有10个整数的数组
int (&aar)[10]=arr; //aar引用一个含有10个整数的数组
int *(&array)[10]=ptrs; //arr是数组的一个引用,该数组含有10个int指针
3.5.2访问数组元素
数组索引从0开始
3.5.3指针和数组
string nums[ ] = {“one”,“two”,“three”}; //数组的元素是string对象
string *p=&nums[0] ; //p指向nums的第一个元素,等价于string *p=nums;
int ia[]={0,2,3,4,5,6};
auto ia2(ia); //ia2是一个整型指针,指向ia的首元素
ia2=ia; // 错误,ia2是一个指针
//decltype(ia) 返回的类型是由10个整数构成的数组
decltype(ia) ia3={0,1,2,3,4,5,6,7,8,9};
ia3=p; //错,不能用整型指针给数组赋值
//指针也是迭代器
string nums[ ] = {“one”,“two”,“three”}; //数组的元素是string对象
string *p=&nums[0] ; //p指向nums的第一个元素,等价于string *p=nums;
++p; //p指向nums[1]
string *e=&nums[3]; //指向nums尾元素的下一个位置的指针
不能对尾后指针执行解引用和递增的操作
//标准库函数begin和end
int ia[ ] = {0,1,2,3,4,5,6,7,8,9}; //ia是一个含有十个整数的数组
int *beg=begin(ia); //指向ia首元素的指针
int *last=end(ia); //指向arr尾元素的下一位置的指针
while(beg!=last&&*beg>=0) //寻找第一个负值元素
++beg;
int *ip=ia;
int ip2=ip+4; //ip2指向ia[4]
auto n=ens(ia)-begin(ia); n=10,即数组中元素的数量
int la=(ia+4); //la4
la=*ia+4; //la=0+4=4;
int *p=&ia[2]; //p指向索引为2的元素
int j=p[1]; //即j=ia[3]=3;
int k=p[-2]; //即k=ia[0];
3.5.4c风格字符串
strlen§; //返回p的长度,空字符不计算在内
strcmp(p1,p2) //比较,p1p2,返回0;大于返回正值,小于返回负值
strcat(p1,p2) //P2加在p1后,返回p1
strcpy(p1,p2) //p2拷贝给p1,返回p1
3.6多维数组
int[3][4]; //大小为3的数组,每个元素是含有4个整数的数组
int ia[3][4]={1,2,3,4}; //初始化第一行的4个元素,其他元素初始化为0
int (&row)[4]=ia[1]; //把row绑定在ia的第二个4元素数组上
使用for循环处理多维数组,除了最内层数组,其他层都是引用类型
for(const auto &row:ia ) //外层数组
for(auto col:row) //内层数组
cout<
指针和多维数组
int ia[3][4]; //大小为3的数组,每个元素是含有4个整数的数组
int(*p)[4]=ia; //p指向含有4个整数的数组
p=&ia[2]; //p指向ia的尾元素
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
