1、数组的长度是固定的,指针则可以像迭代器一样用于遍历和检查数组中的元素。与使用标准vector类型的程序相比,依赖内置数组的程序更容易出错,而且难于调试。
2、C++语言应尽量使用vector和迭代器类型,应避免使用低级的数组和指针,涉及良好的程序只有在强调速度时才在类实现的内部使用数组和指针。因此要向成为一个真正的C++程序员就要多使用vector和string来替代数组和c风格字符串。
3、数组的维数必须用整型常量指定,非const类型或是到运行时才知道其值的const变量都不能用于定义数组的维数。
在没有显式提供元素的初始时数组元素会像普通元素一样初始化。
1)若在函数体外定义的数组,所有元素将会被初始化为0,若是在函数体外定义的数组,其元素不会被初始化。
2)如果数组元素为类类型,无论数组在哪里定义,都会自动调用类的默认构造函数来初始化。如果类没有默认构造函数,则必须为数组的元素提供显式的初始化。这一点与vector类似。
4、与vector中的size_type类似,数组下标的正确类型为size_t;头指针和尾指针之差的正确类型为ptrdiff_t,它是signed类型。
注意:不允许数组直接复制和赋值!
5、指针是指向某种类型对象的复合数据类型,是用于数组的迭代器:指向数组中的一个元素。对指针进行解引用操作,可以获得该指针所指对象的值。指针用于指向单个对象,而迭代器只能用于访问容器内的元素。
理解指针声明语句时,从右向左阅读。
6、使用指针不当易导致错误发生,应将未初始化的指针初始化为NULL,因为编译器可以测出0值的指针。这在一定程度上可以避免指针未初始化就使用的情况。
对指针进行初始化或赋值只能使用以下四种类型的值:
1)0值常量表达式。
2)类型匹配的对象的地址。
3)另一对象之后的下一个地址。
4)同类型的另一个有效指针。
注意:预处理变量不是在std命名空间中定义的,因此其名字应该为NULL,而非std::NULL。
7、指针和引用的比较:
引用总是指向某个对象,定义引用时没有初始化是错误的。给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象。
8、给指针赋值或通过指针进行赋值:
如果对左操作数进行解引用,则修改的是指针所指对象的值,如果没有使用解引用操作,则修改的是指针本身的值。
9、C++使用**操作符指派一个指针指向另一个指针。即指针本身也是可用指针指向的内存对象。
10、void*类型的指针可以存储任何类型的指针。它表明该指针与某一地址值相关,但不清楚存储在此地址上的对象的类型。
void*类型的指针只支持几种有限的操作:
1)与另一个指针比较、
2)向函数传递void*指针或是从函数中返回void*指针。
3)给另一个void*指针赋值。但是不允许使用void*操作它指向的对象。
11、指向const对象的指针:
如果指针指向const对象,则不允许用指针来改变其所指的const值。为了保证这个特性,C++语言强制要求指向const对象的指针也必须具有const特性。
1)把一个const对象的地址赋给一个普通的、非const对象的指针也会导致编译时的错误。
2)不能使用void*指针保存const对象的地址,必须使用const void*类型。
3)允许把非const对象的地址赋给指向const对象的指针。
12、实际中常把指向const的指针用作函数形参,以此确保传递给该函数的实际对象不会再函数中被修改。这也说明了,指向const的指针,既可以指向const对象也可以指向非const对象。
13、使用const定义变量时,const int a;与int const a;是等价的。
这样就容易导致混淆。如:
typedef int *IntPtr;const IntPtr pp;
此时pp是什么类型呢。真正的类型应该是将pp定义为指向int类型的const指针。它等价于int * const pp;原因是在const IntPtr pp;等价于IntPtr const pp, const作用于IntPtr类型。而不是跟const int a 一样作用于a。
所以尽量写成IntPtr const pp;这种形式,此时便不会误会。
14、动态分配数组:
可以在数组长度后面加一对空圆括号,对数组的元素进行初始化,此时数组元素都被初始化为0;
如int *array=new int[10]( );
创建const对象的动态数组时必须为数组元素提供初始化,因为数组元素都是const对象。
如const int *array=new const int[100]( );
动态分配的数组空间要调用delete [ ]进行释放。漏用[ ]编译器无法发现此错误,会导致少释放内存空间,导致内存泄露。
15、String成员函数c_str( )返回const类型的数组指针,因此不能被修改。
另外一旦string对象被改变,c_str()返回的数组就会变为无效,也就是说c_str()返回的数组是在调用函数时才对string对象内容的拷贝,并不实时反映string对象的内容。
16、可以使用数组为vector对象初始化,此时必须指出用于初始化式的第一个元素以及数组最后一个元素的下一个位置的地址。
如int a[ ]={20,41,52,54,63,54,36};
vector<int> v(a,a+7);
两个指针标示出vector初值的范围,第二个指针指向数组最后一个元素的后一个地址空间。
17、区分指针数组与行指针。
如int *ptr[10]; //此为指针数组。
int (*ptr)[10]; //此为行数组,p为指向具有10个元素的数组的指针。
18、平时经常使用typedef int *ptr; 来简化操作。
但是对于typedef int int_array[4];很不熟悉,可以参照typedef int *ptr;来理解。
Int_array p;定义一个具体有四个元素的数组。而int_array *p定义一个指向具有四个元素数组的行指针。
19、在执行程序时,main函数始终是自动调用的,大多数函数并不能自动调用。
20、函数名以小写字母开头,所有随后的单词以大写字母开头。
将一个函数定义在另一个函数内部是一个语法错误。
21、当cin和流提取运算符配合使用时,它读取字符直到遇到第一个空白间隔符为止。
使用getline函数时必须包含<string>头文件。(其遇回车结束)
22、对每个形参而言,应当指定其类型及标识符。形参变量的名字可以与实参变量的名字同名,也可以不同名。
23、类的每个对象管理它自己的在内存中的一份属性副本。
在类的成员函数中如string getCourseName() { return courseName; }中,由于在建立对象后会对对象分配空间,所以courseName存储的地址会一直存在,直到程序结束。
24、private之后的变量或函数只能在类内部使用。类成员的默认成员访问说明符是private,结构体默认为public。
类的设计习惯——将类的数据成员设计为私有的,将成员函数设计为公有的。
成员函数定义的顺序并不决定它们在执行时的调用时间。默认下一个字符串的初始值是空串。
25、set函数和get函数允许客户与对象交互,但是对象的私有数据继续安全地封装(即隐藏)在对象自身中。
构造函数的调用隐式地发生在对象创建时。默认的构造函数将隐式地调用每个数据成员的默认构造函数,保证数据成员正确初始化。
类string的默认构造函数将这个串的值设置为空串。
可以在不同的函数使用相同的形参名,因为对每个函数而言,形参是局部的,它们互不干扰。
26、C++对象通常只包含数据。编译器仅创建类的成员函数的一份副本。该类所有的对象共享它。
类的接口由类的public成员函数组成。通过书写只列出成员函数名、返回类型和形参类型的类定义,就可以说明一个类的接口。
惯例:成员函数的定义放在一个与类的头文件基本名同名而文件扩展名是.cpp的源代码文件中。
头文件不能用于开始程序的执行,因为其没有main函数。因此如果单独编译时会出错。编译器必须知道类的数据成员,以决定为类的每个对象保留多少内存。源代码必须先经过单独编译,再链接在一起。
27、创建GradeBook类的类程序员首先创建两个文件,一是头文件GradeBook.h二是包含该头文件的源代码文件GradeBook.cpp。然后编译源代码文件,创建GradeBook对象的目标代码。向客户提供GradeBook.h和GradeBook类的目标代码。目标代码包含了描述GradeBook成员函数的机器指令。所以客户不知道GradeBook成员函数是如何实现的。客户代码只需要知道使用GradeBook的接口,并保证能够链接到它的目标代码。由于类接口是GradeBook.h头文件中类定义的一部分,客户代码程序员必须有权访问这个文件,并在客户源代码中包含它。当编译客户代码时,编译器使用GradeBook.h中的类定义来保证main函数正确创建和操作GradeBook类的对象。
接下来链接以下几部分:
main函数的目标代码(即客户代码)。
GradeBook类成员函数实现的目标代码。
类实现程序员和客户代码程序员使用的C++类(例如string)的C++标准库目标代码。
链接器的输出就是可供教师使用的GradeBook可执行程序。在编译完代码后,编译器和集成开发环境通常会接下来调用链接器。
28、C++编译器合并相邻的字符串文字,即使他们出现在程序的不同行上。
局部变量不能在声明它的函数外部访问。