VB关于数组作为参数的疑问:

教程说:“数组作为参数,后面的括号不能少”,但是经过我的测试,后面的括号可以少,而且少了括号后,功能更强大,由于是才学不久,如有高手,可以指点一二
Sub zc(ByVal a)
a(1) = "11"
End Sub
Private Sub Command1_Click()
Dim b(3)
b(0) = "a"
b(1) = "b"
b(2) = "c"
b(3) = "d"
Call zc(b)
Print b(1)
End Sub

上面,数组名a,我根本就没加括号,还使用了byval按值传递,子程序中,把a(1)的值变成了“11”,最后输出 b(1)的值,结果输出了b,这说明,他确实是按值传递了,并没有传地址,但是如果子程序的参数a,加了括号后,就不能用byval了,像下面
sub zc(byval a()) 这样写就会提示出错
我刚才看那个教程说,数组必须是传地址,这个又怎么说呢?

Sub zc(ByVal a) //a可以是任意类型;
a(1) = "11" //a被重定义为数组,接收来自b的数据,且a(1)改为"11",感觉像是VB的bug?
ByVal传送的数值,不是传送地址指针,所以修改a的数值不会影响b的数;
sub zc(byval a())会出错,是因为子程序堆栈是有限的,为了防止程序溢出错误,引用数组时强制传输地址指针;

================子程序定义资料==============
Sub语句

声明子过程的名称,参数,以及构成其主体的代码。

语法

[Private | Public | Friend] [Static] Sub name [(arglist)]
[statements]
[Exit Sub]
[statements]

End Sub

Sub 语句的语法包含下面部分:

部分 描述
Public 可选的。表示所有模块的所有其它过程都可访问这个 Sub 过程。 如果在包含 Option Private 的模块中使用,则这个过程在该工程外是不可使用的。
Private 可选的。表示只有在包含其声明的模块中的其它过程可以访问该 Sub 过程。
Friend 可选的。只能在类模块中使用。表示该 Sub 过程在整个工程中都是可见的,但对对象实例的控制者是不可见的。
Static 可选的。表示在调用之间保留 Sub 过程的局部变量的值。Static 属性对在 Sub 外声明的变量不会产生影响,即使过程中也使用了这些变量。
name 必需的。Sub 的名称;遵循标准的变量命名约定。
arglist 可选的。代表在调用时要传递给 Sub 过程的参数的变量列表。多个变量则用逗号隔开。
statements 可选的。Sub 过程中所执行的任何语句组。

其中的 arglist 参数的语法以及语法各个部分如下:

[Optional] [ByVal | ByRef] [ParamArray] varname[( )] [As type] [= defaultvalue]

部分 描述
Optional 可选的。表示参数不是必需的关键字。如果使用了该选项,则 arglist 中的后续参数都必须是可选的,而且必须都使用 Optional 关键字声明。如果使用了 ParamArray,则任何参数都不能使用 Optional。
ByVal 可选的。表示该参数按值传递。
ByRef 可选的。表示该参数按地址传递。ByRef 是 Visual Basic 的缺省选项。
ParamArray 可选的。只用于 arglist 的最后一个参数,指明最后这个参数是一个 Variant 元素的 Optional 数组。使用 ParamArray 关键字可以提供任意数目的参数。ParamArray 关键字不能与 ByVal,ByRef,或 Optional 一起使用。
varname 必需的。代表参数的变量的名称;遵循标准的变量命名约定。
type 可选的。传递给该过程的参数的数据类型,可以是 Byte、Boolean、Integer、Long、Currency、Single、Double、Decimal(目前尚不支持)、Date、String(只支持变长)、Object 或 Variant。如果没有选择参数 Optional,则可以指定用户定义类型,或对象类型。
defaultvalue 可选的。任何常数或常数表达式。只对 Optional 参数合法。如果类型为 Object,则显式的缺省值只能是 Nothing。

说明

如果没有使用 Public、Private 或 Friend 显式指定,Sub 过程按缺省情况就是公用的。如果没有使用 Static,则在调用之后不会保留局部变量的值。Friend 关键字只能在类模块中使用。不过 Friend 过程可以被工程的任何模块中的过程访问。Friend 过程不会在其父类的类型库中出现,且 Friend 过程不能被后期绑定。

注意 Sub 过程可以是递归的;也就是说,该过程可以调用自己来完成某个特定的任务。不过,递归可能会导致堆栈上溢。通常 Static 关键字和递归的 Sub 过程不在一起使用。

所有的可执行代码都必须属于某个过程。不能在别的 Sub、Function 或 Property 过程中定义 Sub 过程。

Exit Sub 语句使执行立即从一个 Sub 过程中退出。程序接着从调用该 Sub 过程的语句下一条语句执行。在 Sub 过程的任何位置都可以有 Exit Sub 语句。

Sub 过程与 Function 过程的相似之处是:它们都一个可以获取参数,执行一系列语句,以及改变其参数的值的独立过程。而与 Function 过程不同的是:带返回值的 Sub 过程不能用于表达式。

可以使用过程名并后跟相应的参数列表来调用一个 Sub 过程。请参阅 Call 语句关于如何调用 Sub 过程的详细的说明信息。

在 Sub 过程中使用的变量分为两类:一类是在过程内显式定义的,另一类则不是。在过程内显式定义的变量(使用 Dim 或等效方法)都是局部变量。对于使用了但又没有在过程中显式定义的变量,除非其在该过程外更高级别的位置有显示地定义,否则也是局部的。

注意 过程可以使用没有在过程内显式定义的变量,但只要有任何在模块级别定义的名称与之同名,就会产生名称冲突。如果过程中使用的未定义的变量与别的过程,常数,或变量的名称相同,则认为过程使用的是模块级的名称。显式定义变量就可以避免这类冲突。可以使用 Option Explicit 语句来强制显式定义变量。

注意 不能使用 GoSub、GoTo 或 Return 来进入或退出 Sub 过程。追问

第一行,如果写成sub zc(a),,这样修改的话,传递的就是地址,修改a,其实就是修改了b,我已经测试过了

如果写成sub zc(byval a)你说的有点道理,a被重定义了数组,并且a数组有b数组的全部数据,而且用ubound(a)输出的最大下标都和b一样,但这样,不就是等价实现数组的传值吗?
这充分说明
数组也可以传值或传地址,可以自己选择。和普通变量一样
前提是,数组参数不加括号,现在看上去,貌似没什么错

追答

ByRef 是 Visual Basic 的缺省选项,也就是说子程序缺省参数是传输地址指针。

sub zc(byval a),a缺省类型VB默认为Variant类型了,等同sub zc(ByVal a As Variant),Variant 是一种特殊的数据类型,除了定长 String 数据及用户定义类型外,可以包含任何种类的数据。既然可以是任何类型数据,数组也是可以的。
至于更深入的为什么就不深究了。要想钻牛角尖的,反汇编后看就知道为什么这样是可以的了。估计是Variant类型是当做临时的全局变量使用的吧。

温馨提示:答案为网友推荐,仅供参考
第1个回答  2011-08-13
不知道你能不能理解,当你调用方法是:
Call zc(b)的时候,这个b代表的是b数组的首元素地址,也是代表b数组,所以虽然的确是传值,但是,并非传的普通数值,而是地址的值。所以,你接收到的,即zc中的a,其实是b的地址,所以
a(1)等效于操作b(1),所以你能做到修改b数组的值。理解这个其实并不困难,如果有C语言的底子,理解起来更快!你懂了吗?追问

你说的,和我的意思,完全相同,我也学过C语言,所以完全能懂
但是似乎倒是你没有看清楚题目
传地址,是首地址,在子程序内部a数组,其实就是b数组
关键的关键在于:我在子程序内部已经把a(1)的值该成了a(1)="11"
按传地址来说:b(1)将发生改变,但是实际b(1)并未改变

追答

Sub zc(ByVal a)
a(1) = "11"
End Sub
改成
Sub zc(ByVal a())
a(1) = "11"
End Sub
应该就可以call 的时候加上括号:
Call zc(b())

第2个回答  2011-08-13
a不加括号怎么看出来是数组?
不管你call不call zc(b)
b(1)就是="b"追问

如果我把第一行该成:sub zc(a)
则b(1)输出为11
不信你去试

相似回答