第五章笔记——《TC++PL》

来源:互联网 发布:c语言中flag=1 编辑:程序博客网 时间:2024/04/30 22:21

1、The sublime and the ridiculous are often so nearly related that it is difficult to class them separately.

2、指针的一般概念
还是那么老一套的东西。T*的变量保存一个类型T的对象的地址。指针可以指向数据或代码。基本操作是间接引用(dereference ),运算符为一元*。
这里所谓对象的地址,其实是虚拟地址而非物理地址。绝大多数机器都可以寻址到字节。

3、零的使用
使用普通的0,而不是NULL。

4、数组中注意的问题
内部数组的界必须是一个常量表达式。vector却不是。多维数组表示为数组的数组,而不能用逗号记法。因为逗号是序列运算符,不能出现在常量表达式里。

5、数组初始化
数组可以用一系列值初始化,要注意老生常谈的那一套规则。不存在相应的“数组赋值”:
v4={‘c’,’d’,0};
是语法错误。

6、字符串文字量
和C不同,字符串文字量的类型不再是char*,而是const char[ ]。不要小看这个变化,通过一个sizeof运算符就可以看出来:sizeof(“Bohr”) == 5;而不是指针的长度。
附:数组的sizeof试验
有int a[10][10]; 则 sizeof(a) == 400; sizeof(a[0]) == 40; sizeof( a[0][0] ) == 4;
字符串文字量是静态分配的,所以让函数返回它们是安全的。
测试:vc编译器是否将相同的字符串文字量分配在一起(优化)
结果:vc的确作了这种优化。给出
const char* p = "To be, or not to be, that is the question";
const char* q = "To be, or not to be, that is the question";
……
if( p == q ) cout << "one!" << endl;
运行程序,果然打出one!
空字符串””的类型是const char[1];
长字符串可以用空白字符断开。带有前缀L的字符串类型是const wchar_t[ ]型,强制转换会出现奇怪的情况。

7、到数组的指针
数组名很容易用作指向其第一个元素的指针。但从数组到指针的转换会丢失其大小信息。
必要时用extern”C”。

8、数组遍历和指针遍历
书上说,用指针遍历数组和用下标遍历数组,没有任何理由说某种方式快于另一种。同过新型的编译器,完全可以产生一模一样的代码。我在机器上做了试验。通过反汇编这两个函数,我发现它们的汇编代码的确差别不大——可以说几乎完全一样。只是在循环的初始化部分,指针遍历要多一条转存地址的语句,而在循环体内,数组遍历要多出一条加法指令——用来把基址和下标相加。从这个意义上,严格一点说,在我的系统中,指针遍历的效率还是要高一点点的——当然数组很大时效率差别也可能很大。但我还是喜欢下标遍历,它似乎不容易出错。
内部数组不具有自描述性。

9、指针运算
同一个数组内指针相减才有意义。指针相加从来没有任何意义。避免复杂的指针运算。

10、常量
const的对象不允许赋值,所以必须进行初始化。
const改变了类型,限制了对象能够使用的方式。
编译器可能对const做出优化。
常量数组一般需要分配空间而不是直接被替换成相应值,但可能被放进只读存储器而得到优化。
应该在程序里系统化地使用符号常量。避免“神秘的数值”。采用符号常量可以使信息局部化。一个数值常量代表着程序中的一个假设,这是应当避免的。
从修改和维护的角度,应当在可用const的地方尽可能的用——最低权限原则。

11、指针和常量的话题
分清这些概念即可:cp is a const pointer to char, and cp2 is a pointer to const char
可以通过对const指针的显式类型转换取掉这种限制。

12、引用
引用必须初始化。或者只是声名,在别处初始化。
引用的最明显的实现方式是指针。但要注意,引用不是一个实体对象,不能像指针那样去操作。
普通的T&初始式必须是类型T的左值。而const T&初始式不必是左值,甚至可以不是类型T的。——绑定一个和用户无关的临时变量,这个临时变量生存期和该引用作用与有关。
引用传递的函数参数——如果要改变参数的值,要么给函数取一个明显如此的名字,要么不用引用而用指针。

13、void*
可进行的操作:比较是否相等,显式的转换为另一个类型。
不能间接引用,不能自增等。
最重要的用途就是向一个函数传递一个指针,而又不能对对象的类型作任何假设。或从函数返回这样的指针。
BS说,到函数的指针和到成员(包括数据和函数)的指针都不能赋给void*。这句话显然有问题。
首先到函数的指针在vc中是绝对可以传给void*的,当然Dev-C++中不能。也许是MS牛B,又不按照标准C++来做编译器:这一点还可商量。然而后面半句显然有误导人的嫌疑。连BS自己在后面都说静态成员的指针看作普通指针,那么当然可以赋给void*了。呵呵,不知道这是省略还是bug。

14、结构体
任意类型元素的一个聚集。
结构体定义:花括号后要写分号。
像其他变量一样简单声明,通过圆点和箭头访问成员。
可以用类似数组的方式初始化。address jd = {……};
存在对齐问题,其大小未必是其成员大小之和。甚至成员的顺序也影响着结构体的大小。
从大到小排列成员可以获得最小的空间浪费,但还是最好按照可读性的要求去排列它们。
在同一作用域里,允许一个名字被同时用于一个struct和一个非结构实体。这时候结构前面需要加上struct消除歧义,class union enum同理。但最好不要这样去重载一个名字。
拥有相同成员的不同名结构体并不等价,每个struct必须是惟一定义的。
 

原创粉丝点击