C++程序设计教程--读书笔记 第五章 函数机制

第五章
 
一、知识点
1、为了防止传递指针参数或者引用参数时破坏非本地数据,需要在指针和引用参数上加const修饰,以限制函数体中对参数的写操作。(P164)
 
2、运行时内存布局:一个程序要运行,就要先将可执行程序文件装载到计算机的内存中。装载是操作系统掌控的,一般而言,操作系统将程序装入内存后,将形成一个随时可以运行的进程空间,该进程空间分四个区域,如下图所示:(P165)

(1)、代码区存放的是程序的执行代码。所谓执行代码就是索引了的一个个函数块代码,它由函数定义块的编译得到。
(2)、全局数据区存放全局数据、常量、文字量、静态全局量和静态局部量
(3)、堆区存放动态内存,供程序随机申请使用。
(4)、栈区存放函数数据区(即局部数据区),它动态地反映了程序运行中的函数状态,其运动轨迹正好用来观察函数的调用与返回,从而研究其函数机制。
 
3、函数调用的整个过程就是栈空间操作的过程。函数调用时,C++做以下工作:(P166)
(1)、建立被调用函数的栈空间,栈空间的大小由函数定义体中的数据量多少决定;
(2)、保护调用函数的运行状态和返回地址;
(3)、传递参数;
(4)、将控制权转交给被调函数;
(5)、函数运行完成后,复制返回值到函数数据块底部;
(6)、恢复调用函数的运行状态;
(7)、返回调用函数。
调用一个函数,可以看作是一个栈中元素的压栈和退栈操作。然而,压栈之后的函数运行,可能导致其他函数被调用。因此,程序运行表现为栈中一系列元素的压栈和退栈。最初,操作系统将main函数压入栈中,标志着程序运行的开始,等到最后main函数退栈,程序也就运行结束了。
 
4、一个运行的程序在内存中的布局,分为四个区域。全局数据区、堆区、栈区被称为数据区域。指向数据区域的指针,称为数据指针。指向代码区域的指针称为指向函数的指针,简称函数指针。但要注意,与返回指针类型的函数不同,那样的函数称为指针函数。(P171)
 
5、函数是以参数个数、参数类型、参数顺序甚至返回类型的不同来区分不同类型的。函数的类型表示是函数声明去掉函数名。例如:(P171)
int g(int);
它的类型就是int (int)。声明一个 int (int)类型的函数g,就是把函数名放在返回类型和括号之间“int g(int)”。同样,定义一个int (int)类型的函数指针gp,就是把指针名放在返回类型和括号之间,即:
int (*gp)(int);
注意,上面是定义了一个函数指针,不是声明,而且容纳函数指针名的括号不能省,否则意思不同。定义函数指针还可以初始化。如果在定义中伴随着初始化,则应写成:
int g(int);
int (*gp)(int) = g;
当然,函数指针赋值也可以与函数指针定义分开,比如:
int g(int);
int (*gp)(int);
gp = g;
定义了一个函数指针,就拥有了一个指针实体,一个指针实体的大小跟int型实体大小是一样的。函数指针的类型必须接受编译器的检查。
 
6、由于函数指针本身也是一种数据类型,即:(P172)
int (*)(int);
是int (int)型函数的指针类型。函数指针的定义形式看起来比较复杂,所以通常采用typedef来简化。例如:
typedef int (*Fun)(int a, int b);
表示声明了一个函数指针类型。因此:
int m(int, int);
Fun funp = m;    // OK
Fun = m;           // 错:不恰当地使用 typedef 'Fun'
 
7、函数名即为函数指针,正像数组名即为指针一样。(P173)
 
8、简略函数指针表示:(P176)
(1)、int ();
是一个无名函数声明,表示一个函数类型;
(2)、int func();
也是一个函数声明,表示一个函数类型,其中func是函数类型的名字;
(3)、int  (*)();
是一个无名函数指针;
(4)、int (*pf)();
是一个函数指针定义,pf是函数指针名,该指针的函数类型是int()。
(5)、int (*func(int))();
是一个函数声明,即*func(int)的类型是int()。也就是:
Func * func(int);
它是一个返回一个函数指针的带有一个int参数的函数声明,该返回的函数指针类型为:int()。
 
9、递归条件:(P183)
(1)、递归不能无限制地调用下去,所以递归函数是有条件地调用自身,该条件就是递归的停止条件。例如:阶乘函数中的“if(n == 1) return 1;”当n为1时,函数就不再递归了。
(2)、递归函数中必须有完成终极任务的语句序列,以使函数有意义。例如,“return 1;”就是阶乘函数完成终极计算的语句。
(3)、递归函数当然有递归调用语句。然而,递归调用应该有参数,而且参数值应该是逐渐逼近停止条件的。
(4)、递归条件应先测试,后递归调用。
 
10、C++编译器能够根据函数参数的类型、数量和排列顺序的差异,来区分同名函数,其技术称为重载技术,相应的同名函数称为重载函数。返回值不同不允许重载。(P186)
 
11、C++允许int型到long型,int型到double型的隐式转换。但若必须在两者之间抉择时,则会引起错误。(P187)
 
12、C++采用名称压轧技术来改变函数名,区分参数不同的同名函数。名称压轧是十分简单的过程,一系列代码被附加到函数名上衣标记参数类型以及它们出现的次序。名称压轧总是在编译过程汇总悄悄进行,在链接过程中默默使用。(P188)
 
13、C函数在C++中使用,或者其他语言的模块移植到C++中时,因为它们都是直接的机器代码,直接的函数名称,而且编译已经完成。这时候,要参加C++程序的链接,会带来衔接上的问题,但通过函数名前加上extern C修饰,阻止函数名压轧,便可解决。(P188)
 
14、默认参数值总是在函数声明时描述的。默认参数值只能置身于声明中。(P189)
 
二、问题
1、P161    代码很好

posted on 2012-05-01 09:54  谷堆旁边  阅读(298)  评论(0编辑  收藏  举报