您的位置:首页 > 其它

关于函数的参数传递

2012-11-23 00:16 183 查看
首先看如下代码:

void creatBtree(Node* head) //按前序生成树。
{
head=new Node();
Node* p=head;
int t;
scanf("%d",&t);
if(t==-1)return;
else p->data=t;
creatBtree(p->left);
creatBtree(p->right);
printf("%在函数里,head的地址为%d\n",head);
return;
}
int main()
{
Head *head;
freopen("tree.txt","r",stdin);
printf("在main中,creat前,head的地址为%d\n",head);
creatBtree(head);
printf("在main中,creat后,head的地址为%d\n",head);
freopen("CON", "r", stdin);
/*以上内容生成了一棵树。*/
return 0;
}


输出结果为:

在main中,creat前,head的地址为2130567168

在函数里,head的地址为3754792

在函数里,head的地址为3754864

在函数里,head的地址为3754768

在函数里,head的地址为3754744

在函数里,head的地址为3754984

在函数里,head的地址为3755056

在函数里,head的地址为3754960

在函数里,head的地址为3739392

在main中,creat后,head的地址为2130567168

可以看出,尽管是传地址,但是函数里对head的修改,返回到main后就消失了。

你是传了head这个“结构体的地址”,可你要修改的就是head这个指针本身,你传它进函数有什么用?你要修改它,你就该把它取地址传入函数!(即方案二和方案三)

想修改谁,就要把谁的地址传进去!!!可以用指针(多重指针),也可以传引用!!!

这是因为,这里虽然传的指针,但是是复制指针的值传进去的。

所谓传地址,指的是你传“你要修改的变量”的地址,然后在函数里你可以通过这个地址来修改这个变量。这个临时地址变量依然是通过复制传到函数里面的,任何函数传参都是复制,只看你复制的是什么东西,什么“传指针”“传引用”,本质上都是“获得指针和引用,然后把它们复制给函数”!

在函数里,new 函数给head重新分配了一块内存地址(这里是对指针进行了修改,修改的是那个副本。因此出去之后,这种修改就没了。),也就是说,head重新指向了另一块地址。之后在所有操作都是在这个新地址里进行的。而传进去的那个地址相当于压根儿没用,没有得到任何修改。因此在main里那个head没有被修改。

传指针,只能修改指针指向的内容。不能修改指针(改了也白改,因为传的这个指针,与传值是一样的,是一个副本)。要想修改指针,就要用指向指针的指针。

咋办呢?

方案一:

最常用的方法,在函数里面申请的内存,要return,才能继续使用。

Node* creatBtree() //按前序生成树。
{
int t;
scanf("%d",&t);
if(t==-1)
{
return NULL;
}
Node* head;
head=new Node();
head->data=t;
head->left=creatBtree();
head->right=creatBtree();
printf("%在函数里,head的地址为%d\n",head);
return head;
}
void preOrder(Node* head) //前序遍历
{
if(head==NULL)    return;
printf("%d ",head->data);
preOrder(head->left);
preOrder(head->right);
}


方案二:

使用指向指针的指针。

void creatBtree(Node** head) //按前序生成树。  传指针,只能修改指针指向的内容,不能修改指针(改了也白改,因为传的这个指针,与传值是一样的,是一个副本)。要想修改指针,就要用指向指针的指针。
{
int t;
scanf("%d",&t);
*head=new Node();
if(t==-1)
{
*head=NULL;
return;
}
(*head)->data=t;
creatBtree(&(*head)->left);

creatBtree(&(*head)->right);
return;
}
void preOrder(Node *head) //前序遍历
{
Node* p=head;
if(p==NULL)    return;
printf("%d ",p->data);
preOrder(p->left);
preOrder(p->right);
}
int main()
{
Head** head;

freopen("tree.txt","r",stdin);
printf("在main中,creat前,head的地址为%d\n",*head);
creatBtree(head);
printf("在main中,creat后,head的地址为%d\n",*head);
freopen("CON", "r", stdin);
/*以上内容生成了一棵树。*/

preOrder(*head);

return 0;
}


方案三:采用传引用的方式。

首先明确一下传引用。

传引用就相当于扩大了这个变量的作用域。

在main里声明了一个变量,通过传引用进入这个函数后,在这个函数里使用这个变量,可以完全与在main里使用这个函数一样。

传引用也是传了个地址进去,但区别在于,在函数里用这个参数时,不需加“*”,直接就能访问地址指向的值。

例如 :

void func(int* t)
{
(*t)++;
}
int main()
{
int *t;
*t=0;
func(t);
printf("%d",*t);
return 0;
}


void func(int &t)
{
t++;
}
int main()
{
int t;
t=0;
func(t);
printf("%d",t);
return 0;
}


以上两个函数运行结果一样,都是1。

从中可以看出,在传&t的函数里,直接修改t,就能修改t的值。

而在传*t的函数里,要想修改t的值,必须使用(*t)取出t所指向的地址里的值。

&t里的t,相当于*t里的(*t)。

因此,第三种方案如下:推荐这一种!!传引用好处多多。

void creatBtree(Node* &head) //按前序生成树。传入head这个指针的引用。(相当于前面的传入了一个指向指针的指针)
{
head=new Node(); //使用head这个指针,就像在main里一样。直接用。

int t;
scanf("%d",&t);
if(t==-1){head=NULL;return;}
else head->data=t;
creatBtree(head->left);
creatBtree(head->right);
printf("%在函数里,head的地址为%d\n",head);
return;
}
void preOrder(Node* head) //前序遍历
{
if(head==NULL)    return;
printf("%d ",head->data);
preOrder(head->left);
preOrder(head->right);
}
int main()
{
Head *head; //head是个指向结构体的指针

freopen("tree.txt","r",stdin);
printf("在main中,creat前,head的地址为%d\n",head);
creatBtree(head);
printf("在main中,creat后,head的地址为%d\n",head);
freopen("CON", "r", stdin);
/*以上内容生成了一棵树。*/
preOrder(head);
return 0;
}


实质其实类似于二重指针。&相当于隐式的使用了“*”。

传指针和传引用的区别:

传指针,传进来的是指针的副本(与传值一样);

传引用,不产生副本。

因此

传进来的指针p,可以修改这个指针,比如p=new Node(),让它指向别的地址(尽管这种修改往往只是局部的修改,即修改的是副本,没什么用,不会对原来那个指针的值(即它所指向的地址)产生影响)。

而传进来的引用t,不能对它修改(因为没有产生副本)。不能通过给&t=new Node() 重新赋值让它指向别的地址(不能进行上面那种无谓的修改,也算是好事)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: