概述

初学 \(c++\),一直搞不懂其参数传递方式。故找到一篇不错的文章:刘志华的深入探讨C++语言中参数传递问题。亲自实践一遍,并作此记录,以加深印象。

 


 

主要内容

本文主要分为五个小部分,下面依次作总结。

 

简单变量作参数

简单变量作参数的传递方式是按值传递,在这种传递方式下,在函数体中对形参的修改不会影响实际参数的值,因为它们使用各自的存储空间。

下面便是一个简单变量作参数的实例。调用 swap 参数同时把 \(x\) 的值传送给形参 \(a\),把 \(y\) 的值传送给形参 \(b\),在函数体中对形参 \(a\) 和 \(b\) 的操作是与对应的实参 \(x\) 与 \(y\) 无关的,因为它们使用各自的存储空间。

void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int x=45, y = 12;
swap(x, y)
cout<<"x="<<x<<' '<<"y="<<y<<endl;
return 0;
}

输出结果是:\(x=45,\, y=12\). 可见在这种传递方式下,在函数体中对形参的修改不会影响实际参数的值。

 

指针作参数

指针本身是一个变量,特殊之处在于它的值是一个地址,因而可以通过指针来间接访问另外一个内存地址。当函数的形式是指针时,它的实际参数的值必须是一个地址。由于指针作形参,因此对应的形参的实参共用同一个内存单元,形参值的改变将影响实参值。下面继续看一个实例。

void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int x = 45;
int y = 12;
swap(&x, &y); cout<<"x="<<x<<' '<<"y="<<y<<endl; return 0;
}

输出结果是:\(x=12,\, y=45\). 可见在这种传递方式下,在函数体中对形参的修改将影响实际参数的值。

 

引用作参数

由于引用作形参,因此对应的形参和实参就是同一个内存单元,形参值的改变也将影响实参值。

void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int x = 45;
int y = 12;
swap(x, y); cout<<"x="<<x<<' '<<"y="<<y<<endl; return 0;
}

输出结果是:\(x=12,\, y=45\). 可见在这种传递方式下,在函数体中对形参的修改将影响实际参数的值。

引用传送的好处是不需要为形参分配新的存储空间,从而节省存储,另外就是如实例这样,能够使对形参的操作反映到实参上。有时,既为了使形参共享实参的存储空间,又不希望通过形参改变实参的值,则应当把该形参说明为常量引用,如:

void swap(const int& a, const int& b)

在这种情况下,只能读取引用参数 \(a\) 和 \(b\) 的值,不能够修改它们的值,因为它们是对应实参的别名,从而杜绝了对实参的有意或无意的破坏。

 

数组作参数

看下面一个实例。

int sum(int a[], int n)
{
int f = 1;
for (int i=0; i<n; i++)
{
f *=a[i];
}
return f;
}
int main()
{
const int N = 6;
int b[N] = {1,2,3,4,5,6}; int x = sum(b, 6);
int y = sum(&b[2], 4);
int z = sum(b+3, 3); cout<<"x="<<x<<' '<<"y="<<y<<' '<<"z="<<z<<endl; return 0;
}

输出结果是:\(x=720,\, y=360,\,z=120\).

该函数包含一个主函数和一个 sum 函数,其功能是求出一维整型数组所有元素之积并返回。

  • 在主函数第一次调用 sum 函数时,把数组 \(b\) 的首地址传送给 \(a\),把数组 \(b\) 的长度 \(6\) 传送给 \(n\). 执行函数体对数组 \(a\) 的操作实际上就是对主函数中数组 \(b\) 的操作,因为它们同时指向数组 \(b\) 的存储空间;
  • 第二次调用 sum 函数是把数组 \(b\) 中 \(b[2]\) 元素的地址传送给 \(a\), 把整数 \(4\) 传送给 \(n\). 执行函数体对数组 \(a[n]\) 的操作实际上是对数组 \(b[2]\) 至 \(b[5]\) 之间元素的操作;
  • 第三次调用 sum 函数是把数组 \(b\) 中 \(b[3]\) 元素的地址传送给 \(a\), 把整数 \(3\) 传送给 \(n\), 执行函数体对数组 \(a[n]\) 的操作实际上是对数组 \(b[3]\) 至 \(b[5]\) 之间元素的操作。

 

字符串作参数

看下面一个实例。

char* sss(char *sp, char* dp)
{
if (*sp == '\0')
{
*dp = '\0';
return dp;
}
int i=0; // i 是记录 dp 中字符个数
int j;
for (char* p=sp; *p; p++)
{
//扫描 sp 所指字符串中的每个字符位置
for (j=0; j<i; j++)
{
if (*p == dp[j])
break; // 当 *p 与 dp[0] 至 dp[i-1] 之间的任一元素相同则比较过程结束
}
if (j >= i)
dp[i++] = *p; // 若 dp 数组的前 i 个元素不等于 *p, 则把 *p 写入 dp[i] 元素中
}
dp[i] = '\0'; // 写入字符串结束符
return dp;
}
int main()
{
char a[15] = "abcdeabcde";
char b[15]; char* c1 = sss(a, b);
cout<<"c1="<<c1<<' '<<"a="<<a<<' '<<"b="<<b<<endl; char* c2 = sss(a+4, b);
cout<<"c2="<<c2<<' '<<"a="<<a<<' '<<"b="<<b<<endl; return 0;
}

sss 函数的功能是把 sp 所指向的字符串去掉重复字符后拷贝到 dp 所指向的字符数组中,并返回 dp 指针。在主函数中第一次调用 sss 函数时,分别以 \(a\) 和 \(b\) 作为实参,第二次调用时分别以 \(a+4\) (即 \(a[4]\) 的地址)和 \(b\) 作为实参。该程序运行结果是:

\(c1=abcde\,\,a=abcdeabcde\,\, b=abcde\)

 

\(c2=eabcd\,\,a=abcdeabcde\,\, b=eabcd\)

c++ 中的函数调用中的参数传递的更多相关文章

  1. C++函数调用时的参数传递-3中传递方式

    参数传递即实参向形参传递信息,使形参获得对应的存储空间及初值,C++中函数传递主要有3种方式: 1.按值传递. 以按值传递方式进行参数传递的过程为:首先计算出实参的值,然后给它所对应的形参变量分配存储 ...

  2. Jni中C++和Java的参数传递 参数对照

    Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...

  3. C++中构造函数调用构造函数

    今天想做道矩阵的题目时,却卡在一些编程细节上了,找了好久才发现原来是在构造函数处出了问题,然后上网百度了下,发现这篇文章说得很好:从一道题谈C++中构造函数调用构造函数,很棒! 还补充一点: 看来自己 ...

  4. ASP.NET中实现页面间的参数传递

    ASP.NET中实现页面间的参数传递   编写人:CC阿爸 2013-10-27 l  近来在做泛微OA与公司自行开发的系统集成登录的问题.在研究泛微页面间传递参为参数,综合得了解了一下现行页面间传参 ...

  5. Jni中C++和Java的参数传递

    Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...

  6. SSIS中执行SQL任务组件参数传递的问题

    原文:SSIS中执行SQL任务组件参数传递的问题 症状: 执行SQL任务,传递参数到子查询中,执行报错. 错误: 失败,错误如下:"无法从使用 sub-select 查询的 SQL 语句中派 ...

  7. 理解js中的函数调用和this

    概述 这是我看typescript的时候看引用资源看到的,原文在这里:Understanding JavaScript Function Invocation and "this" ...

  8. JS循环中使用bind函数的参数传递问题

    JS循环中使用bind函数的参数传递问题,问题代码如下: for (var sc in result) { var tempp = '<div class="sidebar_todo_ ...

  9. 在chrome开发者工具中观察函数调用栈、作用域链与闭包

    在chrome开发者工具中观察函数调用栈.作用域链与闭包 在chrome的开发者工具中,通过断点调试,我们能够非常方便的一步一步的观察JavaScript的执行过程,直观感知函数调用栈,作用域链,变量 ...

随机推荐

  1. 洛谷 - P5030 - 长脖子鹿放置 - 二分图最大独立集

    https://www.luogu.org/problemnew/show/P5030 写的第一道黑色题,图建对了. 隐约觉得互相攻击要连边,规定从奇数行流向偶数行. 二分图最大独立集=二分图顶点总数 ...

  2. codeforces743D 【DFS】

    题意: 给你一棵以1为root的根,然后让你求两棵不相交子树的最大和: 思路: DFS,主要就是你一定得使两棵子树不相交: 对于一个顶点u,维护以u为根的最大子树和. ①:包含u,即所有的结点和. ② ...

  3. 萌新学习图的强连通(Tarjan算法)笔记

    --主要摘自北京大学暑期课<ACM/ICPC竞赛训练> 在有向图G中,如果任意两个不同顶点相互可达,则称该有向图是强连通的: 有向图G的极大强连通子图称为G的强连通分支: Tarjan算法 ...

  4. CodeForces691C 【模拟】

    这一题的模拟只要注意前后导零就好了... 感受就是... 如果是比赛中模拟题打好..要盯着注意点,测试不同的情况下的注意点..起码要针对性测试10分钟.. 还是蛮简单的,但是自己打烦了,应该,队友代码 ...

  5. 洛谷P4301 [CQOI2013]新Nim游戏(线性基)

    传送门 不知道线性基是什么东西的可以看看蒟蒻的总结 后手在什么时候能够获胜呢?只有在他能构造出一个子集的异或和为0时(这个应该是nim博弈的结论了吧) 那么为了必胜,我们就要取到没有子集异或和为0为止 ...

  6. [Xcode 实际操作]七、文件与数据-(23)UI Testing系统界面测试功能的使用

    目录:[Swift]Xcode实际操作 本文将演示UI Testing系统界面测试功能的使用. 如果项目中尚未引入界面测试功能,请点击项目属性面板->[General]面板左下角的[+]图标 - ...

  7. 初次接触Service笔记

    Service是后台的运行的小程序,分两种一种是StarService()另外一种是bindService(),这种可调用Service中的方法和返回结果等操作而StarService不能 他的生命周 ...

  8. Jquery | 基础 | .hover()

    https://api.jquery.com/hover/#hover-handlerIn-handlerOut http://jquery.cuishifeng.cn/hover.html

  9. [題解](并查集)luogu_P2391 白雪皚皚

    今天被老師留的作業搞死了,全是裸的水題,難題就那麼兩道我還沒寫......,狗屎 1.倒序處理,每個點至多會被更新一次 2.所以要做的就是快速找到下一個不同顏色的點, 3.然而不知道怎麼就 想到用并查 ...

  10. 转 怎样解读10046 trace (tkprof 的结果 )

    set autot on SQL> set autotraceUsage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ ...