《CPrimer》全书第一轮学习笔记汇总.docx
《《CPrimer》全书第一轮学习笔记汇总.docx》由会员分享,可在线阅读,更多相关《《CPrimer》全书第一轮学习笔记汇总.docx(72页珍藏版)》请在冰豆网上搜索。
《CPrimer》全书第一轮学习笔记汇总
《C++Primer》全书第一轮学习笔记汇总(2011.10.02)
《C++Primer》整书学习笔记前言
第00章:
前言
——此次决定了写《C++Primer》的学习笔记,刚开始时没有想到怎么个写法,是学完一章后直接写章结还是怎样,不知道,后来,在学习的时候,发觉,有很多细节还是很有用的,不想忘了它们,而之前我又学过《C++PrimerPlus》,也有一些内容已经熟记在心里了,所以,现在决定了写这个学习笔记的模式,方法,框架是怎样了。
——首先,我会整章阅读一次,在认为对自己很有帮助,或者是之前还没有接触过的知识点做上记号;然后,这一章结束后,有时我会将其先写到草稿本上;之后,我会将其录入电脑,在录入的时候顺带再强化记忆,然后,如果有些有地方有想说的话的时候,会在后面加一个“摘录有想”说出自己想说的东西,不过有时候太累赘的话就不说了。
——我会经常反复阅读自己的笔记,当然,知道最主要的是上机实践,不懂的时候再返回书本中的内容去看,去练。
——有人说,这本书你可以直接当作字典去查,不用这样一章章地看下去,但是,我想的是,假如连字典中有些什么内容也不知道,提到过的一些知识点不知道的话,需要用到的时候一点反应都没有,怎么往这里去查呢?
所以,我还是决定,将这本书看一遍,有些地方细看,有些地方粗看,那么等真正需要用的时候,就可以很快地想出曾经有这么一个东西可以用,曾经书上有提过这么一个东西了。
——我从08月21日开始看了这本书,但是那时还没有开始想到要做笔记,因为害怕看了书后也会没看过一样,吸收不到什么,不知道自己看过什么,所以,我决定了做笔记。
之前一段时间,一直有不少的琐事做着,让我不得连续在这个阵线上学习。
现在,事情很大部分已经解决了,除了每天的上课课程这些学习类的东西干扰这个任务外,基它就基本没有什么了,所以,我接下来,会在兼顾现在的学校的专业课教学内容的同时,做完这本《C++Primer》的学习笔记,现在已经是2011年09月07日了,大二了,计划2011年10月15日前,将此任务完成。
——当然,会做好计划往往赶不上变化的准备。
那时就,具体问题具体分析。
嗯,加油!
《C++Primer》第一部分学习笔记汇总——基本语言
《C++Primer》第1章学习笔记
第01章:
快速入门
这一章,书上用了一个例子贯穿每部分的内容,“书店的书本销售情况”(包括销售册数与单价)。
第二节:
介绍输入与输出
@学习摘录001:
——endl称为操纵符(manipulator),可刷新与设备相关联的缓冲区。
——在刷新缓冲区时,用户可立即看到写入到流中的输出。
——程序员经常在调试过程中插入输出语句,这些语句都应刷新输出流。
摘录有想001:
——这几句让我想起之前自己以及朋友们出现过的错误,当if(!
cin)时,只是cin.clear()是不够的,还需要用cin.sync()清空缓冲区或者用while(cin.get()!
=‘\n’)continue;提取多余字符。
看来以后得多注意输入输出缓冲区了。
第三节:
关于注释
@学习摘录002:
——当注释多行时,最好能直观指明每一行都是注释。
摘录有想002:
——这让我注意到了之前没怎么注意的问题,看《数据结构与算法分析》的一书上是用了这样的格式的,才发觉原来那书的编译习惯是不错的。
/*
*now,foraexample.
*likethis.
*/
第四节:
控制结构
@学习摘录003:
——关于控制结构我想到的是之前《C++PrimerPlus》上提到过,循环(判断条件),条件if(判断条件)都会将括号内的内容转换为bool型作为执行与否的依据的。
@学习摘录004:
——编译器能查出的最普通的错误1.语法错误 2.类型错误 3.声明错误
摘录有想004:
——知道编译能检查出错误的话,在编译习惯上有些就可以利用这一点了,可以避免在调试的时候才发现错误了,这也是一个网友跟我说过起的。
如:
if(i=1),将其写为if(1=i)的话就能在编译时检测出自己要写的是if(1==i)了。
第五节:
类的简介
@学习摘录005:
——什么是成员函数:
成员函数是由类定义的函数,有时称为“类方法”(method)
@学习摘录006:
——使用类时需注意的三个问题:
——1.类的名字是什么?
2.它在哪里定义?
3.它支持什么操作?
摘录有想006:
——很多同学不明确的一点是第3点,之前我看同学的程序时,问同学你的这个类想要实行什么样的功能时,他自己也答不上。
《C++Primer》第02章学习笔记
第02章:
变量和基本类型
这一章,主要讲述了常量,变量和一些类型的使用方法,注意事项。
第三节:
变量
@学习摘录007:
——C++是一门静态类型语言,在编译的时候会作类型检查,静态类型检查能帮助我们更早地发现错误。
摘录有想007:
——静态类型使得编译器必须能识别程序中每个实体的类型。
假如没有定义或定义错的时候就能检查出来啦。
@学习摘录008:
——左值:
lvalue,左值可以出现在赋值语句的左边或右边。
——右值:
rvalue,右值只能出现在赋值的右边,不能出现在赋值语句的左边。
——变量是左值,因此可以出现在赋值语句的左边,数字字面是右值,因此不能被赋值。
摘录有想008:
——在我理解中,因为变量可在左也可在右,因此它为左值,而数字则只能出现在右边,因此它为右值。
@学习摘录009:
——变量提供了可以操作的有名字的存储区,对象就是内存中具有类型的区域。
摘录有想009:
——例如:
inta;classb{};bc;这里,a和c属于对象。
@学习摘录010:
——初始化变量不是赋值。
——初始化:
指创建变量并给它赋初始值。
——赋值:
是擦除对象的当前值并用新值代替。
@学习摘录011:
——初始化变量有两种形式。
——1.intival(1024);//direct-initialization直接初始化
——2.intival=1024;//copy-initialization复制初始化
@学习摘录012:
——复制初始化和直接初始化之间的差别是很微妙的。
——现在我们只需知道,直接初始化的效率更高。
@学习摘录013:
——未初始化变量引起的错误难以发现,永远不要依赖未定义行为,使用未初始化的变量是常见的程序错误。
虽然许多编译器都至少会提醒不要使用未初始化变量,但是编译器并未被要求去检测未初始化变量的使用。
而且,没有一个编译器能检测出所有未初始化变量的使用。
@学习摘录014:
——extern声明不是定义,也不分配存储空间。
——事实上,它只是说明变量定义在程序的其他地方。
摘录有想014:
——extern的使用得注意,一个文件里面放定义,另外一个文件里面放声明才可以,上次同学就是犯了这样的错误,没有在另一个文件中声明就想用extern变量了。
@学习摘录015:
——只有当声明也是定义时,声明才可以有初始化式,因此只有定义才分配存储空间。
@学习摘录015:
——看来下次写程序时真的要直接在声明的时候就定义好,那样的话就安全多了。
@学习摘录016:
——作用域可以分为三种:
——1.全局作用域(globalscope)
——2.局部作用域(localscope)
——3.语句作用域(statementscope)
摘录有想016:
——有语句for(intval=1;val<=10;++val)sum+=val;
——此处,val定义在for语句的作用域中,只能在for语句中使用,而不能在main函数的其他地方。
@学习摘录017:
——通常把一个对象定义在它首次使用的地方是一个很好的办法。
放置声明的一个约束是,变量只在从其定义处开始到声明所在的作用域的结束才可以访问。
第五节:
引用
@学习摘录018:
——“const引用”的意思是“指向const对象的引用”。
@学习摘录019:
——非const引用只能绑定到与该引用同类型的对象。
——const引用则可以绑定到不同但相关的类型对象或绑定到右值。
第八节:
类类型
@学习摘录020:
——每类都定义了一个接口(interfer)和一个实现。
——接口由使用该类的代码需要执行的操作实组成。
——实现一般包括该类所需要的数据。
——类体定义了组成该类型的数据和操作。
操作称为成员函数,数据则称为数据成员。
@学习摘录021:
——用class和sturct关键定义类的唯一差别在于默认访问级别:
默认情况下,struct的成员为pulbic,而class的成员为private.
@学习摘录022:
——当我们在头文件中定义了const变量后,每个包含该头文件的源文件都有了自己的const变量,其名称和值一样。
@学习摘录023:
——避免多重包含,为了避免多重包含,避免名字冲突,预处理器变量经常用全大写字母表示。
#ifndefABC_H
#defineABC_H//DefinitionofABCclassandrelatedfunctionsgoeshere
#endif
摘录有想023:
——看了这么多书,这么多个例子,终于知道为什么它总是用大写来表示了。
《C++Primer》第03章学习笔记
第03章:
标准库类型
C++还定义了一个内容丰富的抽象数据类型标准库,其中最重要的标准库类型是string和vector,它们分别定义了大小可变的字符串和集合。
另一种标准库类型bitset提供了一种抽象方法来操作位集合。
第一节:
命名空间using声明
@学习摘录024:
——一旦使用了using声明,我们就可以直接引用名字,而不需要再引用该名字的命名空间:
——//usingdeclarationstatesourintenttousethesenamesfromthenamespacestd.
——usingstd:
:
cin;
——usingstd:
:
string;
@学习摘录025:
——如果在头文件中放置using声明,就相当于在包含该文件的每个程序中都放置了同一个using声明,不论该程序是否需要using声明。
摘录有想025:
——我想这相当于全局变量跟局部变量的作用吧。
@学习摘录026:
——通常头文件中应该只定义确实必要的东西。
请养成这个习惯。
摘录有想026:
——书上建议少用usingnamespacestd这样的风格,以后写程序就尽量用using声明吧,少用using编译指令。
第二节:
标准库string类型
@学习摘录027:
string操作
——s.empty()//检查字符是否为空,bool类型
——s.size();//返回s中字符的个数
——s[n];// 返回s中位置为n的字符,位置从0开始计数
摘录有想027:
——以前还不知道原来有empty()这一操作,初见empty还以为要清空这个对象的数据呢,其实不然,是检查字符串是否为空。
If(s.empty())//ok,empty
@学习摘录028:
——size操作返回的是string:
:
size_type类型的值。
String类类型和许多其他库类型都定义了一些配套类型(companiontype)。
通过这些配套类型,库类型的使用就能与机器无关(machine-independent)。
Size_type就是这些配套类型中的一种。
它定义为unsigned型(unsignedint或unsignedlong)具有相同的含义,而且可以保证足够大能够存储任意string对象的长度。
摘录有想028:
——写程序时不要把size的返回值赋给一个int变量了。
@学习摘录029:
——如在有16位int型的机器上,int类型变量最大只能表示32767个字符的string对象,而能容纳一个文件内容的string对象轻易就会超过这个数字。
因此,为了避免溢出,保存一个string对象size的最安全的方法就是使用标准库类型string:
:
size_type
@学习摘录030:
——string对象比较操作是区分大小写的,即同一个字符的大小写形式被认为是两个不同的字符。
在多数计算机上,大写的字母位于小写字母之前;任何一个大写字母都小于任意的小写字母。
摘录有想030:
——在比较时需注意大小写了,想起以前cctype有一个用于转换字符的函数,把大写转为小写之类的功能可以很容易实现。
@学习摘录031:
——string类型通过下标操作符([])来访问string对象中的单个字符。
下标操作符需要一个size_type类型的值,来标明要访问字符的位置。
这个下标中的值通常被称为“下标”或“索引(index)”。
@学习摘录032:
——string对象的下标从0开始,而s[s.size()–1]则表示s的最后一个字符。
第三节:
标准库vector类型
@学习摘录033:
——虽然可以对给定元素个数的vector对象预先分配内存,但更有效的方法是先初始化一个空vector对象,然后再动态地增加元素。
@学习摘录034:
——C++程序员习惯于优先选用!
=而不是<来编写循环判断条件。
@学习摘录035:
——我们倾向于在每次循环中测试size的当前值,而不是进入循环前,存储size值的副本。
调用size成员而不保存它返回的值,这反映了一种良好的编程习惯。
摘录有想035:
——以后在使用for时,可以注意一下这个问题了。
第四节:
迭代器简介。
@学习摘录036:
——迭代器是一种检查容器内元素并遍历元素的数据类型。
若一种类型支持一组确定的操作(这些操作可用来遍历容器内的元素并访问这些元素的值),我们就称这种类型为迭代器。
@学习摘录037:
——vector:
:
iteratoriter=ivec.begin();
——由end操作返回的迭代器指向vector的“末端元素的下一个”,通常称为超出未端迭代器(off-the-enditerator),表明它指向了一个不存在的元素。
如果vector为空,begin返回迭代器与end返回的迭代器相同。
@学习摘录038:
——由end操作返回的迭代器并不指向vector中任何实际的元素,相反,它只是起一个哨兵(sentinel)的作用,表示我们已经处理完vector中所有的元素。
@学习摘录039:
——迭代器类型可以使用解引用操作符(*操作符)来访问迭代器所指向的元素:
*iter=0;由于end返回的迭代器不指向任何元素,因此不能对它进行解引用或自增操作。
@学习摘录040:
——使用const_iterator类型时,我们可以得到一个迭代器,它自身的值可以改变,但不能用来改变其指向的元素的值。
可以对迭代器进行自增以及使用引用操作符来读取值,但不能对该元素值赋值。
《C++Primer》第04章学习笔记
第04章:
数组和指针
第二节:
指针的引入
@学习摘录041:
——指针的概念很简单,指针用于指向对象。
与迭代器一样,指针提供对其所指对象的间接访问,只是指针结构更通用一些。
与迭代器不同的是,指针用于指向单个对象,而迭代器只能用于访问容器内的元素。
@学习摘录042:
——如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可避免定义一个未初始化的指针,如果必须分开定义指针和其所指针的对象,则将指针初始化为0,因为编译器可检测出0值的指针,程序可判断该指针并未指向一个对象。
摘录有想042:
——我想这也就是说,定义指针最好有初始化,避免不必要的错误。
@学习摘录043:
——预处理器变量不是在std命名空间中定义的,因此其名字应为NULL,而非std:
:
NULL。
@学习摘录044:
——C++提供了一个特殊的指针类型void*,它可以保存任何类型对象的地址。
——void*主要用于以下三种操作:
——1.与另一个指针进行比较
——2.向函数传递void*指针或从函数返回void*指针
——3.给另一个void*指针赋值
doubleobj=3.14;
double*pd=&obj;
//ok,void*canholdtheaddressvalueofanydatapointertype
void*pv=&obj;//objcanbeanobjectofanytype
pv=pd;//pdcanbeapointertoanytype
@学习摘录045:
指针与引用的区别
——指针与引用的相同点:
都可间接访问另一个值
——第一区别:
引用总指向某个对象,定义引用时设有初始化是错误的。
——第二区别:
赋值行为的差异:
给引用赋值修改的是该引用所关联的对象的值,而不使引用与别一个对象关联。
@学习摘录046:
——C++允许计算数组或对象的超出未端的地址,但不允许对此进行解引用操作(*解引用操作),而计算数组超出未端位置之后或数组首地址之前的地址都是不合法的。
第三节:
C风格字符串
@学习摘录047:
C风格字符串与C++的标准库类型string的比较
——以下两段程序反映了使用C风格字符串与C++的标准库类型string的不同之处,使用string类型的版本更短、更容易理解,而且出错的可能性更小。
//C-stylecharacterstringimplementation
constchar*pc=“averylongliteralstring.”;
constsize_tlen=strlen(pc);//spacetoallocate
//performancetestonstringallocationandcopy
for(size_tix=0;ix!
=1000000;++ix)
{
char*pc2=newchar[len+1];//allocatethespace
strcpy(pc2,pc);//dothecopy
if(strcmp(pc2,pc)//userthenewstring
;//donothing
delete[]pc2;//freememory
}
//stringimplementation
stringstr(“averylongliteralstring”);
//performancetestonstringallocationandcopy
for(size_tix=0;ix!
=1000000;++ix)
{
stringstr2=str;//dothecopy,automaticallyallocated
if(str!
=str2)
;//donothing
}//str2isautomaticallyfreed
第四节:
多维数组
@学习摘录048:
——严格来说,C++中没有多维数组,通常所指的多维数组的数组;
//arrayofsize3,eachelementisanarrayofintsofsize4
intia[3][4];
——在使用多维数组时,记住这一点有利于理解其应用。
术语:
@学习摘录049:
——ptrdiff_t:
在cstddef头文件中定义的与机器相关的有符号整型,该类型具有足够大小存储两个指针的差值,这两个指针指向同一个可能的最大数组。
——size_t:
在cstddef头文件中定义的与机器相关的无符号整型,它具有足够大小存储一个可能的最大数组。
《C++Primer》第05章学习笔记
第05章:
表达式
第五节:
自增和自减操作符
@学习摘录050:
自增和自减操作符
——建议:
只有在必要时才使用后置操作符。
——前置操作需要做的工作更少,只需加1后返回加1后的结果即可。
——而后置操作符则必须先保存操作数原来的值,以便返回未加1之前的值作为操作的结果。
——对于int型对象和指针,编译器可优化掉这项额外工作。
但是对于更多的复杂迭代器类型,这种额外工作可能花费更大的代价。
——养成使用前置操作这个好习惯,就不必操心性能差异的问题。
@学习摘录051:
在单个表达式中组合使用解引用和自增操作
——*iter++的意思:
等效于*(iter++)。
子表达式iter++使iter加1,然后返回iter原值的副本作为该表达式的结果。
vector:
:
iteratoriter=ivec.begin();
//prints1098…1
while(iter!
=ivec.end())
cout<<*iter++<摘录有想:
——很多C++程序员都会习惯用这种方法的,可以简洁清晰不冗长。
第十一节:
new和delete表达式
@学习摘录052:
动态创建对象的默认初始化
——在动态创建对象时,(几乎)总是对它做初始化也是一个好方法。
——同样也可以对动态创建的对象做值初始化
string*ps=newstring();//initializedtoemptystring
int*pi=newint();//pipointstoanintvalue-initializedto0
cls*pc=newcls();//pcpointstoavalue-initializedobjectoftypecls
——对比下面的不同初始化方式的不同
int*pi=newint;//pipointstoanuninitializedint
int*pi=newint();//pipointstoanintvalue-initializedto0
@学习摘录053:
——一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象。
摘录有想:
——如果用了delete*p;之后 p=NULL;
第十二节:
显式转换
@学习摘录054:
——命名的强制类型转换 cast-name(expression);
——dynamic_cast,支持运行时识别指针或引用指向的对象。
——const_cast,将转换掉表达式的const性质。
——static_cast,编译器隐式执行的任何类型转换都可以由static_cast显式完成。
——reinterpret_cast,通常为操作数的位模式提供较低层次的重新解释。
摘录有想:
——我想一般现在写程序的时候用到最多的是static_cast吧,而且,书上也建议,不要常用强制转换,如果程序写得好的话,就根本不用用上这个功能。
《C++Primer》第06章学习笔记
第06章:
语句