关闭

C++ Primer 1-3

577人阅读 评论(0) 收藏 举报
分类:
再读C++ Primer


第一章:快速入门
编译器能查出的最常见错误:
1、语法错误
2、类型错误
3、声明错误


for和while选择
for用于次数已知的情况
while用于循环次数未知的情况,但有结束条件




文件结束符:
windows系统下Ctrl+z,Unix下Ctrl+D




第二章:变量和基本类型
基本内置类型:
char 8位
wchar_t 16位
short 16位
int 32位
long 32位
float 32位,6位有效数字
double 64位,至少10位有效数字




字面值整数常量的类型默认为int或long类型,其精度类型决定于字面值——其值适合int就是int型,比int大就是long型。通过增加后缀,能够强制将字面值整数常量转化为long,unsigned或unsigned long类型。通过在数值后面加L指定常量为long。
默认的浮点字面值常量为double类型。如128u, 1024UL


对象:对象就是内存中具有类型的区域。




初始化:
复制初始化:int ival=1024;
直接初始化:int ival(1024);
直接初始化更灵活且效率更高。


变量初始化规则:
1、内置类型变量在函数体外都初始化成0,在函数体内不惊醒自动初始化。
2、类类型变量初始化:大多数类提供了默认构造函数;没有默认构造函数的类,每个定义都必须显式的初始化。


声明和定义:
定义用于变量分配存储空间,还可以为变量指定初始值。声明用于向程序表明变量的类型和名字。可以通过使用
extern关键字声明变量名而不定义它,他只说明变量定义在程序的其他地方。当extern声明有初始化式,那么他可以被当做是定义,但extern声明只能在函数外部才可以含有初始化式,也就是全局变量。
如extern int i;//声明
  extern int i=0;//定义


const限定符:
1.定义const对象时必须初始化
2.const对象默认为文件的局部变量:与其他变量不同,除非特别声明,在全局作用域声明的const变量时定义该对象的文件的局部变量,此变量只存在那个文件中,不能被其他文件访问。但通过制定const变量为extern,就可以在整个程序中访问const对象。
如: //file_1.cc
extern const int bufSize = fcn();
//file_2.cc
extern const int bufSize;
for(int index = 0;index != bufSize; ++index)
非const变量默认为extern。要使const变量能够在其他的文件中访问,必须显式地指定它为extern。




引用:
在引用的情况下,每一种引用类型都关联到某一其他类型。不能定义引用类型的引用,但可以定义其他类型的引用。
引用必须用与该引用同类型的对象初始化。
引用时别名,初始化是指明引用指向哪个对象的唯一方法。




const 引用:只能const引用是指向const对象的引用,不能用非const引用指向const对象:
const int ival = 1024;
const int &refval = ival;//OK:both reference and object are const
int &ref2 = ival;//error: nonconst reference to a const object
可以读取但不能修改refval,因此任何对refval的赋值都是不合法的。这个限制有其意义:不能直接对ival修改,因此不能通过使用refval来修改ival。
同理,用ival初始化ref2也是不合法的:ref2是普通的非const引用,因此可以用来修改ref2指向的对象的值。通过ref2对ival赋值会导致修改const对象的值,为阻止这样的修改,需要规定将普通的引用绑定到const对象时不合法的。


const引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量,但非const引用不能初始化为字面值常量:
int i =42;
const int &r = 42; //OK
const int &r2 = r + i; //OK
int &j = 2; //error
同样的初始化对于非const引用确实不合法的,而且会导致编译错误。观察将引用绑定到不同类型时所发生的事情,最容易解释上述行为:
假如编写:
double dval =3.14; 
const int &ri=dval;
编译器会把这些代码转换成如下形式的编码:
int temp = dval;
const int &ri = temp;
如果ri不是const,那么可以给ri赋一新值。这样做不会修改dval,而是修改temp。期望对ri的赋值会修改dval的程序员会发现dval并没有被修改。仅允许const引用绑定到需要临时变量作为媒介来完全绑定过程的值,因为const引用时只读的。
非const引用只能绑定到与该引用同类型的对象,const引用则可以绑定到不同但相关的类型对象或绑定到右值。


enum:
枚举类型的对象的初始化或赋值,只能通过其枚举成员或同一枚举类型的其他对象来进行。


编程新手经常会忘记类定义后面的分号,这是个普遍的错误!




头文件:
头文件一般包括类的定义,extern变量的声明和函数的声明。
因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义,但有三个例外。头文件可以定义类,值在编译时就已知道的const对象和inline函数。
头文件可以定义值在编译时就已知道的const对象的原因:C++中的任何变量都只能定义一次。定义会分配存储空间,而所有对该变量的使用都关联到同一存储空间。因为const对象默认为定义它的文件的局部变量,所以把他们的定义放在头文件中是合法的。如果const变量不是用常量表达式初始化,那么它就不应该在头文件中定义。相反,和其他变量一样,该const变量应该在一个源文件中定义并初始化。




如果头文件名括在尖括号(<>)里,那么认为该头文件是标准头文件。编译器将会在预定义位置集查找该文件,这些预定义的位置可以通过设置路径环境变量或者通过命令行选项来修改。如果头文件名括在一对引号(" ")里,那么认为它是非系统头文件,非系统头文件文件的查找通常开始于源文件所在的路径。






第三章:标准库类型
Sring:
#include <string>
using std::string;




string对象初始化方式:
string s1; //默认构造函数,s1为空串
string s2(s1); //将s2初始化为s1的一个副本
string s3("value"); //将s3初始化为一个字符串字面值副本
string s4(n, 'c'); //将s4初始化为字符'c'的n个副本






string对象的读写:
string类型的输入操作符读取规范:
1.读取并忽略开头所有的空白字符(如空格,换行符,制表符)
2.读取字符直至再次遇到空白字符,读取终止




读入数目未知的string对,string的输入操作符也会返回所读的数据流,因此,可以把输入操作符作为判断条件。如:
int main()
{
string word;
while(cin >> word)
cout << word << endl;
return 0;
}
上例中,用输入操作符来读取string对象。如果输入流是有效的,即还未到达文件尾且未遇到无效输入,则执行while循环体;否则跳出循环。




用getline读取正行文本:
有用的string IO操作:getline。这个函数接受两个参数:一个输入流对象和一个string对象。getline函数从输入流的下一行读取,并保存读取到string中,但不包括换行符。只要getline遇到换行符,即便它是输入的第一个字符,getline也将停止读入并返回。如果第一个字符就是换行符,则string参数被置空。
如:
int main(){
string line;
while(getline(cin,line))
cout << line << endl;
return 0;
}


string对象的操作;
s.empty;
s.size(); //返回string::size_type类型,size_type是unsigned型,但不要把返回值赋给int型数据,因为int型数据可能太小
s[n]; //n应当为size_type型数据
s1+s2; //“+”左右操作数必须至少有一个是string型
//string s1 = "hello";// OK
//sting s2 = "word";
//string s3 = s1 + "ww"; //OK
//string s4 = "heoo" + "wdfe";//error,+两边都是字符串字面值
//string s5 = s1 + "dd" + "dew";//OK
//string s6 = "dew" + "dedew" + s1;//error
s1=s2; //必须先把s1中的内存释放,再分配足够存放s2的内存
v1==v2;
!=, <, <=, >和>=//如果两个string对象长度不同,且短的string对象与长的string对象的前面部分相匹配,则短的string对象小于长的string对象
//如果两个string对象的字符不同,则比较第一个不匹配的字符






C++中的头文件cctype其实就是利用了C标准库函数,这些库函数就定义在C标准库的ctype.h头文件中










vector:一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string对象一样,标准库负责管理与存储元素相关的内存。
#include <vector>
using std::vector;


vector不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector类型的每一种都指定了其保持元素的类型。因此,vector<int>和vector<string>都是数据类型。
vector对象的初始化方式:
vector<T> v1; //vector保存类型为T的对象。默认构造函数,v1为空
vector<T> v2(v1); //v2是v1的副本,v2和v1对象必须保存同一元素类型
vector<T> v3(n,i); //v3包含n个值为i的元素
vector<T> v4(n); //v4含有值初始化的元素的n个副本


vector对象的动态增长:
vector对象(以及其他标准容器对象)的重要属性就在于可以运行时高效地添加元素。虽然可以对给定的元素个数的vector预先分配内存,但更有效的方法是先初始化一个空的vector对象,然后再动态的增加元素。




值初始化:
vector值初始化取决于存储在vector中元素的数据类型。
如果vector保存内置类型(如int)的元素,那么标准库将用0值创建元素初始化式!
vector<int> fvec(10); //10 elements,each intialized to 0;
如果保存的事含有构造函数的类类型(如string)的元素,标准库将用该类型的默认构造函数初始化!
vector<string> svec(10); //10 elements, each intialized to empty string




vector对象的操作:
v.empty();
v.size(); //返回vector<T>::size_type,如vector<int>::size_type,vector<string>::size_type
v.push_back(t); //在v的末尾增加一个值为t的元素
v[n];
v1 = v2;
v1 == v2;
!=, <,<=,>,>=




vector下标操作不添加元素,但string下标操作添加元素
vector<int> ivec;
for(vector<int>::size_type ix=0;ix != 10; ++ix)
ivec[ix] = ix;
上式错误,因为ivec是空的vector对象,而且下标只能用于获取已存在的元素。
正确用法如下:
for (vector<int>::isze_type ix =0; ix !=10;++ix)
ivec.push_back(ix);
vector必须是已存在的元素才能用下标操作符进行索引,通过下标操作进行赋值时,不会添加任何元素,但可以改变元素。






迭代器(iterator):
容器的iterator类型:
如vector<int>::iterator iter;


begin和end操作:
vector<int>::iterator iter=ivec.begin();
若vector不空,则iter即指该元素为ivec[0];
由end操作返回的迭代器指向vector的“末端元素的下一个”,通常称为超出末端迭代器,表明它指向了一个不存在的元素。
如果vector为空,begin返回的迭代器和end返回的迭代器相同。
由end操作符返回的迭代器并不指向vector中任何实际的元素,相反,它只是起一个哨兵的作用,表示我么已处理完vector中所有的元素。






迭代器可使用解引用操作符(*)来访问迭代器所指向的元素。由于end操作符返回的迭代器不指向任何元素,因此不能对它进行解引用或者自增操作。
迭代器的操作符:
== //如果两个迭代器指向同一个元素,则相等否则不相等。
!= //
iter + n;
iter - n;
iter1 - iter2; //返回difference_type的signed类型的值,计算两个迭代器对象的距离




用迭代器编写循环:、
for(vector<int>::iterator iter = ivec.begin();iter != ivec.end();++iter)
*iter = 0; //如果ivec为空,则ivec.begin()和ivec.end()一样不指向任何元素,测试条件立即失败






当对普通iterator类型解引用时,得到对某个元素的非const引用。而如果对const_iterator类型解引用时,则可以得到一个指向const对象的引用,如果常量一样,该对象不能重写。使用const_iterator类型时,我们得到一个迭代器,它自身的值可以改变,但不能用来改变其所指的元素的值。可以对迭代器进行自增以及使用解引用操作符来读取值,但不能对该元素值赋值。
const_iterator:该类型只能用于读取容器内的元素,但不能改变其值。
for(vector<string>::const_iterator iter=text.begin();iter !=text.end();++iter)
cout << *iter << endl;//OK


for(vector<string>::const_iterator iter=text.begin();iter !=text.end();++iter)
*iter = 0; //error


不要把const_iterator对象和const的iterator对象混淆。声明一个const迭代器时,必须初始化迭代器,一旦初始化后就不能改变他的值。
vector<int> nums(10); //num is nonconst
const vector<int>::iterator cit=nums.begin();
*cit = 1; //OK
++cit; //error:can't chang the value of cit






bitset类型
#include<bitset>
using std::bitset;




bitset类是一种类模板,在定义biset时,要明确bitset含有多少位,须在尖括号内给出它的长度值。
bitset<32> bitvec;
给出的长度必须是常量表达式。长度值必须定义为整形字面值常量或者是已用常量值初始化的整形const对象。




bitset对象的初始化方法:
bitset<n> b; //b有n位,
bitset<n> b(u); //b是unsigned long型u的一个副本;每位都为0;
bitset<16> bitvec1(0xffff);//bits 0....15为1;
bitset<32> bitvec2(0xfffff);//bits 0....15为1;16...31为0
bieset<n> b(s); //b是string对象s中含有位串的副本;从string对象读入位集的顺序是从右到左:
string strval("1100");bitset<32> bitvec4(strval);//bitvec4的第2和3位为1,其余为0;
bieset<n> b(s,pos,n); //b是s中从位置pos开始的n个位的副本;string str("1111111000000011001101");bitset<32> bitvec5(str,5,4);//4bits staring at str[5],1100,初始化bitset对象时总是从字串最右边结尾字符开始,也就是bitvec5的索引从3到0的二进制位置为1100,其他二进制都为0;
//如果省略第三个参数意味着从开始位置已知道string末尾的所有字符


bitset对象的操作:
b.any(); //b中是否存在置为1的二进制位
b.none(); //b中是否不存在置为1的二进制位
b.count(); //b中存在置为1的个数
b.size(); //b的二进制位数,返回size_t类型,该类型定义在cstddef头文件中
b[pos]; //访问b中pos处的二进制位
b.test(pos); //b中在pos处的二进制位是否为1
b.set(); //把b中所有二进制位都置为1
b.set(pos); //pos处置为1
b.reset(); //全置为0
b.reset(pos); //pos置为0
b.flip(); //所有都取反
b.flip(pos); //pos处取反
b.to_ulong(); //用b中同样的二进制位返回一个unsigned long值
os << b; //把b中的位集输出到os流
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:179170次
    • 积分:3735
    • 等级:
    • 排名:第8671名
    • 原创:205篇
    • 转载:12篇
    • 译文:1篇
    • 评论:21条
    博客专栏
    最新评论