第4章 过程抽象――函数
1、    简述子程序的作用。
答:子程序是有名字的一段程序代码,它通常完成一个独立的(子)功能。在程序的其他地方通过子程序的名字来使用它们。除了能减少程序代码外,采用子程序的主要作用是实现过程抽象,使用者只需知道子程序的功能,而不需要知道它是如何实现的,这有利于大型、复杂程序的设计和理解。
    简述局部变量的作用。
答:1、实现信息隐藏,使得函数外无法访问该函数内部使用的数据。
2、减少名冲突,一个函数可以为局部变量定义任何合法名字,而不用担心与其他函数的局部变量同名。
    2、局部变量的内存空间在栈中分配,函数调用完之后释放,因此,使用局部变量能节省程序的内存空间。
    简述变量的生存期和标识符的作用域。
答:变量的生存期指程序运行时一个变量占有内存空间的时间段。C++把变量的生存期分为静态、自动和动态三种。标识符的作用域是指:一个定义了的标识符的有效范围,即该标识符所标识的程序实体能被访问的程序段。在C++中,根据标识符的性质和定义位置规定了标识符的作用域。作用域分为:全局作用域、文件作用域、局部作用域、函数作用域、函数原型作用域、类作用域、名空间作用域。
    全局标识符与局部标识符在哪些方面存在不同?
答:1、作用域不同
2、生存期不同
3、用途不同,全局标识符用于标识共享的实体,而局部标识符用于标识专用的实体。
    下面的声明中哪一些是定义性声明?这些定义性声明的非定义性声明是什么?
(1)const int i=1;
(2)static double square(double dbl) { return dbl*dbl; }
(3)char *str;
(4)struct Point;
(5)char* (*pFn)(int(*)(char*,int),char**);
答:1)是。非定义性声明:extern const int i;
    2)是。非定义性声明:extern double square(double);
    3)是。非定义性声明:extern char *str;
    4)不是。
    5)是。非定义性声明:extern char* (*pFn)(int(*)(char*,int),char**);
    下面的宏cube1和函数cube2相比,各有什么优缺点?
#define cube1(x) ((x)*(x)*(x))
double cube2(double x) { return x*x*x; }
答:小型函数的频繁调用会带来程序执行效率的严重下降,宏的出现解决了函数调用效率不高的问题,但宏本身也存在很多问题:(1)宏会出现重复计算,(2)不进行参数类型检查和转换,(3)不利于一些工具对程序的处理。而函数可以很好的处理这些问题。
    另外,对于:int a; 当a的值很大时,cube1(a)得不到正确结果!(因为结果类型为int,而如果a*a*a的结果超出了int型的范围,则结果将会截断!)
    编写一个函数digit(n,k),它计算整数n的从右向左的第k个数字。例如:
digit(123456,3) = 4
digit(1234,5) = 0
答:int digit (int n,int k)
{    for ( int i=1; i<k ; i++)
            n = n/10;
        return n%10;
}
    分别用函数实现习题3.8中的第1、4、7和10题的程序功能。
答:第1题:
double Fahrenheit_To_Celsius(double x)
{
    return (x-32)*5/9;
}
    第4题:
int num_of_digits(int gzint)
{    int count = 0;
    if (gzint<0) gzint = - gzint;
    while (gzint!=0)
    {    gzint = gzint / 10;
        count++;
    }
    return count;
}
    写出下面程序的执行结果:
#include <iostream>
using namespace std;
int count=0;
int fib(int n)
{    count++;
    if (n==1 || n==2)
        return 1;
    else
        return fib(n-1)+fib(n-2);
}
int main()
{    cout << fib(8);
    cout << ',' << count << endl;
    return 0;
}
答:21,41
分别写出计算Hermit多项式Hn(x)值的迭代和递归函数。Hn(x)定义如下:
H0(x) = 1
H1(x) = 2x
Hn(x) = 2x Hn-1(x)-2(n-1) Hn-2(x)    (n>1)
答:
#include <iostream>
using namespace std;
double Hermit_Iterative(int,double);      //迭代方法
double Hermit_Recursion(int,double);    //递归方法
void main()
{    const int n=3;                        //n与x可自行指定
    double x=3.14;
    cout<<Hermit_Iterative(n,x)<<endl
        <<Hermit_Recursion(n,x)<<endl;
}
double Hermit_Iterative(int n,double x)
{    if(n==0)
        return 1;
    else if(n==1)
        return 2*x;
    else
    {    double res1=1,res2=2*x;
        double Result=0;
        for (int i=2;i<=n;i++)
        {    Result=2*x*res2-2*(i-1)*res1;
            res1=res2;
            res2=Result;
        }
        return Result;
    }
}
double Hermit_Recursion(int n,double x)
{    if(n==0)
        return 1;
    else if(n==1)
        return 2*x;
    else
        return 2*x*Hermit_Recursion(n-1,x)-2*(n-1)*Hermit_Recursion(n-2,x);
}
写出计算Ackermann函数Ack(m,n)值的递归函数。Ack(m,n)定义如下(m0,n0)
Ack(0,n) = n+1
Ack(m,0) = Ack(m-1,1)
Ack(m,n) = Ack(m-1,Ack(m,n-1))  (m>0, n>0)
答:
int Ack(int m,int n)
{    if(m==0)   
        return n+1;
    else if(n==0)   
        return Ack(m-1,1);
hermit    else
        return Ack(m-1,Ack(m,n-1));
}
根据下图写一个函数:int path(int n); 用于计算从结点1到结点n(n大于1)共有多少条不同的路径。
      2        4      6      8
                         
      1        3      5      7
答:
int path(int n)
{ if (n==1) return 1;
  if (n==2) return 1;
  if (n==3) return 2;
  if (n%2 == 0)
return  path(n-1)+path(n-2)+path(n-3);
  else
    return path(n-1)+path(n-2);
}
编程解决下面的问题:若一头小母牛,从出生起第四个年头开始每年生一头母牛,按此规律,第n年有多少头母牛?
答:除了第一年到第三年外,每一年的母牛数应该是上一年的母牛数加上三年前的母牛数(现在它们是第四年了,要生小牛了!)
int f(int n)
{ if (n==1 || n==2 || n==3) return 1;
  return f(n-3)+f(n-1);
}
假设有三个重载的函数:
void func(int,double);
void func(long,double);
void func(int,char);
对下面的函数调用,指出它们分别调用了哪一个重载函数;如果有歧义,指出导致歧义的重载函数定义。
func('c',3.0);
func(3L,3);
func("three",3.0);
func(3L,'c');
func(true,3);
答:
func('c',3.0);  与  void func(int,double);  匹配
func(3L,3);  与  void func(long,double);  匹配
func("three",3.0); 没有与之匹配的函数
func(3L,'c'); 与 void func(long,double); 和 void func(int,char); 均能匹配
func(true,3); 与 void func(int,double); 和 void func(int,char); 均能匹配
下面的函数定义为什么是正确的?在函数f中如何区分(使用)它们?
void f()
{    int f;
    .......
}
答:两个f的作用域不一样,void f()中的f为全局作用域,int f; 中的f为局部作用域。在函数f中如果使用局部变量,则用f;如果使用函数f,则用::f。
为什么一般把内联函数的定义放在个头文件中?
答:为了防止同一个内联函数的各个定义之间的不一致,往往把内联函数的定义放在某个头文件中,在需要使用该内联函数的源文件中用文件包含命令#include把该头文件包含进来。由于内联函数名具有文件作用域,因此,不会出现重复定义问题。
2、用循环实现 412中的辗转相除法计算最大公约数。
    答:
int gcd(int x, int y)
{    while (y!=0)
{ int t=y;
  y = x%y;
  x = t;
}
return x;
}