我记得刚上大学我们学院就给我们开了第一门专业课——高级语言程序设计。在函数一节里面,首先要学到形式参数和实际参数,然后就学了按值传递和按引用传递,当时学得那叫一个云里雾里啊,再加上后面还学了个指针,弄得我完全是丈二和尚摸不着头脑……好在我记住了一段话,并把它做为金科玉律,还是让我勉强在编程的时候不会搞出太多错来。
这段话就是:凡是在函数定义里面的形式参数为类类型的,函数调用时实际参数为对象,此时为按引用传递;凡是在函数定义里面的形式参数为值类型的,函数调用时实际参数为值,此时为按值传递。
还好,这句话有些绕口但不是特别绕口。
现如今,我编程再也不用C和C++了(我皈依到Microsoft门下),真正做应用的时候,那些问题我也从来不再考虑,可是前几天同学弄的一个问题着实让我迷糊了半天。
总之,我先把代码写下来吧。在VS中新建一个控制台应用程序,改写其Program.cs文件如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
有兴趣的话,先想想在控制台里会打出来什么结果——当然啦,这种小儿科只能糊弄像我这样的菜鸟。。。。结果我先写下来
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
其实我也先为自己辩解几句,上面这东西迷糊人,Microsoft也有责任,从前在C的年代,哪有string这东西,什么时候我们都用char*,这肯定是个指针。现如今说int是值类型吧,它有个Int32的结构(Java更狠,直接就是Integer的类),说String是个引用吧,它还有个小写的string的关键字。微软让高人方便了,却让像我这样的矬人傻了眼。
不多说,看上面代码。明眼人一看,第一个changeInt(int i)的方法就是狗屁,这显然是按值传递,以前那个i纹丝不动;再看第三个changA(A a),这个方法也没什么,A是我定义的类型,肯定是按引用传递,方法里面改了A的公共字段,外面的A也得跟着改;最后看一下changeString(string s),直说了吧,这个也是按引用传递,在函数里面改了s,白痴问题来了,函数里面改了s,怎么改完了输出不跟着变呢?
其实这段程序纯是骗小孩玩的,不管我传的是个string还是个String,都是一码事,全是按引用传递的。这段代码和那个changeA(A a)的区别就在于,changeA改的是a的公共字段,而changeString改的是s本身。如果我在changeA的第一句添上a=new A();再运行这段代码,就会发现最后一句输出的a和从前的结果是一样的。
说到底,C#和Java说是不用指针,那不可能,没指针哪来的NullReferenceException和NullPointerException啊。对于按引用传递的对象来说,函数在调用的时候,创建了一个新的指针(Java中的pointer、C#中的reference),指向的是那个对象。这个东西存的就是那个对象在内存里的地址,和C里面的指针是一个东东,只是不让+、-而已。然后我们在changeString里把这个地址指向了"world"的内存地址,这里改变的只是新创建出来的那个指针,而原来那个指向"hello"的没跟着变,所以打印语句打出来的还是hello。对于changeA来说,新创建出来的指针指向地址的和Main函数的a指向的是一个地方,由于在changeA里面我们没给它重新定向,所以我改了changeA里面的a,Main函数里面的a也跟着改了。
现在那条金科玉律还是对的了,只不过我要恬不知耻地加上:看吧,如果你用VS来开发程序,对于函数按引用传递的参数来说,如果你改的东西是.出来的,那就改变了函数外面那个对象,如果你把形参拿下来直接后面就放=了,那外面就不改啦,嘿嘿嘿^_^
PS:看客请不要逼问我指针的定义是啥,如果你认为C#里面reference不是指针我也不反对
缥缈落花街 月圆月缺 望峦山平川 雁返君未还 怆然晚春残 忆天上人间