为什么在这个prog中使用指针指针?

时间:2009-12-16 09:21:11

标签: c tree pointers

以下程序显示了如何在C程序中构建二叉树。它使用动态内存分配,指针和递归。二叉树是一种非常有用的数据结构,因为它允许在排序列表中进行有效的插入,搜索和删除。因为这样一个树本质上是一个递归定义的结构,递归编程是处理它的自然而有效的方法。

tree
   empty
   node left-branch right-branch

left-branch
   tree

right-branch
   tree

以下是代码:

#include <stdlib.h>
#include <stdio.h>

struct tree_el {
   int val;
   struct tree_el * right, * left;
};

typedef struct tree_el node;

void insert(node ** tree, node * item) {
   if(!(*tree)) {
      *tree = item;
      return;
   }
   if(item->val<(*tree)->val)
      insert(&(*tree)->left, item);
   else if(item->val>(*tree)->val)
      insert(&(*tree)->right, item);
}

void printout(node * tree) {
   if(tree->left) printout(tree->left);
   printf("%d\n",tree->val);
   if(tree->right) printout(tree->right);
}

void main() {
   node * curr, * root;
   int i;

   root = NULL;

   for(i=1;i<=10;i++) {
      curr = (node *)malloc(sizeof(node));
      curr->left = curr->right = NULL;
      curr->val = rand();
      insert(&root, curr);
   }

   printout(root);
}

为什么使用指针指针?

4 个答案:

答案 0 :(得分:6)

因为insert方法需要修改树的根。

答案 1 :(得分:2)

白板吧。或者修改示例代码来执行此操作:

for(i=1;i<=10;i++) {
  curr = (node *)malloc(sizeof(node));
  curr->left = curr->right = NULL;
  curr->val = rand();
  printf("before: %d\n", root);
  insert(&root, curr);
  printf("after: %d\n", root);
}

// printout(root);

打印结果如下所示:
之前:0
后:3871888
之前:3871888
后:3871888
之前:3871888
之后:3871888

为什么会这样?

因为它改变了传递给它的指针。

插入是如何工作的:插入遍历树。首先,它访问当前节点。然后左边的节点(通过递归)。然后右边的节点(通过递归)。如果它是一个空的节点(NULL),它将用该项替换该节点。

为此,它取消引用外部指针,并将指针“item”的值赋给该内部指针。

在一般情况下,指针就像int或char。您按值传递指针。如果你取消引用它,你可以修改它指向的任何内容,但不能修改指针本身。如果传递指向指针的指针,则可以更改内部指针,但外部指针不能。

这里有一些可以咀嚼的指针示例代码:

#include <cstdio>
#include <cstdlib>

void some_func(int* value)
{
  *value = 12;
}

int main(int argc, char* argv[])
{
  int a = 5;
  printf("%d\n", a); // prints 5
  some_func(&a);
  printf("%d\n", a); // prints 12

  int b = 7;
  int* c = &b;
  printf("%d\n", b); // prints 7
  printf("%d\n", c); // prints 2029440 (some random memory address)
  some_func(c);
  printf("%d\n", b); // prints 12
  printf("%d\n", c); // prints 2029440 (the same value as before)
}

#include <cstdio>
#include <cstdlib>

void some_other_func(int** other_value)
{
  *other_value = NULL;
}

int main(int argc, char* argv[])
{
  int b = 7;
  int* c = &b;

  printf("%d\n", c); // prints 4718288 (some random memory address)
  some_other_func(&c);
  printf("%d\n", c); // prints 0
}

最后但并非最不重要:

#include <cstdio>
#include <cstdlib>

void some_third_func(int* third_value)
{
  *third_value = 12;
  int** lets_modify_third_value = &third_value;
  *lets_modify_third_value = NULL;
}

int main(int argc, char* argv[])
{
  int b = 7;
  int* c = &b;

  printf("%d\n", b); // prints 7
  printf("%d\n", c); // prints 1637380 (some random memory address)
  some_third_func(c);
  printf("%d\n", b); // prints 12
  printf("%d\n", c); // prints 1637380 (same as before.  Note that the pointer was passed by value, so "third_value" was just a COPY of the address)
}

答案 2 :(得分:0)

更准确的答案是: 因为函数需要替换给定字段(指针)的内容

答案 3 :(得分:0)

“输入”参数的替代 - 返回值,需要在每个访问级别中额外分配:

typedef node* node_ref;

node_ref insert ( node_ref tree, node_ref item) {  
    if ( !tree )  
        return item;

    if ( item -> val < tree -> val ) 
        tree -> left = insert ( tree -> left, item );
    else  if ( item -> val > tree -> val )
        tree -> right = insert ( tree -> right, item );

    return tree;
}

...
// in the loop 
   root = insert ( root, curr );

该方法(或原始代码)的另一个缺点是无法判断节点是否已插入;如果您添加一个返回值来表示它,如果没有插入,则不必泄漏curr

typedef node* node_ref;

bool insert ( node_ref *tree, node_ref item) {  
    if ( !*tree )  {
        *tree = item;
        return true;
    }

    if ( item -> val < ( *tree ) -> val ) 
        return insert ( & ( *tree ) -> left, item );

    if ( item -> val > ( *tree ) -> val )
        return insert ( & ( *tree ) -> right, item);

    return false;
}

...
// in the loop 
for ( int i = 1; i <= 10; ++i ) {
    node_ref curr = malloc ( sizeof ( node ) );

    curr -> left = curr -> right = NULL;
    curr -> val  = rand();

    if ( ! insert ( &root, curr ) )
        free ( curr );
}