yixinhuahua666
2015-05-30 12:42
采纳率: 100%
浏览 6.5k
已采纳

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

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

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

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

17条回答 默认 最新

  • 就要吃个鸟 2015-05-30 14: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字节)即可。
    特别是在单栈结构的处理器上,系统栈和进程栈使用同一个栈指针,按值传递将会很快耗尽栈空间,导致系统崩溃。
    在双栈设计的处理器上这个问题会好一些,但是也会导致当前进程崩溃。
    对于一些安全性较差的系统,栈的溢出可能导致补课预料的读写了其他进程的空间,甚至是系统区。将会导致不可预知的后果。

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • threenewbee 2015-05-30 12:51
    评论
    解决 无用
    打赏 举报
  • threenewbee 2015-05-30 12:51

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

    评论
    解决 无用
    打赏 举报
  • 美丽小东西 2015-05-30 13:05

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

    评论
    解决 无用
    打赏 举报
  • yixinhuahua666 2015-05-30 13:07

    图片说明

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

    评论
    解决 无用
    打赏 举报
  • fang92 2015-05-30 13:11

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

    评论
    解决 无用
    打赏 举报
  • 零度永恒 2015-05-30 13:29

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

    评论
    解决 无用
    打赏 举报
  • 知常曰明 2015-05-30 13:33
    • 我想你对参数的理解有点偏差。
    • 所谓形式参数,是指在函数定义的时候,得有个形式来接收传递的参数(这个形式在程序来说,也是一个变量),请注意这只是一个形式而已,你可以叫他a,也可以叫他array,或者叫他point都没有关系。"形式"的意思是说,不管这个变量叫什么,都是一个形式。
    • 形式参数是和实际参数对应的,所谓实际参数,就是说我实际传给被调用函数什么。
    • 所有的参数传递,就传递的本身来说,都是不会返回给调用函数的,请记住这一点。
    • 那么为什么传指针会把我们要的值传出来呢?(请注意是我们要的值,不是指针的值。指针的值仍然没有传出来。)
    • 可以认为指针是一块内存的"名字"。你传指针,意思是告诉子函数:"我们交换数据依靠那块内存。"内存是没有作用域的,在程序里,谁都可以写也都可以读
    • 因此,并不是"指针把值传出来",而是"指针指向的地址把值传出来了"
    • 根据你的说法,指针就是一个用完就扔的东西,但是指针扔了,内存没有扔
    评论
    解决 无用
    打赏 举报
  • 美丽小东西 2015-05-30 13:35

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

    评论
    解决 无用
    打赏 举报
  • threenewbee 2015-05-30 13:45

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

    评论
    解决 无用
    打赏 举报
  • haoyu314 2015-05-30 14:20

    不知道可不可以传递数组,但是从你函数形参定义来看,应该只是定义了一个数组,没有成员,会被识别为一个指向int型数组的指针。你可以定义一个含有固定成员的数据类型,作为形参类型。

    评论
    解决 无用
    打赏 举报
  • shadow_dreamer 2015-05-30 14:21

    确实数组传进去的是形参,所以你传的数组名(也即指向数组内容的指针),所以在函数里面,你修改的不是数组名,而是数组里的元素(即指向的内容)
    所以函数调用者的数组内容也会改变的!

    评论
    解决 无用
    打赏 举报
  • 纵横车 2015-05-30 14:48

    指针是形参,只是我们改的是指针指的位置,和指针是不是形参没关系。
    另外如果把数组每个元素都复制一遍传入子函数不觉得太占空间了吗?

    评论
    解决 无用
    打赏 举报
  • 九灵@alibaba 2015-05-30 16:36

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

    评论
    解决 无用
    打赏 举报
  • yixinhuahua666 2015-05-31 00:27

    昨天早早就睡了。感谢大家的回复。我会认认真真看的

    评论
    解决 无用
    打赏 举报
  • ES2020 2015-05-31 00:58

    因为你使用了地址对这个存储但愿的数据进行了操作,你传进函数的参数是复制后的地址,但是它操作的对象是那个地址对应的数据

    评论
    解决 无用
    打赏 举报
  • yixinhuahua666 2015-05-31 02:20

    谢谢各位,我已经懂了,感谢大家

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题