C++ Primer Plus 笔记第七章

复习函数基本知识:

  要使用C++函数,要完成工作:

     1. 提供函数基本知识;

     2. 提供函数原型;

     3. 调用函数

   库函数是已经定义和编译好的函数,同时可以使用标准库头文件提供其原型

     eg:标准头文件 cstring 中包含了 strlen() 和其它一些字符串相关的函数原型

函数原型和函数调用:

   函数原型描述了函数到编译器的接口,将函数返回值的类型及参数类型和数量告诉编译器;

   double cube ( double x );   or  double cube ( double );    

   原型的功能:

    编译器正确处理函数返回值;

    编译器检查使用的参数数目是否正确;

    编译器检查使用参数类型是否正确,如果不正确,转换为正确的类型(可能的话)

函数和数组:

  int sum_arr ( int * arr,int n )   //  数组的元素为 int 型,因此 正确的函数头传递参数为 int * arr

  int sum_arr ( int arr[ ],int n )  // 用 int arr[ ] 替换 int * arr ,含义相同。同时 int arr[ ] 还提醒用户 arr 不仅指向 int 而且是指向数组的第一个 int 

   在大多数情况下,C++和C语言一样,将数组名视为指针,存在两种例外:

    1. 数组声明,使用数组名来标记存储位置;

    2. 对数组名使用 sizeof 将得到整个数组的长度

   函数传递数组时,将数组的位置(地址)、包含的元素种类(类型)以及元素的数目(n变量)提交给函数;

   函数传递常规变量时,函数将使用变量的拷贝,但使用数组时,函数使用原来的数组;

   可以在被传递函数中,数组参数使用 const 限定符,保证原始数组数据不被修改(只读传入)

    int show_array ( const double arr[ ],int limit );  // 函数原型

键盘输入数组并显示输入数组例程:

 1 #include<iostream>
 2 using namespace std;
 3 int fill_array(double ar[], int limit);
 4 void show_array(const double ar[],int n);   // const 可以防止修改数组内容
 5 
 6 int main()
 7 {
 8     const int arsize = 5;
 9     double ar[arsize];
10     int n;
11     n = fill_array(ar, arsize);    // 数组调用,将数组的首地址作为实参
12     //cout << n<<endl;
13     show_array(ar, n);                
14 }
15 
16 // 输入数组
17 int fill_array(double ar[], int limit) 
18 {
19     double res;
20     int i;
21     for ( i = 0; i < limit; i++)
22     {
23         cout << "Enter value #" << i + 1 << ": ";
24         while (!(cin >> res))        // 判断是否正确读入数字,如果没有,进入循环
25         {
26             cin.clear();            // 重置输入,如果省略,程序将拒绝继续读取输入
27             while (cin.get() != '\n')        // 清除输入流中所有的错误输入到'\n'
28                 continue;
29             cout << "wrong! please enter number: \n"
30                 << "Enter value #" << i + 1 << ":";
31         }
32         if (res < 0)                // 负值输入将提前结束数组的输入
33             break;
34         ar[i] = res;
35     }
36     return i;
37 }
38 // 显示数组
39 void show_array(const double ar[], int n)
40 {
41     for (int i = 0; i < n; i++)
42         cout << ar[i] << endl;
43 }

自下而上的程序设计:

   通过数据类型和设计适当的函数来处理数据,然后将这些函数组合成一个程序;

   适合于OOP——它首先强调的数据表示和操纵

使用数组区间的函数:

   对于处理数组的C++函数,必须将处理数组中的种类、数组的起始位置和数组中元素数量交给函数:

    1. 将数组的起始处的指针作为一个参数,将数组的长度作为第二个参数;

    2. 指定元素区间,通过传递两个指针完成,一个标识数组开头,一个标识数组尾部

   eg: 

    sum = sum_arr ( arr, arr+3 );                       // 函数调用,实参传入地址区间 

    int sum ( const int* begin,const int* end );// 函数头,形参为两个指向数组类型的指针(int*)

指针和 const:

   可以使用两种不同的方式将 const 关键字用于指针:

    1. 让指针指向一个常量对象,防止使用该指针修改所指向的值;

    2. 将指针本身声明为常量

   声明一个指向常量的指针:

    int age = 39;

    const int * pt = &age;

    声明中 pt 指向一个 const int 因此不能使用 pt 修改这个值—— *pt 为常量不能修改

   还可以将 const 变量的地址赋给指向const的指针,不能将 const 的地址赋给常规的指针

   记住:如果数据类型不是指针,可以将 const 数据或非 const 数据的地址指向 const 指针

      不能将 const 数据赋给非 const 指针

    int * const finger = &sloth:

    指针 finger 本身被声明为 const,使得 finger 只能指向 sloth,但允许使用 finger 来修改 sloth 的值

函数和二维数组:

   数组作为参数的函数,数组名被视为地址,相应的形参应为一个指针;

   int data[3][4] = { {1,2,3,4},  {9,8,7,6},  {2,4,6,8} };  // 声明

   int tatal = sum(data, 3);                                 // 调用

   两种函数原型(形参的形式):

     int sum (int (*ar2) [4],int size );    // 声明一个由4个指向 int 的指针组成的数组,括号不能省

     int sum (int ar2[ ][4],int size);       // 可读性更强

   在函数定义中使用二维数组,最简单的办法是将 ar2 看作一个二维数组的名称

   ar2 实际上是一个指针,必须对 ar2 执行两次解除引用才能得到数据:

    最简单的方式:ar2[r][c];

    ar2[r][c] = *(*(ar2 + r) + c);    // same thing

函数和C-风格字符串:

   将字符串作为参数时意味着传递的是地址;

   表示字符串的方式有3种:

    1. char 数组

    2. 用引括号起的字符串常量

    3. 被设置为字符串的地址的 char 指针

   将字符串作为参数来传递,实际传递的是字符串的第一个字符的地址,形参声明应为 char*:

    int c_in_str (const char * str,char ch); // 使用指针表示法

    int c_in_str (const char str[],char ch); // 也可以使用数组表示法

   处理字符串中字符的标准方式:

1 while (*str)        // until *stt == '\0'
2 {
3     statement;
4     str++      // 将指针增加一个字节 
5 }

返回C-风格字符串的函数:

   函数无法返回一个字符串,但是可以返回字符串的地址;

   char * buildstr ( char c,int n )

函数和结构:

   为结构编写函数比为数组编写函数简单,结构变量相比于数组更接近于单值变量;

   函数可以使用原始结构的拷贝,也可返回结构(因为结构可以互相赋值);

   结构名只是结构的名称,要获得结构的地址,必须使用地址操作符 &;

处理结构的函数例程:

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 struct polar {
 6     double distance;
 7     double angle;
 8 };
 9 struct rect {
10     double x;
11     double y;
12 };
13 polar rect_to_polar(rect xypose);
14 void show_polar(polar rrpose);
15 int main()
16 {
17     polar rppose;
18     rect xypose;
19     cout << "Enter pose x and y or type 'q' to quiz: ";
20     while (cin>>xypose.x>>xypose.y)
21     {
22 
23         rppose = rect_to_polar(xypose);
24         show_polar(rppose);
25         cout << ("Continue Enter x and y or type 'q' to quiz: ");
26 
27     }
28     return 0;
29 }
30 
31 polar rect_to_polar(rect xypose)
32 {
33     polar rppose;
34     rppose.distance = sqrt(xypose.x*xypose.x + xypose.y*xypose.y);
35     rppose.angle = atan2(xypose.y, xypose.x);
36     return rppose;
37 }
38 
39 void show_polar(polar rppose)
40 {
41     const double rad_to_deg = 57.29577951;
42 
43     cout << "distance = " << rppose.distance << endl;
44     cout << "angle = " << rppose.angle*rad_to_deg << " degrees\n";
45 
46 }

 传递结构地址例程:

   与传递结构本身不同之处:

    1. 调用函数时,将结构地址(&pplace)而不是结构本身(pplace);

    2. 将形参声明为指向 polar 的指针,即 polar* 类型;

    3. 形参指针而不是结构,因此应使用间接成员操作符(->)而不是(.);

    4. 传递地址而不是复制,函数可能不在需要返回值,使用 void

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 struct polar {
 6     double distance;
 7     double angle;
 8 };
 9 struct rect {
10     double x;
11     double y;
12 };
13 void rect_to_polar(const rect * xypose, polar* rppose);
14 void show_polar(const polar * rppose);
15 int main()
16 {
17     polar rppose;
18     rect xypose;
19     cout << "Enter pose x and y or type 'q' to quiz: ";
20     while (cin >> xypose.x >> xypose.y)
21     {
22 
23         rect_to_polar( &xypose, &rppose );
24         show_polar( &rppose );
25         cout << ("Continue Enter x and y or type 'q' to quiz: ");
26 
27     }
28     return 0;
29 }
30 
31 void rect_to_polar(const rect* xypose, polar * rppose)
32 {
33     rppose->distance = sqrt(xypose->x*xypose->x + xypose->y*xypose->y);
34     rppose->angle = atan2(xypose->y, xypose->x);
35 }
36 
37 void show_polar(const polar * rppose)
38 {
39     const double rad_to_deg = 57.29577951;
40 
41     cout << "distance = " << rppose->distance << endl;
42     cout << "angle = " << rppose->angle*rad_to_deg << " degrees\n";
43 
44 }

 函数和 string 对象:

   C++如果需要多个字符串,可以声明一个 string 对象数组,而不是二维 char 数组;

   以下例程声明了一个 string 对象数组,并将该数组传递给一个函数以显示其内容:

 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 const int SIZE = 5;
 5 void display(const string list[], int n);
 6 
 7 int main()
 8 {
 9     string list[SIZE];    // 声明 string 数组,每一个元素为一个 string 对象
10     cout << "Enter your " << SIZE << " favotite astronomical sights: \n";
11     for (int i = 0; i < SIZE; i++)
12     {
13         cout << i + 1 << ": ";    
14         getline(cin, list[i]);       // 读取一个字符串     
15     }
16 
17     cout << "Your list: \n";
18     display(list, SIZE);
19 
20     return 0;
21 }
22 
23 void display(const string list[], int n)
24 {
25     for (int i = 0; i < n; i++)
26         cout << list[i] << endl;
27 }

    该例程中,除了函数 getline() 外,程序像对待内置类型(int)一样对待 string 对象

递归:

   函数调用自己成为递归;

   每个递归都创建自己的一套变量;

函数指针:

   可以编写将另一个函数的地址作为参数的函数;

   这种方法与调用函数相比,允许在不同的时间传递不同的函数地址;

函数指针基础知识:

   获取函数地址;

   声明函数的指针;

   使用函数指针来调用函数

   1. 获取函数地址

    只要使用函数名即可,如果 think() 是一个函数,则 think 就是该函数的地址

    要区分函数的地址和函数的返回值:

      process ( think );  // 参数为函数地址,使得函数 process 能够在函数内部调用 think() 函数

      thought ( think() );     // 参数为函数的返回值,先调用 think() 函数,其返回值传给 thought

   2. 声明函数指针

    声明函数指针时,必须指定指针指向的函数类型:

      double pam ( int );      // 原型

      double ( *pf ) ( int ); // 指针类型声明,将 pam 替换为了 (*pf),(*pf)是函数,pf 就是函数指针

      pf = pam;      // 将相应的函数地址赋给指针

    提示: 要声明指向特定类型的函数指针,可以先编写这种函数的原型,然后用(*pf)替换函数名

    注意: 函数地址赋给函数指针时,特征标和返回返回类型必须相同

   3. 使用指针来调用函数

    void estimate ( int lines,double (*pf) (int) );   // 函数原型

    estimate ( 50, pam);            // 让 estime() 使用 pam() 函数

    (*pf) 扮演的角色与函数名相同,使用(*pf)时,只需要将它看成函数名

      double pam ( int );

      double (*pf) (int);

      pf = pam;       // 函数指针指向函数 pam()

      double x = pam (4);  // 使用函数名调用函数pam()

      double y = (*pf) (5);  // 使用函数指针调用函数pam()

      double y = pf(5);    // C++允许像使用函数名那样使用 pf

复习题:

 函数 judge() 的返回值为 int,他将这样一个函数地址作为参数:将 const char 指针作为参数,返回一个 int 值,编写函数原型:

    int judge ( int (*pf) ( const char * ) )

  

    

       

 

 

  

          

     

  

    

 

   

      

猜你喜欢

转载自www.cnblogs.com/kidycharon/p/9689357.html