函数传指针

函数传指针与引用

由于在今天编程的时候遇到一个小小的问题,这个问是虽然小,但是闲扰了我一整天的时间------注意,是一整天!

废话不多说,先给出一段代码

  1. // 二叉树的建立.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include <iostream>
  4. using namespace std;
  5. //定义二叉排序树的节点
  6. typedef struct Node
  7. {
  8. int data;
  9. struct Node * lchild;//左孩子
  10. struct Node * rchild;//右孩子
  11. }Node,* PNode;
  12. PNode T=NULL;//二叉排序树的根节点
  13. //中序遍历二叉树
  14. void MidSequence(PNode t)
  15. {
  16. if(t!=NULL)
  17. {
  18. MidSequence(t->lchild);
  19. cout<<t->data<<" ";
  20. MidSequence(t->rchild);
  21. }
  22. }
  23. //往二叉排序树中插入一个新节点(递归实现)
  24. void CreateBSortTree2(PNode & t,int data)
  25. {
  26. if(t==NULL)
  27. {
  28. //建立一个新节点
  29. PNode p=(PNode)malloc(sizeof(Node));
  30. p->data=data;
  31. p->lchild=NULL;
  32. p->rchild=NULL;
  33. t=p;
  34. return;
  35. }
  36. else if(t->data>data)
  37. CreateBSortTree2(t->lchild,data);
  38. else
  39. CreateBSortTree2(t->rchild,data);
  40. }
  41. void insertNode(Node *root,int value){
  42. if(root==NULL){
  43. Node *node=(Node*)malloc(sizeof( Node));
  44. node->data=value;
  45. node->lchild=NULL;
  46. node->rchild=NULL;
  47. root=node;
  48. return ;
  49. }
  50. if(root->data>value){
  51. insertNode(root->lchild,value);
  52. }
  53. if(root->data<value){
  54. insertNode(root->rchild,value);
  55. }
  56. }
  57. //测试
  58. int main()
  59. {
  60. int a[]={0,5,8,4,2,3,10};
  61. int len=sizeof(a)/sizeof(int);
  62. for(int i=0;i<len;i++)
  63. {
  64. //CreateBSortTree2(T,a[i]);
  65. insertNode(T,a[i]);
  66. }
  67. std::cout<<T->rchild->data;
  68. MidSequence(T);
  69. system("PAUSE");
  70. return 0;
  71. }

上面代码的意思是写了两个二叉树插入的代码,一个是我写的:

  1. void insertNode(Node *root,int value){
  2. if(root==NULL){
  3. Node *node=(Node*)malloc(sizeof( Node));
  4. node->data=value;
  5. node->lchild=NULL;
  6. node->rchild=NULL;
  7. root=node;
  8. return ;
  9. }
  10. if(root->data>value){
  11. insertNode(root->lchild,value);
  12. }
  13. if(root->data<value){
  14. insertNode(root->rchild,value);
  15. }
  16. }

上面这部分的代码是存在一定的问题的。不能按期望的结果把value值插入到二叉树中。

  1. //往二叉排序树中插入一个新节点(递归实现)
  2. void CreateBSortTree2(PNode & t,int data)
  3. {
  4. if(t==NULL)
  5. {
  6. //建立一个新节点
  7. PNode p=(PNode)malloc(sizeof(Node));
  8. p->data=data;
  9. p->lchild=NULL;
  10. p->rchild=NULL;
  11. t=p;
  12. return;
  13. }
  14. else if(t->data>data)
  15. CreateBSortTree2(t->lchild,data);
  16. else
  17. CreateBSortTree2(t->rchild,data);
  18. }

而上面的程序按预期的结果运行了。其实比较上面两段代码,我们可以发现,两段代码除了

void  CreateBSortTree2(PNode & t,int data)

void insertNode(Node* root,int value)

红色的部分外,其它的一模一样的。于是我们会问了,为什么会这样子?我们传的不是指针吗,只要是指针,不管在哪里

都可以改变原来的值吗?

嗯,是的,确实可以改变原来的值,因为它把原来值的地址传给你了嘛。。注意,这里传指针也就是将地址按值传过了,

你要知道C语言里面传值是坑人的复制一份的策诺。嗯。。。你确实可以改变函数外面的那个值,但关键是你得使用一个

解引用(*)的操作 也就是说,你得结合那个解引用的操作才行啊,,其它都是扯淡。

  1. #include<iostream>
  2. void foo(int *a){
  3. int b=10;
  4. std::cout<<"b的值 "<<b<<std::endl;
  5. //a=&b;
  6. *a=b;
  7. }
  8. int main(){
  9. int a=3;
  10. foo(&a);
  11. std::cout<<"a的值 "<<a<<std::endl;
  12. }

但是如果程序变成这样:、

  1. #include<iostream>
  2. void foo(int *a){
  3. int b=10;
  4. std::cout<<"b的值 "<<b<<std::endl;
  5. a=&b;
  6. // *a=b;
  7. }
  8. int main(){
  9. int a=3;
  10. std::cout<<"函数运行前a的值 "<<a<<std::endl;
  11. foo(&a);
  12. std::cout<<"函数运行后a的值 "<<a<<std::endl;
  13. }

看到没有,这里a的值可是没有半点改变呢。但是在函数里面我们可是改变了它的地址啊。。。

void foo(int *a){

int b=10;

std::cout<<"b的值 "<<b<<std::endl;

a=&b;

// *a=b;

}

这里传入叁数的时候,确实是将a的地址变成了b的地址。

但是前面说过,传指针其实就是将地址传值嘛。

指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

我们还是回到前面的问题,那为什么人家的代码可以呢?

  1. //往二叉排序树中插入一个新节点(递归实现)
  2. void CreateBSortTree2(PNode & t,int data)
  3. {
  4. if(t==NULL)
  5. {
  6. //建立一个新节点
  7. PNode p=(PNode)malloc(sizeof(Node));
  8. p->data=data;
  9. p->lchild=NULL;
  10. p->rchild=NULL;
  11. t=p;
  12. return;
  13. }
  14. else if(t->data>data)
  15. CreateBSortTree2(t->lchild,data);
  16. else
  17. CreateBSortTree2(t->rchild,data);
  18. }

因为它传的是引用:

而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。

被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操

作都影响了主调函数中的实参变量。

引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。

为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。

来源: <http://xinklabi.iteye.com/blog/653643>

来自为知笔记(Wiz)

时间: 2024-11-05 14:53:27

函数传指针的相关文章

关于函数传参--传指针,传引用

今天和同学讨论到指针和引用的传递问题,有些想法从推理上讲是正确的,但是因为是推理,说出自己观点的时候不是那么有底气,本着实践是检验真理的唯一标准的原则,在电脑上敲了几段代码,验证了推理的正确性. 先上代码,再分析. 代码1: void Swap0(int a1,int b1){ int temp; temp=a1; a1=b1; b1=temp; } void Swap1(int *a1,int *b1){ //交换地址 int *temp; temp=a1; a1=b1; b1=a1; } v

函数参数的传值和传指针有什么区别?

前言 我们可能听过C语言中的传值和传指针,在其他语言中,也有传引用一说,那么他们到底有什么区别呢?如果你还不能准确地分辨,就该好好了解一下了. 传值 我们在初学C语言的时候就被老师教过,下面的方式是无法交换a和b的值的: #include<stdio.h> void swap(int a,int b) { int temp = a; a = b; b = temp; printf("swap a = %d,b = %d\n",a,b); } int main(void) {

1.7 C之 指针与函数传参(挺骚)

前置++和后置++的区别前置++称为前自加,后置的++称为后自加.其计算效果均为操作数自加一.当单独一个语句的时候没有区别,如果用在表达式中:i++是先自加,然后在取i的值做计算.int i =2, j:如果j = i++:那么先取i的赋值给j,于是j值为2,i值再自加,i=3.如果j =++i:那么i先自加,得到i = 2,然后再取i计算,j值为3. 函数传参中使用的指针int add(int a,int b)函数传参使用了int型数,本身是数值类型.实际调用该函数时,实参将自己拷贝一份,并将

华为机试 小结 关于函数传参修改的问题

第一第二道题比较简单,第三道题还好,就是一个递归,但是传参的时候出了个问题,我做了一个flag来标志,但是函数中修改了flag之后,但是退出函数之后,flag并没有改变,想起来,应该是没有传入指针,故此处进行学习. http://blog.csdn.net/herecles/article/details/6072523 在C++中,如果函数的实参的类型是数据类型比较大的数据类型,这是如果使用一般传参就会有很大的不方便,这是如果能够传递一个地址或者是对原来参数的一个引用对提高性能会有很大的帮助.

c++: 指向类成员函数的指针

指向函数的指针有和指向类成员函数的指针的有什么不同? int f(char a, float b);如果它是普通函数,则它的类型是 int (*)(char, float);如果它是非静态成员函数,则它的类型是 int(ClassName::*)(char, float);如果它是静态成员函数,则它的类型是和普通函数一样. 如何把一个类的成员函数传递给event handler, 线程启动函数等? 类的成员函数必须和一个类的实例结合起来才有意义.可以写一个函数来包装类的成员函数. class X

C语言中函数和指针的参数传递

最近写二叉树的数据结构实验,想用一个没有返回值的函数来创建一个树,发现这个树就是建立不起来,那么我就用这个例子讨论一下c语言中指针作为形参的函数中传递中隐藏的东西. 大家知道C++中有引用的概念,两个数据引用同一个数据,那么更改任意的一个都相当于更改了本体,那么另一个数据所对应的值也会改变,可是C中是没有这个概念的.所以就产生了一些东西.和我们本来想的有差别. 一.明确C语言中函数的入口: C语言中函数的形参负责接收外部数据,那么数据究竟怎么进入函数的呢,其实我们在函数体内操作的形参只是传递进来

学习笔记之14-返回指针的函数与指向函数的指针

一.返回指针的函数 指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的. 返回指针的函数的一般形式为:类型名 * 函数名(参数列表) 比如下面这个函数,返回一个指向char类型变量的指针 1 // 将字符串str中的小写字母变成大写字母,并返回改变后的字符串 2 // 注意的是:这里的参数要传字符串变量,不能传字符串常量 3 char * upper(char *str) { 4 // 先保留最初的地址.因为等会str指向的位置会变来变去的. 5 char *dest =

【C语言】-返回指针的函数与指向函数的指针

本文目录 前言 一.返回指针的函数 二.指向函数的指针 说明:这个C语言专题,是学习iOS开发的前奏.也为了让有面向对象语言开发经验的程序员,能够快速上手C语言.如果你还没有编程经验,或者对C语言.iOS开发不感兴趣,请忽略 回到顶部 前言 前面我们花了接近3个章节学习指针,应该都感受到指针的强大了吧.指针可以根据地址直接操作内存中的数据,使用得当的话,不仅能使代码量变少,还能优化内存管理.提升程序性能.关于指针的内容还非常多,比如指针数组.指向数组的指针.指向指针的指针,呵呵,看到这些名字是否

【C语言】14-返回指针的函数与指向函数的指针

前言 前面我们花了接近3个章节学习指针,应该都感受到指针的强大了吧.指针可以根据地址直接操作内存中的数据,使用得当的话,不仅能使代码量变少,还能优化内存管理.提升程序性能.关于指针的内容还非常多,比如指针数组.指向数组的指针.指向指针的指针,呵呵,看到这些名字是否都觉得头大了,不过我就暂时不在博客中讲解这些内容了,我只讲述在iOS开发中指针的最常见用法,比如这一章的内容----返回指针的函数 与 指向函数的指针 回到顶部 一.返回指针的函数 指针也是C语言中的一种数据类型,因此一个函数的返回值肯