今天一个学弟问了了一个数据结构的问题.他学习是很好的.而且程序中也能显示出编程功底,但这个程序他却没有得到自己想的的结果,很多人编程的时候都会遇到这样的问题,我也遇到过不少.下面先看这个小小程序,它是一个关于,用先根法建立并输出一棵树的程序:
----------------------------------------------------------------------------------------------------------------------------------------------------
#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语言中可以用指针的访问控制,其它,句柄就相当于对访问控制的一个封装),关于句柄,可以看之前写的文章.
----------------------------------------------------------------------------------------------------------------------------------------------------
最后,祝大家都学习愉快!!~~