c中一个利用 副作用 返回值容易出现的误区

        今天一个学弟问了了一个数据结构的问题.他学习是很好的.而且程序中也能显示出编程功底,但这个程序他却没有得到自己想的的结果,很多人编程的时候都会遇到这样的问题,我也遇到过不少.下面先看这个小小程序,它是一个关于,用先根法建立并输出一棵树的程序:

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
 char data;
 struct node *lchild,*rchild;
}BNode;
void createTree(BNode *r){
 char x;
 scanf("%c",&x);
 if(x=='*')r=NULL;
 else{
  r=(BNode*)malloc(sizeof(BNode));
  r->data=x;
  createTree(r->lchild);
   createTree(r->rchild);
 }
}
void PreorderTraverse(BNode *r){
 if(r != NULL){
  printf("%c",r->data);
  PreorderTraverse(r->lchild);
  PreorderTraverse(r->rchild);
 }
}
void main(void)
{
 int i=0;
 BNode *root=NULL;
 printf("Please enter the member in the mode of PreorderTraverse(*=NULL):/n");
 createTree(root);
 printf("the tree is:/n");
 PreorderTraverse(root);
}

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

       一眼看上去(可能看几眼都是这样的),会发现,这个程序挺对的.而且书写格式,还是其它的,都很标准.可是程序执行不出结果,为什么呢...这是个很好的问题.可以给我们自己一个提醒,它让我们再一次去思考,副作用用作返回值本质是怎么样的.以前可能只是知道怎样去用,可是确从来没有想过为什么会这样...

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

      函数参数的副作用,实质是,我把我的地址告诉你,你可以对这地址进行操作,(就是说,这地地址我在函数内也可以操作,本身也可以对其操作),然后,我在函数里面对它里面的值进行修改,当函数返回的时候,外面的值再去用,这块内存的话,就是修改过后的值了..而正常的传值,是传了一份实参的拷贝,作为形参,这样,函数内外就有两块一样的内存了,函数要返回的话,就得用return了.

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

     所以,为了让函数内操作函数外的内存(即,用副作用去实现函数返回值),那么在函数内一定是对形参进行解引用去操作,而要是对形参本身进行操作了,那么对不起,相当于你放弃了对给你传进来的那块内存的操作.这就是上面那题的问题所在.

 

     知道问题了,相应的解决方法也就很明显了,一种是就不用副作用了,直接用return来返回,把传值和返回完全分开.第二种就是,还是用副作用,上面我是想对root这个指针本身的值改变(而不是它指向的地址.况且它开始也没指向任何地方),改变它本身的值,可以把它的地址传进去(不错,就是用二指针.)

 

     下面是我修改后的程序:

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

第一种:(用return)

 

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
 char data;
 struct node *lchild,*rchild;
}BNode;
BNode* createTree(BNode *r){
 char x;
 scanf("%c",&x);
 if(x=='*')r=NULL;
 else{
  r=(BNode*)malloc(sizeof(BNode));
  r->data=x;
  r->lchild=createTree(r->lchild);
  r->rchild=createTree(r->rchild);
 }

return r;
}
void PreorderTraverse(BNode *r){
 if(r != NULL){
  printf("%c",r->data);
  PreorderTraverse(r->lchild);
  PreorderTraverse(r->rchild);
 }
}
void main(void)
{
 int i=0;
 BNode *root=NULL;
 printf("Please enter the member in the mode of PreorderTraverse(*=NULL):/n");
 root=createTree(root);
 printf("the tree is:/n");
 PreorderTraverse(root);
}

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

第二种:(二级指针)

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
 char data;
 struct node *lchild,*rchild;
}BNode;
void createTree(BNode **r){
 char x;
 scanf("%c",&x);
 if(x=='*')*r=NULL;
 else{
  *r=(BNode*)malloc(sizeof(BNode));
  (*r)->data=x;
  createTree(&(*r)->lchild);
   createTree(&(*r)->rchild);
 }
}
void PreorderTraverse(BNode *r){
 if(r != NULL){
  printf("%c ",r->data);
  PreorderTraverse(r->lchild);
  PreorderTraverse(r->rchild);
 }
}
void main(void)
{
 int i=0;
 BNode *root=NULL;
 printf("Please enter the member in the mode of PreorderTraverse(*=NULL):/n");
 createTree(&root);
 printf("the tree is:/n");
 PreorderTraverse(root);
}

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

       这个问题已经解决了,下面,说一下关于传址的一些其它方面的事,主要是程序安全方面的.

 

       想像一下,我把我的地址暴露给你,你可以操作,那我肯定很不爽了.这样很多问题就来了.

    

       1>我把我的内存给你了,你给我释放了怎么办,我并不知道啊,

       2>如果我们是纯种间的调用的话,问题就更多了,我要的释放了我的空间,同样,你在不知道,这里就涉及到了纯种间临界资源访问的问题了,

这里就先不多说了,只要大家都能想到这个严重问题就可以了.

       3>C++中的这种就涉及到了内存管理问题,我应该在什么时候回收内存呢,(因为有多个指针操作同一块空间,我并不知道什么时候这块空间会没人用了),在析构里回收显然是不行的.这里有个很好的解决方法,就是用句柄类代替指针,(c语言中可以用指针的访问控制,其它,句柄就相当于对访问控制的一个封装),关于句柄,可以看之前写的文章.

 

----------------------------------------------------------------------------------------------------------------------------------------------------

 

      最后,祝大家都学习愉快!!~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值