2 huanhuanshisb huanhuanshisb 于 2015.05.30 20:42 提问

C语言数组作为参数传入子函数

对不起,可能我没表达清楚,我想问,数组作为参数传入子函数为什么不是作为形式参数传入,请你看程序运行结果,如果数组作为形式参数传入子函数,那么形式参数的值并不会影响原来main函数中的值,但是实际上,main函数中数组原来的值已经被修改了,这是因为数组传入的是地址(指针),我的问题就在这里,传入的是指针为什么不是用完就扔的形式参数。

这与c语言的设计有关是吗?内部有什么机制吗?

18个回答

u013685226
u013685226   2015.05.30 22:25
已采纳

首先提一下std C 调用约定,参数的传递使用栈。
在传递时首先将参数按照反序压栈,比如你有四个int参数 arg1 arg2 arg3 arg4,那么他们会按照4 - 1的顺序入栈。
接着将返回地址(当前pc值)入栈,然后将当前的辅助栈指针(ebp)入栈,接着设置辅助栈指针为当前栈指针 ebp = esp。
接着在子例程的内部使用ebp作为基准寻址参数。
接下来按照编译器的设计会先为局部变量流出空间或者将会用到的寄存器入栈。
然后子例程的栈架构就建立了。这是寻址参数可以使用 ebp
栈的结构如下:

栈历史 (地址高位)
arg4
arg3
arg2
arg1
pc
ebp
eax
ebx
ecx
...
为局部变量保存的空间
... (esp)(内存低地址)
寻址第一个变量就是在位置 ebp + 4 的位置上(arg1), 同理 arg2 --> ebp + 8, arg3 --> ebp + 12, arg4 --> ebp +16

再回来说数组为什么不采用按值传递的问题。如果一个数组采用按值传递,将会在栈上为这个数组分配大量的空间,而栈空间是非常宝贵且有限的。
但是按引用传递就没有这个问题。不论数组有多长,都只需要传递一个地址。栈空间内只需要保留一个地址的空间(4或8字节)即可。
特别是在单栈结构的处理器上,系统栈和进程栈使用同一个栈指针,按值传递将会很快耗尽栈空间,导致系统崩溃。
在双栈设计的处理器上这个问题会好一些,但是也会导致当前进程崩溃。
对于一些安全性较差的系统,栈的溢出可能导致补课预料的读写了其他进程的空间,甚至是系统区。将会导致不可预知的后果。

huanhuanshisb
huanhuanshisb 懂了!
2 年多之前 回复
caozhy
caozhy   Ds   Rxr 2015.05.30 20:51

其实两种方法都可以。但是传数组占用更多存储空间,好处是可以得到数组长度。

huanhuanshisb
huanhuanshisb 谢谢您,请再看,我修改题目了。
2 年多之前 回复
caozhy
caozhy   Ds   Rxr 2015.05.30 20:51
sinat_28611199
sinat_28611199   2015.05.30 21:05

传数组占用更多存储空间,好处是可以得到数组长度。

huanhuanshisb
huanhuanshisb   2015.05.30 21:07

图片说明

对不起,可能我没表达清楚,我想问,数组作为参数传入子函数为什么不是作为形式参数传入,请你看程序运行结果,如果数组作为形式参数传入子函数,那么形式参数的值并不会影响原来main函数中的值,但是实际上,main函数中数组原来的值已经被修改了,这是因为数组传入的是地址(指针),我的问题就在这里,传入的是指针为什么不是用完就扔的形式参数。

JokerKon
JokerKon 如果你想用的是形参就直接把数组传过去,传入指针的话是属于实参
2 年多之前 回复
JokerKon
JokerKon 因为你传入的指针是指向该数字的地址,当你在函数里面重定义一个数组的时候,他的地址就是你原本主函数里面的数组的地址,而当你改变里面的内容的时候就会影响到原本主函数里面的数组,所以在结束函数之后,返回主函数的时候就会改变原本的数组。
2 年多之前 回复
fang92
fang92   2015.05.30 21:11

其实传到函数的指针也是一个用完就扔的形参而已。只是这个形参是指针,所以通过解引用可以改变数组的值。

chaobo_lu
chaobo_lu   2015.05.30 21:29

这么说吧, main里面 array 的基址是 0x100,长度是10。在调用子函数时,会生存一个临时生存一个数组类型的变量,它的基址也指向 0x100这个地址,长度也是10,它和main里面的array指向同一内存空间,而不是新的内存空间;这个临时变量生命周期只在子函数内有效,子函数退出时就结束了。由于它们都指向同一内存空间,所以你改变了其中一个的值,另外一个的值也跟着被改变了。

gamefinity
gamefinity   Rxr 2015.05.30 21:33
  • 我想你对参数的理解有点偏差。
  • 所谓形式参数,是指在函数定义的时候,得有个形式来接收传递的参数(这个形式在程序来说,也是一个变量),请注意这只是一个形式而已,你可以叫他a,也可以叫他array,或者叫他point都没有关系。"形式"的意思是说,不管这个变量叫什么,都是一个形式。
  • 形式参数是和实际参数对应的,所谓实际参数,就是说我实际传给被调用函数什么。
  • 所有的参数传递,就传递的本身来说,都是不会返回给调用函数的,请记住这一点。
  • 那么为什么传指针会把我们要的值传出来呢?(请注意是我们要的值,不是指针的值。指针的值仍然没有传出来。)
  • 可以认为指针是一块内存的"名字"。你传指针,意思是告诉子函数:"我们交换数据依靠那块内存。"内存是没有作用域的,在程序里,谁都可以写也都可以读
  • 因此,并不是"指针把值传出来",而是"指针指向的地址把值传出来了"
  • 根据你的说法,指针就是一个用完就扔的东西,但是指针扔了,内存没有扔
huanhuanshisb
huanhuanshisb 谢谢!
2 年多之前 回复
sinat_28611199
sinat_28611199   2015.05.30 21:35

只是这个形参是指针,所以通过解引用可以改变数组的值。

caozhy
caozhy   Ds   Rxr 2015.05.30 21:45

因为复制数组的开销很大,这是C语言设计者在最初就将数组当作引用处理的初衷,本质上,传递数组复制的只是数组的指针,而不是数组本身。

huanhuanshisb
huanhuanshisb 就是这样
2 年多之前 回复
共18条数据 1 尾页
Csdn user default icon
上传中...
上传图片
插入图片