深入剖析C/C++函数的参数传递机制

本文详细解析了函数参数传递中的指针、引用方式,包括其在效率、作用上的区别,以及如何在不同场景下选择合适的传递方式。通过实例代码展示在C++中使用指针和引用传递参数时的功能与特性,强调了理解这些概念对于提升代码性能的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看一下简单的例子。

void Func1(int x) //这个函数的参数使用值传递方式
{
  x = x + 10;
}
//
当参数类型更复杂时,指针和引用传递方式在效率等方面的优势更为明显
//
不过那样例子就不够“简单”了
void Func2(int *x) //
这个函数的参数使用指针传递方式
{
  *x = *x + 10;
}

void Func3(int &x) //
这个函数的参数使用引用传递方式
{
  x = x + 10;
}

以下代码调用这些函数:

int n = 0;
Func1(n);
acutPrintf(
n = %d
, n); // n = 0
Func2(&n);
acutPrintf(
n = %d
, n); //n = 10
Func3(n);
acutPrintf(
n = %d, n); //n = 20

以上代码段中,当程序调用Func1()函数时,首先在栈(Stack)内分配一块内存用于复制变量n。若变量n的类型复杂,甚至重载了该类的默认拷贝构造函数:

CMyClass(const CMyClass &obj);

这个过程可能会比较复杂。<类的默认拷贝构造函数使用“位拷贝”而非“值拷贝”,若类中包括指针成员,不重载该函数几乎注定程序会出错。关于这个问题以后再深入探讨。>

程序进入函数Func1()体内后,操作的是栈中的临时变量,当函数结束(或者说返回)时,栈内变量被释放。而对于函数Func1()来说的外部变量n并未起任何变化,因此随后的acutPrintf函数将输出n = 0

程序调用函数Func2()时,在栈内分配内存用于存放临时的指针变量x。然后用&运算取得变量n的地址,并拷贝给临时指针变量x作为x的值。此时,指针x就成了指向变量n的指针。在函数体内,*x运算得到的是指针x指向的内容,即变量n。对*x操作实际上就是对n操作。因此,在函数Func2()中变量n的值起了变化。在分析Func2()函数时应该注意到,临时指针变量x要指向的内存地址,也就是说变量x的“值”仍然是采用了值传递方式从函数外部(或者说函数调用者)获得,那么“值”也就应该具有值传递方式的特点,它要在栈中复制临时变量,它在函数体内被修改不会影响到函数外部。比如说,在上面的代码段中,函数Func2()内可以让指针x指向另外的变量,但函数结束或返回后,在函数外部是无法得到这样的指向另外变量的指针。

程序调用函数Func3()时,临时变量x是一个变量n的引用,此时变量x就是变量n本身,对x操作的同时,外部变量n也起了变化。实际上,引用能做的事,指针也能做到。

以上的代码段确实简单,以至还不能充分显示指针和引用在传递函数参数时的许多其他功能。下面我们设计这样一个函数,函数需要两个参数,在函数内将两个参数的值互换。由于值传递方式尽管能通过返回值赋值的方法修改一个参数值,但不能同时修改两个参数值,因此这个函数不能使用值传递方式。使用指针传递方式,函数可以写成这样:

bool swap(int *x, int *y)
{
  int temp;
  temp = *x;
  *x = *y;
  *y = temp;
  return true;
}

以下代码调用该函数:

/*原文如此

int *a = 10;
int *b = 15;

*/

int a1 = 10 ;

int b1 =15 ;

int *a = &a1 ;

int *b = &b1 ;
if (swap(a, b))
{
  acutPrintf(
“整数a1,b1已交换数据,*a = %d, *b = %d
, *a, *b);
}

在以上代码中,swap()函数设计成与常见的ARX函数一致的风格,用一个bool类型返回函数执行状态。<ARX中,这个返回值通常使用Acad::ErrorStatus类。>在调用函数时,由于变量ab已经声明为指针,使用标识符ab访问的是int类型变量的内存地址。

使用引用传递参数,可以这样设计swap()函数:

bool swap(int &x, int &y)

{
int temp;
temp = x;
x = y;
y = temp;
return true;
}

使用代码swap(int a, int b)调用以上函数时,进入函数体内,xy分别是变量ab的引用,对xy操作就是操作变量ab。函数返回后,变量ab的值互相交换了。

注意:以上代码只是交换两个变量(或者指针指向的变量)的值。即将变量ab(或指针ab指向的变量)的修改为ba(或指针ba指向的变量)的值,而不是将指针a指向原来指针b指向的变量。也就是说,swap()函数调用前后,指针ab的值(地址)并没有发生任何变化。(当然,引用关系在任何时候都不能修改。)要修改指针的地址值,应该使用指向指针的指针或者使用对指针的引用。这样设计和调用函数:

 bool swap(int **x, int **y); //使用指向指针的指针传递参数

int *a = 10;//原文如此,不可
int *b = 15;// //
原文如此,不可
swap(&a, &b);

或者:

bool swap(int *&x, int *&y); //使用对指针的引用传递参数

int *a = 10; //原文如此,不可
int *b = 15; //
原文如此,不可
swap(a,b);

在以上的两个swap()函数以交换两个指针的值,使指针a指向原来指针b指向的变量,指针b指向原来指针a指向的变量。

另外,由于引用关系不可修改,指向引用的指针和引用一个引用没有实际意义。若编译器允许它们存在,实际上也会退化为普通指针(或对指针的引用)和引用。这一点请读者自行分析。

最后,我们看一个ARX程序中使用指针和引用传递参数的函数例子:

AcDbDatabase *pDb = new AcDbDatabase();

AcDbBlockTable *pBlkTbl;
pDb->getBlockTable(pBlkTbl, AcDb::kForRead);

ARX帮助中可以查看到,getBlockTable()函数的原型是:

Acad::ErrorStatus getBlockTable( AcDbBlockTable*& pTable, AcDb::OpenMode mode);其中可以看到,函数的第一个参数是对一个AcDbBlockTable类型指针的引用,从而可以在函数体内部对指针pBlkTbl进行修改,使之指向pDb指针指向的图形数据库的块表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值