关于函数的参数传递

首先看如下代码:

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() 重新赋值让它指向别的地址(不能进行上面那种无谓的修改,也算是好事)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值