找回密码
 注册
Simdroid-非首页
查看: 1176|回复: 15

【原创】MATLAB函数的输入参数传递方式探秘

[复制链接]
发表于 2007-4-29 10:01:53 | 显示全部楼层 |阅读模式 来自 浙江舟山
在各种语言中,输入参数传递方法(地址传递、值传递)各有不同。如:
VB :默认为地址传递,可以指定用值传递
C:   普通方式实现值传递,指针方式实现地址传递
C++:比 C 多了引用传递,本质上是地址传递
Fortran: 默认为地址传递,可以指定使用值传递

两种传递方式的区别:
用地址传递方式可以在函数内部修改传入的参数值,而值传递不可以。

那么MATLAB的函数参数究竟用哪一种方式呢?
查看帮助文档得到结果:如果函数内部试图修改输入参数的值则为值传递,如果没有修改则为地址传递。
采用这一处理方式的目的是:
一、不允许函数内部修改输入参数的值
二、兼顾执行效率(地址传递不需要将输入参数拷贝一份)

那么我们可不可以去验证一下呢?
首先我们需要借助一个mex函数,该函数的功能就是改变输入参数的数值,由于该函数是借助mex方式实现的,所以MATLAB无法检测到我们修改了输入参数的值。

以下是该mex函数的代码:mexChangeValue.cpp
  1. #include "mex.h"
  2. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  3. {
  4.      if(nrhs != 1)
  5.      {
  6.           mexErrMsgTxt("需要一个输入参数!");
  7.      }
  8.      if(mxIsEmpty(prhs[0]) || !mxIsDouble(prhs[0]))
  9.      {
  10.           mexErrMsgTxt("输入参数必须为非空 Double 类型!");
  11.      }
  12.      double *pValue = mxGetPr(prhs[0]);
  13.      pValue[0] = 1.2;
  14. }
复制代码
然后开始做实验:
  1. function ArgTest
  2. clc
  3. a = 0;
  4. fun1(a);
  5. disp(a);

  6. b = 0;
  7. fun2(b);
  8. disp(b);

  9. function fun1(a)
  10. a = 3;    % 更改输入参数的值为 3,此时MATLAB做一份外部输入参数的拷贝
  11. mexChangeValue(a);    % 用mex方式将输入参数的值改为 1.2,因为做了一份拷贝,所以并没有更改外部参数的值

  12. function fun2(b)
  13. mexChangeValue(b);   % 用mex方式将输入参数的值改为 1.2,还没有做拷贝,更改了外部参数的值
  14. b = 3;                        % 此时做了外部参数的一份拷贝,但为时已晚,外部参数的值已经被更改了
复制代码
我们可以看到输出结果为:
0
1.2000

a 的值没有改变,而 b 的值被改变了,说明在 fun1 中 "a = 3;" 之后,对输入参数 a 做了一份拷贝,变为“值传递”,而在 fun2 中刚开始进入函数时是“地址传递”的。

结论:
1. 在改变输入参数的值之前是“地址传递”的,在改变输入参数的值之后变为“值传递”
2. 我们在编写函数时,尽量不要对输入参数重新赋值,尤其是对复杂的数据,这样会降低执行效率。

[ 本帖最后由 SCIE 于 2007-4-29 11:43 编辑 ]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

1

查看全部评分

发表于 2007-4-30 09:33:24 | 显示全部楼层 来自 浙江杭州
Simdroid开发平台
不愧是金牌会员,很厉害!
谢谢
发表于 2007-4-30 19:47:59 | 显示全部楼层 来自 上海
很深刻!
很经典!
很精彩!
发表于 2007-4-30 20:27:36 | 显示全部楼层 来自 天津
请问SCIE,你用的matlab是哪个版本?
我试了一下你的程序,结果输出的是0 0。
偶用的是2006b
有warning: Input argument 'a'(or 'b')  appears never to be used .
是否可以说参数a、b跟函数中的a、b是不一样的?
发表于 2007-4-30 20:34:44 | 显示全部楼层 来自 天津

回复 #4 Blaise 的帖子

之前我也遇到过一个类似的问题。程序大概是这样的
fun(par)
if nargin~=1
    par=2;%当时只是为了函数调用方便些,给了一个默认值,却带来了隐患。
end
...
可是之后我调用此函数并改变par参数时,结果跟原来的一样。害的我白分析数据了。
发表于 2007-5-2 10:34:57 | 显示全部楼层 来自 河北邢台
两个原则:
           1、所有m函数的输入都是不可改变的,即使在函数里面改变了,函数返回时也会恢复
           2、mex函数和m函数是两回事,在mex函数中可以直接操作输入数据的指针,当然也可以改变输入的值了

评分

1

查看全部评分

 楼主| 发表于 2007-5-3 10:50:40 | 显示全部楼层 来自 浙江舟山
原帖由 Blaise 于 2007-4-30 20:27 发表
请问SCIE,你用的matlab是哪个版本?
我试了一下你的程序,结果输出的是0 0。
偶用的是2006b
有warning: Input argument 'a'(or 'b')  appears never to be used .
是否可以说参数a、b跟函数中的a、b是不一 ...


我用的是6.5,2007b有些差异,它能检测到后面对输入值的改变,只要把函数fun2改一下就可以了。
把 b=3 去掉。

  1. function fun2(b)
  2. mexChangeValue(b);   
复制代码
发表于 2007-5-27 11:17:04 | 显示全部楼层 来自 河南郑州
经典的很啊?
学了不少啊!!

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2007-5-29 15:25:06 | 显示全部楼层 来自 天津蓟县
真是经典啊!

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2007-6-25 23:30:05 | 显示全部楼层 来自 中国农业大学
厉害阿,佩服,我正在学,交流中

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2007-10-11 00:09:30 | 显示全部楼层 来自 北京
这是不是说明matlab对传值操作是有滞后性的吗?
mex函数可以成功修改a的值而后面当出现对a重新赋值的时候就会对a作拷贝从而使之不能修改a的值。
这样的话,我觉得在对待以a作为输入参数的mex函数时,malab也应该以传值方式来对待,不然容易出错吧。

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2007-10-11 19:29:36 | 显示全部楼层 来自 新加坡
这有可能是matlab6.5的bug。因为matlab的function是不会改变输入参数的。也就是在ArgTest中调用func1和func2后都不会改变a和b在ArgTest中的值。不管func1和func2有多复杂。

ArgTest的结果应该是两个0才对。matlabR2007b中测试的结果是这样的。
回复 不支持

使用道具 举报

发表于 2007-11-6 14:49:09 | 显示全部楼层 来自 北京
经典的很啊?
学了不少啊!!

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2007-11-7 15:33:01 | 显示全部楼层 来自 上海嘉定区
原帖由 daoxiangcun2002 于 2007-10-11 00:09 发表
这是不是说明matlab对传值操作是有滞后性的吗?
mex函数可以成功修改a的值而后面当出现对a重新赋值的时候就会对a作拷贝从而使之不能修改a的值。
这样的话,我觉得在对待以a作为输入参数的mex函数时,malab也应 ...

那是否可以理解为,
在function代码中,使用mex函数可以改变输入参数的值,这种改变仅在function代码中没有任何对此输入参数的赋值语句时有效。
我在7.1版本测试为 (把function2的b = 3;去掉)
0
1.2

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2008-7-21 09:03:37 | 显示全部楼层 来自 重庆

回复 1# 的帖子

好,兄弟们顶啊

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2008-7-21 12:04:00 | 显示全部楼层 来自 美国
我的理解是6.5还是真正解释执行的,所以一直到第一次输入变量出现在等号左边的时候,才对它复制。而之后的版本可能在执行函数前进行了简单的预处理,在函数的开头就决定要不要进行复制。

原帖由 taohe 于 2007-10-11 19:29 发表
这有可能是matlab6.5的bug。因为matlab的function是不会改变输入参数的。也就是在ArgTest中调用func1和func2后都不会改变a和b在ArgTest中的值。不管func1和func2有多复杂。

ArgTest的结果应该是两个0才对。matlab ...
回复 不支持

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-5-12 15:19 , Processed in 0.093337 second(s), 25 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表