跟我快乐学C++系列:(4) 理解函数的调用
引言
本节课我们依然通过
C++
代码来探索
C++
函数。通过分析本节课提供的代码,观察程序的执行结果,您可以发现
C++
函数调用时形参,实参之间有趣的现象,理解这些现象的本质将有助于理解指针。
适用对象:
本文仅用于初学
C++
的同学。
如果您对本文理解困难,可以参考本系统的前面的课程:
第一节:介绍了安装
c++
开发环境,通过图解,您可以获得一个
g++
的开发环境;
第二节:介绍了
c++
的基本程序结构;
第三节:介绍了指针的初步。
另外,您还可以参考《跟我学“数据结构”》的第一节。
C++函数调用
C++
语言通过函数可以把一系列的语句包装在一起被其它函数调用,这相当于把函数的中的语句插入到调用它的代码中一样。
理解函数要理解几个重要的术语:
l
函数的名称
l
函数的参数列表
l
函数的返回值类型
l
函数的返回值
l
函数的原型
l
形式参数
l
实际参数
不用担心上面的术语太多,我们通过示例,就能更好的理解它们。
函数
int main (int argc, char* argv[])
上面这个函数大家最熟悉了。它的函数
名称
|
main
|
参数列表
|
int argc, char* argv[]
两个参数,一个是
argc,
另一个是
argv
|
反回值的类型
|
int
|
返回值
|
在函数结果的
return 0; 0
表示是这个函数的返回值。调用
main
是操作系统,操作系统处理这个返回值。对于操作系统而言,通常
0
表示函数成功结束。非
0
表示失败结束。
|
函数原型
|
返回类型,名称,参数列表合在一起叫函数原型
|
形式参数
|
在函数参数列表中的参数名。
这里
argc, argv
就是形式参数
|
实际参数
|
调用时使用的参数。(后面再举例讲解)
|
运行本节的代码并观察结果
为了讲解方便,代码的运行结果中我们使用了行号,因此建议在编辑器中打开显示行号的功能。
[
代码
]
- #include <iostream>
- #include<iomanip>
- #include<string>
- using namespace std;
- void showBytes(unsigned char* p, size_t length);
- template <typename T> void showType( T x);
- void showPointerAddress(string name,const void* p);
- void add_100(int* x, int* p);
- void add_100_2(int& x, int *p);
- void bad_add_100(int x,int *p);
- int main(int argc, char* argv[])
- {
- int a = 3;
- int* p = &a;
- cout << "line 18:" << " a = " << dec << a << endl;
- showPointerAddress("line 19 a's address = ",p);
- add_100(&a,p);
- cout << "line 21:" << " a = " << dec << a << endl;
- cout << "line 23:" << " the value in addrees p is " << dec << *p << endl;
- a = 3;
- cout << "line 24: let a is 3" << " a = " << dec << a << endl;
- showPointerAddress("line 25 a's address = ",p);
- bad_add_100(a,p);
- cout << "line 28:" << " a = " << dec << a << endl;
- cout << "line 29:we can not change the a's value. :( " << endl;
- a = 3;
- cout << "line 30: let a is 3" << " a = " << dec << a << endl;
- add_100_2(a,p);
- cout << "line 32:" << " a = " << dec << a << endl;
- return 0;
- }
- void add_100(int* x,int *p)
- {
- *x = *x + 100;
- showPointerAddress("/tline 39 x's address = ",x);
- cout << "/tline 40, p's address is same as x." << endl;
- cout << "/tline 41:" << " the value in addrees p is " << dec << *p << endl;
- }
- void bad_add_100(int x,int *p)
- {
- x = x + 100;
- showPointerAddress("/tline 46 x's address = ",&x);
- cout << "/tline 47, p's address is NOT same as x." << endl;
- cout << "/tline 48:" << " the value in addrees p is " << dec << *p << endl;
- }
- void add_100_2(int& x, int *p)
- {
- x = x + 100;
- showPointerAddress("/tline 55 x's address = ",&x);
- cout << "/tline 56, p's address is same as x." << endl;
- cout << "/tline 57:" << " the value in addrees p is " << dec << *p << endl;
- }
- void showBytes(unsigned char* p, size_t length)
- {
- unsigned int i = 0;
- for(i = 0; i < length ; i++)
- {
- //printf(" %.2x",p[i]);
- cout<<hex<<setw(2)<<right<<setfill('0')<<(int)p[i] << " ";
- }
- cout << endl;
- }
- template < typename T > void showType(T x)
- {
- showBytes((unsigned char* )&x, sizeof (T));
- }
- void showPointerAddress(string name,const void* p)
- {
- cout << name << " ";
- showType<const void*>(p);
- }
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)
就演示了这个用法。我们发现,引用的地址实际上与实参的地址相同,所以我们得到了期望的结果。