【问题标题】:Double pointer: pointer to struct member that is a pointer双指针:指向结构成员的指针,它是一个指针
【发布时间】:2012-12-06 12:06:57
【问题描述】:

我正在尝试编写一个程序来播放“Pangolin”(例如 this guy - 它会询问是/否问题,沿着二叉树向下走直到它到达叶节点。然后它会“猜测”,如果用户说答案是错误的,询问用户他们在想什么,并提出一个问题来区分错误的猜测。然后它将新数据添加到树中。

这是我的树节点结构。对于包含问题的节点,NodeType 为 QUESTION_NODE,对于包含“对象”的节点,则为 OBJECT_NODE - 这是程序推断用户正在考虑的事情。问题节点具有指向子节点的指针 - 一个表示是,一个表示否。

typedef struct _TreeNode {
  NodeType type;
  union {
    char* question;
    char* objectName;
  } nodeString; 
  //children for yes and no answers: will be invalid when type is OBJECT_NODE
  struct _TreeNode* yes;
  struct _TreeNode* no;
} TreeNode;

由于这是一个学习练习,我尝试使用双指针来完成。这是应该向树中添加问题节点的函数:

void addData(TreeNode** replace, char* wrongGuess) {
  //create a new object node for what the user was thinking of
  // ... (code to get user input and build the new object node struct) ... //

  //create a new question node so we don't suck at pangolin so much
  // ... (code to get a question from the user and put it in a question node struct) ... //

  //link the question node up to its yes and no
  printf("What is the answer for %s?\n", newObjectName);
  if (userSaysYes()) {
    newQuestionNodePtr->yes = newObjectNodePtr;
    newQuestionNodePtr->no = *replace;
  }
  else {
    newQuestionNodePtr->no = newObjectNodePtr;
    newQuestionNodePtr->yes = *replace;
  }

  //redirect the arc that brought us to lose to the new question
  *replace = newQuestionNodePtr;
}

然后调用 addData 函数因此

void ask(node) {
  //(... ask the question contained by "node" ...)//

  //get a pointer to the pointer that points to the yes/no member pointer
  TreeNode** answerP2p;
  answerP2p = userSaysYes() ? &(node.yes) : &(node.no);

     //(... the user reports that the answer we guessed was wrong ...)//

      puts("I am defeated!");
      //if wrong, pass the pointer to pointer
      addData(answerP2p, answerNode.nodeString.objectName);

我的(可能是错误的)理解是这样的:

在“ask()”中,我向 addData 传递了一个指针,该指针指向“node”的成员“yes”(或 no)。该成员又是一个指针。当在 addData 中分配给“*replace”时,这应该修改结构,将其“是”(或否)成员指针重定向到指向我创建的新问题节点。

我调试了一下,发现newQuestionNode和newObjectNode创建成功。 newQuestionNode 的子节点已正确分配。但是,新的问题节点不会插入到树中。 “*replace = newQuestionNodePtr”行没有我期望的效果,并且“询问”范围内的“节点”引用的节点没有重定向其子指针。

谁能看出我的理解有什么问题?或者也许是我没有在我的代码中正确表达它的一种方式?抱歉这个问题太长了。

【问题讨论】:

    标签: c pointers struct double-pointer


    【解决方案1】:

    您不应将传递给函数的指针声明为双指针。而是将单个指针的地址传递给函数:

    TreeNode* answerP2p;
    answerP2p = userSaysYes() ? node.yes : node.no;
    
    addData(&answerP2p, answerNode.nodeString.objectName);
    

    【讨论】:

    • 嗯……据我所知,“T** a; a = &(b); f(a);”相当于“T* a; a = b; f(&a);”至于 f() 收到什么?我已经尝试过您的建议,但行为完全相同。
    • @user1582407 不,它们不一样。第一种情况(T** a = &b; f(a);)是指针bf更新,第二种情况是指针a
    • 对不起,我不明白。在我的示例中,b 是我要更新的值。在这两种情况下,f() 都会收到指向 b 的指针。在第二种情况下,& 运算符的使用被简单地推迟到 f() 调用。你能看到我错过了什么吗?
    • @user1582407 地址操作符&返回它所使用的变量的地址,所以在第二种情况下,你使用f(&a),它会将a的地址传递给函数f,当f 改变参数时,a 改变了。因此,在第二种情况下,您先调用f,然后再调用a == b,但在调用a != b 之后。
    • 再次,我真的很抱歉,但我还是不明白。在我的问题中,我将指针 (answerP2p) 传递给指向 addData 的指针 (node.yes)。在addData 中,当我分配给*replace(其中answerP2p 作为replace 参数传递)时,为什么不更新node.yes?我尝试通过&node.yes,并得到了相同的行为 - 据我了解,这是预期的,因为answerP2p == &node.yes(我已经验证了这一点!)。
    【解决方案2】:

    不幸的是,我不太理解上面 Joachim Pileborg 的回答,但我最终解决了我的问题,我想这对于新的 C-farers[1] 来说是一个相当常见的错误,所以我会在这里发布我自己的条款。

    在我从 Java 到 C 的仓促过渡中,我告诉自己“好的,structs 只是没有方法的 objects”。评估这种简化的有效性留给读者作为练习。我还将这个假设扩展到“当参数是结构类型时,它会自动通过引用传递”。这显然是错误的,但我什至没有考虑过。愚蠢的。

    所以这里真正的问题是我传递了ask() 一个TreeNode 类型的变量作为它的node 参数。整个结构是按值传递的(当然)。当我将answerP2p 传递给addData() 时,它实际上工作正常,但它正在修改ask()TreeNode 的本地副本。我将ask() 更改为TreeNode*,瞧,有一棵树。

    1. C 我在那里做了什么[1]?

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 1970-01-01
      • 2019-01-18
      • 1970-01-01
      • 2020-11-15
      • 2015-01-24
      • 1970-01-01
      • 2011-05-17
      相关资源
      最近更新 更多