Двойной указатель: указатель на член структуры, который является указателем

Я пытаюсь написать программу для воспроизведения "Pangolin" (как этот парень - он задает вопросы "да / нет", идет по двоичному дереву, пока не доберется до листового узла. Затем он "угадывает", и если пользователь говорит ответ был неверным, спрашивает пользователя, о чем он думает, и отвечает на вопрос, который отличает это от неправильных подсказок. Затем он добавляет новые данные в дерево).

Это моя структура для узла дерева. 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 указатель, который указывает на члена "узла" "да" (или нет). Этот член в свою очередь является указателем. Когда в addData я назначаю "*replace", это должно изменить структуру, перенаправив указатель на член "yes" (или no), чтобы он указывал на новый узел вопроса, который я создал.

Я отладил и обнаружил, что newQuestionNode и newObjectNode созданы успешно. Дочерние элементы newQuestionNode назначены правильно. Однако новый узел вопроса не вставляется в дерево. Строка "*replace = newQuestionNodePtr" не имеет ожидаемого эффекта, а узел, на который ссылается "узел" в области видимости "ask", не перенаправляет свой дочерний указатель.

Кто-нибудь может увидеть, что не так в моем понимании? Или, может быть, я не выразил это прямо в своем коде? Извините, этот вопрос так долго.

2 ответа

Вы не должны объявлять указатель, который вы передаете функции, как двойной указатель. Вместо этого передайте адрес одного указателя на функцию:

TreeNode* answerP2p;
answerP2p = userSaysYes() ? node.yes : node.no;

addData(&answerP2p, answerNode.nodeString.objectName);

К сожалению, я не совсем понимаю ответ Йоахима Пилеборга выше, но в конце концов я подозревал свою проблему и думаю, что это довольно распространенная ошибка для новых путешественников C [1], поэтому я опубликую ее здесь на своих собственных условиях.

В моем поспешном переходе от Java к C I я сказал себе: "Хорошо, структуры - это просто объекты без методов". Оценка обоснованности этого упрощения оставлена ​​читателю в качестве упражнения. Я также расширил это предположение до "когда аргумент имеет структурный тип, он автоматически передается по ссылке". Это очевидно ложно, но я даже не думал об этом. Глупый.

Так что настоящая проблема здесь в том, что я проходил мимо ask() переменная типа TreeNode для его node аргумент. Вся эта структура передавалась по значению (конечно). Когда я прошел answerP2p в addData(), это на самом деле работает правильно, но это было изменение ask()локальная копия TreeNode, Я изменился ask() взять TreeNode* и вот, там было дерево.

  1. C чем я там занимался [1]?
Другие вопросы по тегам