跟我快乐学C++系列:(4)理解函数的调用

来源:互联网 发布:血清甘油三酯增高 知乎 编辑:程序博客网 时间:2024/05/28 16:25

 

跟我快乐学C++系列:(4) 理解函数的调用
引言
本节课我们依然通过C++代码来探索C++函数。通过分析本节课提供的代码,观察程序的执行结果,您可以发现C++函数调用时形参,实参之间有趣的现象,理解这些现象的本质将有助于理解指针。
适用对象:
本文仅用于初学C++的同学。
如果您对本文理解困难,可以参考本系统的前面的课程:
第一节:介绍了安装c++开发环境,通过图解,您可以获得一个g++的开发环境;
第二节:介绍了c++的基本程序结构;
第三节:介绍了指针的初步。
另外,您还可以参考《跟我学“数据结构”》的第一节。
 
C++函数调用
C++语言通过函数可以把一系列的语句包装在一起被其它函数调用,这相当于把函数的中的语句插入到调用它的代码中一样。
 
理解函数要理解几个重要的术语:
函数的名称
函数的参数列表
函数的返回值类型
函数的返回值
函数的原型
形式参数
实际参数
不用担心上面的术语太多,我们通过示例,就能更好的理解它们。
函数 int main (int argc, char* argv[])
上面这个函数大家最熟悉了。它的函数
  

名称
main
参数列表
int argc, char* argv[]
两个参数,一个是argc,另一个是argv
反回值的类型
int
返回值
在函数结果的 return 0; 0表示是这个函数的返回值。调用main是操作系统,操作系统处理这个返回值。对于操作系统而言,通常0表示函数成功结束。非0表示失败结束。
函数原型
返回类型,名称,参数列表合在一起叫函数原型
形式参数
在函数参数列表中的参数名。
这里argc, argv就是形式参数
实际参数
调用时使用的参数。(后面再举例讲解)

 
运行本节的代码并观察结果
为了讲解方便,代码的运行结果中我们使用了行号,因此建议在编辑器中打开显示行号的功能。
[代码]
Code:
  1. #include <iostream>   
  2. #include<iomanip>   
  3. #include<string>   
  4. using namespace std;   
  5.   
  6. void showBytes(unsigned char* p, size_t length);   
  7. template <typename T> void showType( T x);   
  8. void showPointerAddress(string name,const void* p);   
  9.   
  10. void add_100(int* x, int* p);   
  11. void add_100_2(int& x, int *p);   
  12. void bad_add_100(int x,int *p);   
  13.   
  14. int main(int argc, char* argv[])   
  15. {   
  16.     int a = 3;   
  17.     int* p = &a;   
  18.     cout << "line 18:" << " a = " << dec <<  a << endl;   
  19.     showPointerAddress("line 19 a's address = ",p);   
  20.     add_100(&a,p);   
  21.     cout << "line 21:" << " a = " << dec << a << endl;   
  22.     cout << "line 23:" << " the value in addrees p is " << dec << *p << endl;   
  23.     a = 3;   
  24.     cout << "line 24: let  a is 3" << " a = " << dec <<  a << endl;   
  25.     showPointerAddress("line 25 a's address = ",p);   
  26.     bad_add_100(a,p);   
  27.     cout << "line 28:" << " a = " << dec << a << endl;   
  28.     cout << "line 29:we can not change the a's value. :( " << endl;   
  29.     a = 3;   
  30.     cout << "line 30: let  a is 3" << " a = " << dec <<  a << endl;   
  31.     add_100_2(a,p);   
  32.     cout << "line 32:" << " a = " << dec << a << endl;   
  33.     return 0;   
  34. }   
  35.   
  36. void add_100(int* x,int *p)   
  37. {   
  38.     *x = *x + 100;   
  39.     showPointerAddress("/tline 39 x's address = ",x);   
  40.     cout << "/tline 40, p's address is same as x." << endl;   
  41.     cout << "/tline 41:" << " the value in addrees p is " << dec << *p << endl;   
  42. }   
  43. void bad_add_100(int x,int *p)   
  44. {   
  45.     x = x + 100;   
  46.     showPointerAddress("/tline 46 x's address = ",&x);   
  47.     cout << "/tline 47, p's address is NOT same as x." << endl;   
  48.     cout << "/tline 48:" << " the value in addrees p is " << dec << *p << endl;   
  49.   
  50. }   
  51.   
  52. void add_100_2(int& x, int *p)   
  53. {   
  54.     x = x + 100;   
  55.     showPointerAddress("/tline 55 x's address = ",&x);   
  56.     cout << "/tline 56, p's address is  same as x." << endl;   
  57.     cout << "/tline 57:" << " the value in addrees p is " << dec << *p << endl;   
  58. }   
  59.   
  60. void showBytes(unsigned char* p, size_t length)   
  61. {   
  62.     unsigned int i = 0;   
  63.     for(i = 0; i < length ; i++)   
  64.     {   
  65.         //printf(" %.2x",p[i]);   
  66.         cout<<hex<<setw(2)<<right<<setfill('0')<<(int)p[i] << " ";   
  67.     }   
  68.     cout << endl;   
  69. }   
  70.   
  71. template < typename T > void showType(T x)   
  72. {   
  73.        
  74.     showBytes((unsigned char* )&x, sizeof (T));   
  75.   
  76. }   
  77.   
  78. void showPointerAddress(string name,const void* p)   
  79. {   
  80.     cout << name << " ";   
  81.     showType<const void*>(p);   
  82.        
  83. }   
 
 
line 18: a = 3
line 19 a's address = 60 ff 12 00
         line 39 x's address = 60 ff 12 00
         line 40, p's address is same as x.
         line 41: the value in addrees p is 103
line 21: a = 103
line 23: the value in addrees p is 103
line 24: let a is 3 a = 3
line 25 a's address = 60 ff 12 00
         line 46 x's address = 34 ff 12 00
         line 47, p's address is NOT same as x.
         line 48: the value in addrees p is 3
line 28: a = 3
line 29:we can not change the a's value. :(
line 30: let a is 3 a = 3
         line 55 x's address = 60 ff 12 00
         line 56, p's address is same as x.
         line 57: the value in addrees p is 103
line 32: a = 103
 
代码讲解
帮助函数
代码中使用了3个帮助函数:
void showBytes(unsigned char* p, size_t length);
template <typename T> void showType( T x);
void showPointerAddress(string name,const void* p);
 
这些函数用来显示地址的值。我们不是第一次使用这类帮助函数了,在“跟我学数据结构”一节中,我们也使用了类似的技巧能帮助我们理解c++的机制。
 
代码要点
我们先显示出为变量a的值的地址。请注意代码的第20行,调用 void add_100(int* x, int *p)。调用的代码是第20行。这里的代码
add_100(&a , p),其中 a, p表示函数的实际参数。我们再看代码的36行,这里是函数的实现(即函数的定义),这里的在数列表中的x, p叫形式参数。我们可以让实参与形参用同一个标识符(如p)也可以用不同的标识符如(a,x)。
当我们以指针(地址)为参数调用的函数add_100(),我们得到了期望的结果。
 
紧接着我们试用以传值的方式调用函数bad_add_100(),我们发现形参与实参的地址并不相同,也就是,我们试图修改的值a与实际修改的值x并不是同一个变量,所以我们得不到想要的结果。
 
C++和C语言相比增加了引用类型,它相当于给变量取了一个别名,与指针非常相似,在某些场合要可以代替指针。我们的函数void add_100_2(int& x, int *p)就演示了这个用法。我们发现,引用的地址实际上与实参的地址相同,所以我们得到了期望的结果。
 
 
 
 
原创粉丝点击