为什么“再”呢?哈哈~ 闲话少叙,上代码:
这是我们最熟悉的3个swap函数,分别为传值,传址和传引用,输出结果大家肯定都很清楚:第一个没有交换成功,第二个和第三个交换成功。#include<iostream> using namespace std; void swap_a(int a, int b) { int temp = a; a = b; b = temp; } void swap_b(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } void swap_c(int& a, int& b) { int temp = a; a = b; b = temp; } int main() { int x(10), y(11); swap_a(x, y); cout<<"x="<<x<<" "<<"y="<<y<<endl; swap_b(&x, &y); cout<<"x="<<x<<" "<<"y="<<y<<endl; swap_c(x, y); cout<<"x="<<x<<" "<<"y="<<y<<endl; return 0; }
现在只分析前两个,传值和传址:
1、传值为何没有交换成功?大家肯定都知道,因为传递参数时生成了两个临时变量a、b,同时将x、y的值赋值给a、b,a、b在函数体内完成了交换,x、y没有任何变化。
2、传址为何成功了那?因为传递的是x、y的地址。
这是我们大家都熟悉的一种解释,那么传址函数在传递过程中就有没有生成临时变量吗?
答案是肯定的。这就产生了一个疑问,同样都产生了临时变量,为什么传址交换成功了?
下面分析一下传址过程:
在传址过程中生成了两个临时的指针变量a、b,a、b里分别存储x、y的地址。能成功的关键在于:
int temp = *a; *a = *b; *b = temp;
在这三行核心代码中,通过“*”对a、b中存储的地址对应的值进行了解引用。*a、*b实际是在通过x、y的地址操纵x、y实际的值,最终成功完成了交换。
好了,问题交代清楚。那么看下一个代码:
函数haha()是否帮助p完成分配内存初始化了呢?根据前面的分析,p显然为完成初化,从实质上来看p只是完成了传值。要想真正完成内存分配,可以采用以下两种方法:#include<iostream> #include<stdlib.h> using namespace std; void haha(char* p) { p = (char*) malloc(10); } int main() { char* p = NULL; haha(p); if(p != NULL) { cout<<"p is initial"<<endl; } else { cout<<"p is NULL"<<endl; } return 0; }
1)将p的地址传入;
2)在原函数基础上,返回p值。
问题到此,还未结束,我们来探讨一下类的new操作符,上代码:
#include<iostream> #include<stdlib.h> using namespace std; class Test { public: void f() { cout<<"i am test"<<endl; } }; void hehe(Test* p) { p = new Test; } int main() { Test* p; hehe(p); p->f(); return 0; }
p->f()能调用成功吗?按照前面的思路,当然不能,因为p未完成初始化,所以不能调用。果真如此吗?编译-运行 啊偶~~ 正常输出“i am test”~ why?
想起来啦,类的函数不属于对象的一部分,可以随时通过指针来调用,也就是没有没有hehe()函数也能完成调用。即下面代码依然可以通过运行:
所以,这个例子实际上并未与我们之前对传址的解释相违背,看如下例子:Test* p; p->f();
由于p未初始化,造成了编译错误。#include<iostream> #include<stdlib.h> using namespace std; class Test { public: void f() { cout<<"i am test"<<endl; } int set_a(int x) { a = x; } private: int a; }; void hehe(Test* p) { p = new Test; p->set_a(5); } int main() { Test* p; hehe(p); p->f(); cout<<p->set_a(10)<<endl;//error return 0; }
总结一下,在使用传址时,问一下自己到底是在传值还是在传址,通过解引用操作才能达到真正的传址。