C++ Primer 3rd 英文版 阅读笔记+练习代码
chapter 1:
1、目前对ISO98标准的C++支持的较好的编译器有gcc和VC7.1(Visual Studio .NET 2003)
2、由于各平台和编译器的不同实现,导致了C++头文件的扩展名(suffix)不统一,所以目前的C++标准中,头文件不带任何后缀,如#include <iostream>,不再是#include <iostream.h>等类似的写法
3、目前的C++标准,要调用任何库,必须使用namespace,如using namespace std就是使用C++的标准库,不带namespace的任何库调用(包括第三方的库),编译器将报告不认识库函数的错误
4、C++标准中预定义了两个名称,__LINE__和__FILE__,分别代表源代码的行号和文件名,可以在代码中直接引用
5、在做输出的时候,我们可以使用endl来代替"\n",因为endl除了在行内插入一个换行符(newline)之外,还能flush output buffer
1、目前对ISO98标准的C++支持的较好的编译器有gcc和VC7.1(Visual Studio .NET 2003)
2、由于各平台和编译器的不同实现,导致了C++头文件的扩展名(suffix)不统一,所以目前的C++标准中,头文件不带任何后缀,如#include <iostream>,不再是#include <iostream.h>等类似的写法
3、目前的C++标准,要调用任何库,必须使用namespace,如using namespace std就是使用C++的标准库,不带namespace的任何库调用(包括第三方的库),编译器将报告不认识库函数的错误
4、C++标准中预定义了两个名称,__LINE__和__FILE__,分别代表源代码的行号和文件名,可以在代码中直接引用
5、在做输出的时候,我们可以使用endl来代替"\n",因为endl除了在行内插入一个换行符(newline)之外,还能flush output buffer
Chapter2
1、int *pint = new int(1024); //new一个int类型的object,并赋初值1024
2、int *pia = new int[4]; //new一个int类型的数组,包含四个元素,pia是数组第一个元素的地址
3、new出来的对象必须用delete销毁,没有用new出来的object,系统会自动销毁和回收。delete一个object,用delete pint , delete一个数组,用delete [] pia
4、有关namespace。第一种用法,<namespace>:: ,如std::cout;第二种用法,using namespace std; ,这样,后续代码中所有的库调用都会被编译器假设是std下面的库;第三种用法,namespace LIB = Disney_Feature_Animation; 然后用LIB::<方法名>可以调用,相当于给一个长的,不好记的namespace赋一个容易记忆的别名。更详细的看专门讲 namespace的一章
5、C++中有数组,但是在标准库中提供了vector作为一个更好的数组替代品。如:
vector<int> ivec( 10 ); //一个有十个int object的vector
vector<string> svec( 10 ); //一个有十个string object的vector
还有更多的用法:
// ways of creating a vector object
vector<int> vec0; // empty vector
const int size = 8;
const int value = 1024;
// vector of size 8,
// each element initialized to 0
vector<int> vec1( size );
// vector of size 8,
// each element initialized to value 1024
vector<int> vec2( size, value );
// vec3 is of size 4
// initialized to the four values of ia
int ia[4] = { 0, 1, 1, 2 };
vector<int> vec3( ia, ia+4 );
// vec4 is a copy of vec2
vector<int> vec4( vec2 );
附件代码中有一个例子是如何使用vector的(包括如何遍历vector)
1、int *pint = new int(1024); //new一个int类型的object,并赋初值1024
2、int *pia = new int[4]; //new一个int类型的数组,包含四个元素,pia是数组第一个元素的地址
3、new出来的对象必须用delete销毁,没有用new出来的object,系统会自动销毁和回收。delete一个object,用delete pint , delete一个数组,用delete [] pia
4、有关namespace。第一种用法,<namespace>:: ,如std::cout;第二种用法,using namespace std; ,这样,后续代码中所有的库调用都会被编译器假设是std下面的库;第三种用法,namespace LIB = Disney_Feature_Animation; 然后用LIB::<方法名>可以调用,相当于给一个长的,不好记的namespace赋一个容易记忆的别名。更详细的看专门讲 namespace的一章
5、C++中有数组,但是在标准库中提供了vector作为一个更好的数组替代品。如:
vector<int> ivec( 10 ); //一个有十个int object的vector
vector<string> svec( 10 ); //一个有十个string object的vector
还有更多的用法:
// ways of creating a vector object
vector<int> vec0; // empty vector
const int size = 8;
const int value = 1024;
// vector of size 8,
// each element initialized to 0
vector<int> vec1( size );
// vector of size 8,
// each element initialized to value 1024
vector<int> vec2( size, value );
// vec3 is of size 4
// initialized to the four values of ia
int ia[4] = { 0, 1, 1, 2 };
vector<int> vec3( ia, ia+4 );
// vec4 is a copy of vec2
vector<int> vec4( vec2 );
附件代码中有一个例子是如何使用vector的(包括如何遍历vector)
Chapter3 C++ Data types
第一节 Literal Constant
1、char, short, int, long 都是数字型的类型。他们都有signed和unsigned两种类型。signed类型,就是最高位的bit代表sign bit,unsigned类型,就是所有位都用来表示数字。所以,signed类型的表示范围是-128-127,unsigned类型的表示范围是0- 255
2、表示数的方法有十进制、八进制和十六进制三种。八进制就是在数的前面加0,十六进制就是在数的前面加0x
3、integer默认情况下被认为是signed,如果要声明一个unsigned的常量integer,可以在数的后面加上U/u(大小写无 所谓,推荐用大写)。同理,如果要把一个常量integer表示为一个long类型,可以在后面加L/l(大小写都可以,推荐用大写)。如128U 1024UL 1L 8Lu
4、浮点数,如3.14159。默认情况下,常量浮点数将被认为是double类型,如果要将其定义为单精度的Float类型,可以在常量后面加F/f(大小写都可以,推荐用大写),如3.14159F,当然,如果用科学技术法表示的浮点数是不可以这样的。
5、字符-char。常量字符的表示使用单引号,如'a'。另外,有一些转义字符,如'\n' '\t'等,字符还可以使用八进制来表示(说明了字符也是一种数字类型),如\7(bell) \14(newline) \0(null) \062('2')。在常量字符前,加上一个L(大写),表示这是一个宽字符(wide-character),对应的类型就是wchar_t,宽字符可 以用来表示中文。
6、字符串。字符串是用双引号包括起来的一些字符。一行表示不下的字符串,可以在行末使用一个back-slash来延续。常量字符串前,也可以使用L来表示一个由wide-char组成的宽字符串,如L"Hello",注意,宽字符串的结尾符号\0也是一个宽字符。
7、字符和字符串的区别。字符的结尾没有\0,字符串的结尾有一个\0的字符。所以,对于compiler来说,'A'和"A"是不一样的。
8、两个字符串相邻的时候,compiler会自动将两个字符串做连接(concatenate),然后在末尾的地方加上一个\0。 如"two""some" 将会被表示成twosome,但是,注意,一个字符串和一个宽字符串是不能被连接的,如"two"L"some",这样是不可以的。
第二节 Variable
1、变量和文本常量、常量(以const修饰的变量)不同的是,变量有read value和location value两个属性,而后两者一般都只有read value(指我们一般不能对他们的location value做操作)。
第三节 Pointer Types
1、指针变量定义的时候,强烈要求将*写到变量的前面,而不是紧跟在类型的后面。如string *ps,而不是写成string* ps。之所以要这样,是为了在同时定义多个指针时发生误解。如string* ps, ps2; 这个其实是定义了一个ps指针和一个ps2的string变量,如果这样写,很容易让人误解为ps和ps2都是指针,所以,我们要求改成这样: string *ps, ps2; 这样就比较清晰,不容易产生误解。
2、int *pi = 0; 将指针置为null(null就是0)
3、指向不同类型的指针不能相互赋值。如:
double dval; double *pd = &dval;
int ipi; int *pi = &ipi;
pi = pd; //出错!
这里出错不是因为指针本身的值不能互相赋(从本质上来说,不管是什么指针,其本身的值都只占用4个byte的空间,在32位系统下,所以,互相赋值根本没 问题),而是因为pi和pd指向的变量类型不同,所以,编译器在解释他们所指向的对象的时候,对象的大小和层次结构也会不一样,所以,指向不同类型的指针 不能互相赋值。
4、void * 仅仅表示这是一个指针,但该指针所指向的变量类型为unknown。所以,void * 这种指针只能被用来赋值以及和一些指针地址做比较。
5、指针运算,pointer arithmetic。如:
int i = 9;
int *pi = &i;
pi = pi + 2;
如上,pi+2这个操作之后,pi的地址将后移两个int的大小。也就是说,给指针做运算时,将会根据指针本身所指向对象的大小,相应的前移/后移N个对 象地址。最典型的情况是,在一个数组中,假设a是指向数组开头地址的指针,那么a+2之后,将指向数组第三个元素!
第一节 Literal Constant
1、char, short, int, long 都是数字型的类型。他们都有signed和unsigned两种类型。signed类型,就是最高位的bit代表sign bit,unsigned类型,就是所有位都用来表示数字。所以,signed类型的表示范围是-128-127,unsigned类型的表示范围是0- 255
2、表示数的方法有十进制、八进制和十六进制三种。八进制就是在数的前面加0,十六进制就是在数的前面加0x
3、integer默认情况下被认为是signed,如果要声明一个unsigned的常量integer,可以在数的后面加上U/u(大小写无 所谓,推荐用大写)。同理,如果要把一个常量integer表示为一个long类型,可以在后面加L/l(大小写都可以,推荐用大写)。如128U 1024UL 1L 8Lu
4、浮点数,如3.14159。默认情况下,常量浮点数将被认为是double类型,如果要将其定义为单精度的Float类型,可以在常量后面加F/f(大小写都可以,推荐用大写),如3.14159F,当然,如果用科学技术法表示的浮点数是不可以这样的。
5、字符-char。常量字符的表示使用单引号,如'a'。另外,有一些转义字符,如'\n' '\t'等,字符还可以使用八进制来表示(说明了字符也是一种数字类型),如\7(bell) \14(newline) \0(null) \062('2')。在常量字符前,加上一个L(大写),表示这是一个宽字符(wide-character),对应的类型就是wchar_t,宽字符可 以用来表示中文。
6、字符串。字符串是用双引号包括起来的一些字符。一行表示不下的字符串,可以在行末使用一个back-slash来延续。常量字符串前,也可以使用L来表示一个由wide-char组成的宽字符串,如L"Hello",注意,宽字符串的结尾符号\0也是一个宽字符。
7、字符和字符串的区别。字符的结尾没有\0,字符串的结尾有一个\0的字符。所以,对于compiler来说,'A'和"A"是不一样的。
8、两个字符串相邻的时候,compiler会自动将两个字符串做连接(concatenate),然后在末尾的地方加上一个\0。 如"two""some" 将会被表示成twosome,但是,注意,一个字符串和一个宽字符串是不能被连接的,如"two"L"some",这样是不可以的。
第二节 Variable
1、变量和文本常量、常量(以const修饰的变量)不同的是,变量有read value和location value两个属性,而后两者一般都只有read value(指我们一般不能对他们的location value做操作)。
第三节 Pointer Types
1、指针变量定义的时候,强烈要求将*写到变量的前面,而不是紧跟在类型的后面。如string *ps,而不是写成string* ps。之所以要这样,是为了在同时定义多个指针时发生误解。如string* ps, ps2; 这个其实是定义了一个ps指针和一个ps2的string变量,如果这样写,很容易让人误解为ps和ps2都是指针,所以,我们要求改成这样: string *ps, ps2; 这样就比较清晰,不容易产生误解。
2、int *pi = 0; 将指针置为null(null就是0)
3、指向不同类型的指针不能相互赋值。如:
double dval; double *pd = &dval;
int ipi; int *pi = &ipi;
pi = pd; //出错!
这里出错不是因为指针本身的值不能互相赋(从本质上来说,不管是什么指针,其本身的值都只占用4个byte的空间,在32位系统下,所以,互相赋值根本没 问题),而是因为pi和pd指向的变量类型不同,所以,编译器在解释他们所指向的对象的时候,对象的大小和层次结构也会不一样,所以,指向不同类型的指针 不能互相赋值。
4、void * 仅仅表示这是一个指针,但该指针所指向的变量类型为unknown。所以,void * 这种指针只能被用来赋值以及和一些指针地址做比较。
5、指针运算,pointer arithmetic。如:
int i = 9;
int *pi = &i;
pi = pi + 2;
如上,pi+2这个操作之后,pi的地址将后移两个int的大小。也就是说,给指针做运算时,将会根据指针本身所指向对象的大小,相应的前移/后移N个对 象地址。最典型的情况是,在一个数组中,假设a是指向数组开头地址的指针,那么a+2之后,将指向数组第三个元素!