user-0 提问: 学习到按值传递机制的一点小问题

回复:
user: user-1
content: 在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆

user: user-2
content: 理解和讨论之前请先学会如何观察！

user: user-2
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  想要从本质上理解C指针，必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针，原本看似复杂的东西就会变得非常简单！ 指针即地址。“地址又是啥？”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认：  有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物；  而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。 而我本人属前者。  不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质， 而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。  这辈子不看内存地址和内存值；只画链表、指针示意图，画堆栈示意图，画各种示意图，甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗？本人深表怀疑！ 这辈子不种麦不收麦不将麦粒拿去磨面；只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头，压面条，烤面包，……能从本质上理解面粉、理解面食吗？本人深表怀疑！！  提醒： “学习用汇编语言写程序” 和 “VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 （Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。） 想要从本质上理解C指针，必须学习C和汇编的对应关系。” 不是一回事！  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  十字链表交换任意两个节点C源代码（C指针应用终极挑战）http://download.csdn.net/detail/zhao4zhong1/5532495

user: user-3
content: 引用 3 楼 Lcumin 的回复:[quote=引用 1 楼 jiht594 的回复:] 每个格子是一块内存, a存在第一块内存中 |a=1|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |    值传递之后, b=1在另一个格子, 所以b是a的副本 |a=1|  |  |  |  |  |  |  |b=1 |  |  |  |  |  |  |  |    也就是说, 你修改a不影响b, 修改b不影响a ---------------- 如果引用传递, a,b在同一块内存中, 修改其中一个, 另一个也被修改了. |a=b=1|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  那请问如果一个指针作为变元按值传递时，也应该是传递一个地址副本，这个副本和原来的地址相同吗？该怎样理解？[/quote]                                                                         地址x         地址y |p1=地址x|  |  |  |  |  |  |  |p2=地址x |  |  |  |  |  |  |          |    |  |            | 不知道能看明白吗?  如果修改p1或者p2的值, 比如 p2=地址y, 则p1还是指向地址x. 这里和非指针变量是一样的, 引用传参你自己想把 如果修改 "地址x"的内容, p1和p2所指向的值, 都被修改.

user: user-4
content: 副本，即意味着传入函数中的，是原值的一份拷贝。

user: user-5
content: 传值调用时. 会在栈中重新分配一个空间,(可以理解为新定义了一个变量), 然后把原来的值赋给这个新"变量". 然后再调用函数.  要很好的理解这个东西, 需要你懂汇编, 然后看汇编代码即能明白

user: user-6
content: 《汇编语言 》 -- 王爽 “研究实验 5” 函数如何接收不定数量的参数

user: user-7
content: “按值传递”这个术语不知道是谁发明的。 为了解释C语言的行为，人们不知道发明了多少这种根本不需要的垃圾术语啊！ 1，参数传递类似于赋值，所以，参数传递本来就是传递值而不是其它。 2，至于是否能够通过实参修改其它对象，这是指针的特征，和参数传递无关。

user: user-1
content: 引用 20 楼 zhao4zhong1 的回复:[quote=引用 13 楼 Sandrer 的回复:] 在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 有时（在64位系统上几乎每次）值通过CPU的寄存器而非堆栈内存传递。[/quote]  刚刚看了一下，的确都是 mov 到寄存器的..........

user: user-2
content: 引用 21 楼 Sandrer 的回复:[quote=引用 20 楼 zhao4zhong1 的回复:] [quote=引用 13 楼 Sandrer 的回复:] 在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 有时（在64位系统上几乎每次）值通过CPU的寄存器而非堆栈内存传递。[/quote]  call 之前不是都会 push 入栈吗？[/quote] 要不我怎么会说： 理解和讨论之前请先学会如何观察！ 不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  呢？

user: user-1
content: 引用 20 楼 zhao4zhong1 的回复:[quote=引用 13 楼 Sandrer 的回复:] 在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 有时（在64位系统上几乎每次）值通过CPU的寄存器而非堆栈内存传递。[/quote]  call 之前不是都会 push 入栈吗？

user: user-2
content: 引用 13 楼 Sandrer 的回复:在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 有时（在64位系统上几乎每次）值通过CPU的寄存器而非堆栈内存传递。

user: user-7
content: 引用 18 楼 Sandrer 的回复:[quote=引用 16 楼 sholber 的回复:] 而不要似是而非的在卖弄你的学识 你所说的，正是矛盾的地方，你应当正视。 C本来是很清爽的，没有这些术语。虽然没有这些术语，却也解释得很清楚。 相反，这些术语都是一些写书的人生造出来的，造成了更多的混乱。 我说得不对吗？ C标准用一句话“参数传递类似于赋值”就解释清了所有问题，还需要这些轮子吗？[/quote]  就正是因为你的这个“类似”，所谓的垃圾术语就会这样诞生了 你要说就要说得明明白白，一个“类似”别人会有很多中理解的[/quote]  才发现你上一次的回帖中有这么一句“而不要似是而非的在卖弄你的学识”。 我不会回答你的任何问题了。你可以保留你的看法。

user: user-1
content: 引用 16 楼 sholber 的回复:而不要似是而非的在卖弄你的学识 你所说的，正是矛盾的地方，你应当正视。 C本来是很清爽的，没有这些术语。虽然没有这些术语，却也解释得很清楚。 相反，这些术语都是一些写书的人生造出来的，造成了更多的混乱。 我说得不对吗？ C标准用一句话“参数传递类似于赋值”就解释清了所有问题，还需要这些轮子吗？[/quote]  就正是因为你的这个“类似”，所谓的垃圾术语就会这样诞生了 你要说就要说得明明白白，一个“类似”别人会有很多中理解的

user: user-1
content: 引用 16 楼 sholber 的回复:你所说的，正是矛盾的地方，你应当正视。 C本来是很清爽的，没有这些术语。虽然没有这些术语，却也解释得很清楚。 相反，这些术语都是一些写书的人生造出来的，造成了更多的混乱。 我说得不对吗？ C标准用一句话“参数传递类似于赋值”就解释清了所有问题，还需要这些轮子吗？  哦，那请你指正一下我哪里说得矛盾了  void func(int &n) void func(int *n) void func(int n) 这几个函数请问怎样赋值？ 按你所说的类似赋值，只是“类似”，而不是“真正” 那怎样另不懂的人去明白？  那 vb 里面的 ByRef ByVal 那就是多余的了，C 里面的 *、& 也是多余的了

user: user-7
content: 引用 15 楼 Sandrer 的回复:[quote=引用 14 楼 sholber 的回复:] [quote=引用 13 楼 Sandrer 的回复:] 在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 按值传递？按址传递？这种垃圾术语实在不知道从哪本书开始散播开来的…… 给定函数调用表达式 f (5); 试问，这里的变量是谁？怎么才能“将一个变量的值复制一份到函数参数的栈地址上”？[/quote]  你那么与众不同，为什么不去出书呢，你去出书一定很畅销 所谓的名词，自古以来都是为了通俗易懂为重 那 vb 中的 ByVal、ByRef 你怎样叫法？你的 f(5) 本来就可以理解成按值传递 很简单的一个概念，我给函数传递一个值为5的参数 按你7楼所说，难道这个 5 是指针吗  别人有错你可以指证，但你要为所说的话负责，既然你说它不应该存在，就请证明它为什么不存在 而不要似是而非的在卖弄你的学识[/quote] 你所说的，正是矛盾的地方，你应当正视。 C本来是很清爽的，没有这些术语。虽然没有这些术语，却也解释得很清楚。 相反，这些术语都是一些写书的人生造出来的，造成了更多的混乱。 我说得不对吗？ C标准用一句话“参数传递类似于赋值”就解释清了所有问题，还需要这些轮子吗？

user: user-1
content: 引用 14 楼 sholber 的回复:[quote=引用 13 楼 Sandrer 的回复:] 在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 按值传递？按址传递？这种垃圾术语实在不知道从哪本书开始散播开来的…… 给定函数调用表达式 f (5); 试问，这里的变量是谁？怎么才能“将一个变量的值复制一份到函数参数的栈地址上”？[/quote]  你那么与众不同，为什么不去出书呢，你去出书一定很畅销 所谓的名词，自古以来都是为了通俗易懂为重 那 vb 中的 ByVal、ByRef 你怎样叫法？你的 f(5) 本来就可以理解成按值传递 很简单的一个概念，我给函数传递一个值为5的参数 按你7楼所说，难道这个 5 是指针吗  别人有错你可以指证，但你要为所说的话负责，既然你说它不应该存在，就请证明它为什么不存在 而不要似是而非的在卖弄你的学识

user: user-7
content: 引用 13 楼 Sandrer 的回复:在汇编里面，所有的参数其实都是栈地址，编译时按照栈地址获得变量数据  所谓的按值传递，就是将一个变量的值复制一份到函数参数的栈地址上 而按址传递，就是将函数参数的地址替换成变量的地址，所以修改参数的值会直接作用到函数外部的变量中  程序中一个变量不论是否为指针，只要是变量就肯定会有一个变量地址 在汇编语言中的所有变量不是按名字记忆，而是按地址记忆 按值传递？按址传递？这种垃圾术语实在不知道从哪本书开始散播开来的…… 给定函数调用表达式 f (5); 试问，这里的变量是谁？怎么才能“将一个变量的值复制一份到函数参数的栈地址上”？

user: user-8
content: 在函数调用的时候，在内存中开辟一块地址，用来存放形参的副本，函数调用完后释放，不会改变原来的值。

user: user-9
content: 实参把值赋值给形参，就是副本机制