Разве мы не можем сделать создание узла без использования указателя на объект в C ++? - PullRequest
0 голосов
/ 05 июня 2019

Я решал эту проблему в Связанном списке по рангу хакера: https://www.hackerrank.com/challenges/insert-a-node-at-the-head-of-a-linked-list/

И получил правильный ответ для данного кода.Большая часть кода была написана заранее;Мне нужно было только выполнить функцию insertNodeAtHead (заключенную между тремя звездами):

#include <bits/stdc++.h>
using namespace std;

class SinglyLinkedListNode {
    public:
        int data;
        SinglyLinkedListNode *next;

        SinglyLinkedListNode(int node_data) {
            this->data = node_data;
            this->next = nullptr;
        }
};

class SinglyLinkedList {
    public:
        SinglyLinkedListNode *head;
        SinglyLinkedListNode *tail;

        SinglyLinkedList() {
            this->head = nullptr;
            this->tail = nullptr;
        }

};

void print_singly_linked_list(SinglyLinkedListNode* node, string sep, ofstream& fout) {
    while (node) {
        fout << node->data;

        node = node->next;

        if (node) {
            fout << sep;
        }
    }
}

void free_singly_linked_list(SinglyLinkedListNode* node) {
    while (node) {
        SinglyLinkedListNode* temp = node;
        node = node->next;

        free(temp);
    }
}

// Complete the insertNodeAtHead function below.

/*
 * For your reference:
 *
 * SinglyLinkedListNode {
 *     int data;
 *     SinglyLinkedListNode* next;
 * };
 *
 */
***SinglyLinkedListNode* insertNodeAtHead(SinglyLinkedListNode* llist, int data) {

  SinglyLinkedListNode *nnode;
  nnode = new SinglyLinkedListNode(data);
  if(llist !=NULL)
    nnode->next=llist;
  return llist=nnode;
}***

int main()
{
    ofstream fout(getenv("OUTPUT_PATH"));

    SinglyLinkedList* llist = new SinglyLinkedList();

    int llist_count;
    cin >> llist_count;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    for (int i = 0; i < llist_count; i++) {
        int llist_item;
        cin >> llist_item;
        cin.ignore(numeric_limits<streamsize>::max(), '\n');

        SinglyLinkedListNode* llist_head = insertNodeAtHead(llist->head, llist_item);
        llist->head = llist_head;
    }

    print_singly_linked_list(llist->head, "\n", fout);
    fout << "\n";

    free_singly_linked_list(llist->head);

    fout.close();

    return 0;
}

Мне нужно было только выполнить функцию insertNodeAtHead ().Остальное все уже было там.Но когда я попытался сделать это без использования указателя nnode object (мой идентификатор) типа класса SinglyLinkedListNode (их предопределенный класс), я получаю ошибку компиляции:

#include <bits/stdc++.h>

using namespace std;

class SinglyLinkedListNode {
  public:
    int data;
  SinglyLinkedListNode * next;

  SinglyLinkedListNode(int node_data) {
    this - > data = node_data;
    this - > next = nullptr;
  }
};

class SinglyLinkedList {
  public:
    SinglyLinkedListNode * head;
    SinglyLinkedListNode * tail;

  SinglyLinkedList() {
    this - > head = nullptr;
    this - > tail = nullptr;
  }

};

void print_singly_linked_list(SinglyLinkedListNode * node, string sep, ofstream & fout) {
  while (node) {
    fout << node - > data;

    node = node - > next;

    if (node) {
      fout << sep;
    }
  }
}

void free_singly_linked_list(SinglyLinkedListNode * node) {
  while (node) {
    SinglyLinkedListNode * temp = node;
    node = node - > next;

    free(temp);
  }
}

// Complete the insertNodeAtHead function below.

/*
 * For your reference:
 *
 * SinglyLinkedListNode {
 *     int data;
 *     SinglyLinkedListNode* next;
 * };
 *
 */
***SinglyLinkedListNode * insertNodeAtHead(SinglyLinkedListNode * llist, int data) {

  SinglyLinkedListNode nnode;
  nnode = new SinglyLinkedListNode(data);
  if (llist != NULL)
    nnode.next = llist;
  return llist = & nnode;
}***

int main() {
  ofstream fout(getenv("OUTPUT_PATH"));

  SinglyLinkedList * llist = new SinglyLinkedList();

  int llist_count;
  cin >> llist_count;
  cin.ignore(numeric_limits < streamsize > ::max(), '\n');

  for (int i = 0; i < llist_count; i++) {
    int llist_item;
    cin >> llist_item;
    cin.ignore(numeric_limits < streamsize > ::max(), '\n');

    SinglyLinkedListNode * llist_head = insertNodeAtHead(llist - > head, llist_item);
    llist - > head = llist_head;
  }

  print_singly_linked_list(llist - > head, "\n", fout);
  fout << "\n";

  free_singly_linked_list(llist - > head);

  fout.close();

  return 0;
}

ОШИБКА ПОСЛЕ КОМПИЛЯЦИИ:

solution.cc: В функции 'SinglyLinkedListNode * insertNodeAtHead (SinglyLinkedListNode *, int)': solution.cc:63:24: ошибка: отсутствует соответствующая функция для вызова метода SinglyLinkedListNode :: SinglyLinkedListNode ()SinglyLinkedListNode nnode;^ ~~~~ solution.cc:10:9: примечание: кандидат: 'SinglyLinkedListNode :: SinglyLinkedListNode (int)' SinglyLinkedListNode (int node_data) {^ ~~~~~~~~~~~~~~~~~~~~~~~~~~ solution.cc:10:9: примечание: кандидат ожидает 1 аргумент, 0 предоставлено solution.cc:5:7: примечание: кандидат: 'constexpr SinglyLinkedListNode :: SinglyLinkedListNode (const SinglyLinkedListNode &)' class SinglyLinkedListNode {^ ~~~~~~~~~~~~~~~~~~~ solution.cc:5:7: примечание: кандидат ожидает 1 аргумент, 0 предоставлено решение.cc:5:7: примечание: кандидат: 'constexpr SinglyLinkedListNode :: SinglyLinkedListNode(SinglyLinkedListNode &&) 'solution.cc:5:7: примечание: кандидат ожидает 1 аргумент, 0 предоставлено solution.cc:64:40: error: неоднозначная перегрузка для оператора' = = (типы операндов: 'SinglyLinkedListNode' и 'SinglyLinkedListNode *') nnode = новый SinglyLinkedListNode (данные);^ решение.cc:5:7: примечание: кандидат: 'SinglyLinkedListNode & SinglyLinkedListNode :: operator = (const SinglyLinkedListNode &)' class SinglyLinkedListNode {^ ~~~~~~~~~~~~~~~~~~~ решение.cc: 5: 7: примечание: преобразование аргумента 1 будет некорректным: solution.cc:64:11: ошибка: недопустимое пользовательское преобразование из 'SinglyLinkedListNode *' в 'const SinglyLinkedListNode &' [-fpermissive] nnode = newSinglyLinkedListNode (данные);^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ solution.cc:10:9: примечание: кандидат - это: 'SinglyLinkedListNode :: SinglyLinkedListNode (int) 'SinglyLinkedListNode (int node_data) {^ ~~~~~~~~~~~~~~~~~~~ solution.cc:10:9: примечание: преобразование аргумента 1 будет некорректным: решение.cc: 64: 11: ошибка: недопустимое преобразование из 'SinglyLinkedListNode *' в 'int' [-fpermissive]
nnode = new SinglyLinkedListNode (data);^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ solution.cc:64:11: ошибка: недопустимое преобразование из 'SinglyLinkedListNode *' в 'int'[-fpermissive] solution.cc:10:34: примечание: инициализировать аргумент 1 из' SinglyLinkedListNode :: SinglyLinkedListNode (int) 'SinglyLinkedListNode (int node_data) {~~~~ ^ ~~~~~~~~ solution.cc: 5: 7: примечание: кандидат: класс 'SinglyLinkedListNode & SinglyLinkedListNode :: operator = (SinglyLinkedListNode &&)' SinglyLinkedListNode {^ ~~~~~~~~~~~~~~~~~~~: note: преобразование аргумента 1 будет некорректным: solution.cc:64:11: ошибка: неправильное преобразование, определенное пользователем, из 'SinglyLinkedListNode *' в 'SinglyLinkedListNode &&' [-fpermissive] nnode = new SinglyLinkedListNode (data);^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ solution.cc:10:9: примечание: кандидат - это: 'SinglyLinkedListNode :: SinglyLinkedListNode (int) 'SinglyLinkedListNode (int node_data) {^ ~~~~~~~~~~~~~~~~~~~ solution.cc:10:9: примечание: преобразование аргумента 1 будет некорректным: решение.cc: 64: 11: ошибка: недопустимое преобразование из 'SinglyLinkedListNode *' в 'int' [-fpermissive]
nnode = new SinglyLinkedListNode (data);^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ solution.cc:64:11: ошибка: недопустимое преобразование дляот «SinglyLinkedListNode *» до «int» [-fpermissive] solution.cc:10:34: note: инициализация аргумента 1 из «SinglyLinkedListNode :: SinglyLinkedListNode (интермедиат)» SinglyLinkedListNode (int node_data) { ~~~~ ^ ~~~~~~~~ solution.cc:64:40: ошибка: преобразование в неконстантный ссылочный тип ‘класс SinglyLinkedListNode &&’ из rvalue типа «SinglyLinkedListNode» [-fpermissive] nnode = новый SinglyLinkedListNode (данные);

Статус выхода 255

Я твердо верил, что это должно было сработать, но этого не произошло. Поскольку логика была одинаковой, единственное отличие заключалось в том, что я не использовал указатель для создания объекта. Поскольку я новичок в C ++, я не могу понять, почему это происходит. Пожалуйста, дайте понимание.

Ответы [ 3 ]

2 голосов
/ 05 июня 2019

Можем ли мы создать узел без указателя ...

Технически да, но практически нет.Не в этом случае.

SinglyLinkedListNode nnode;

завершается сбоем, потому что не существует конструктора для SinglyLinkedListNode, который не принимает параметров.

SinglyLinkedListNode nnode(data);

или

SinglyLinkedListNode nnode{data};

call SinglyLinkedListNode(int node_data) и создайте SinglyLinkedListNode, но эта SinglyLinkedListNode является локальной переменной автоматической области действия.Он будет уничтожен, как только вернется insertNodeAtHead.Это бесполезно для вас.Вы бы получили то, что называется висящим указателем, указателем на мертвый объект.Доступ к этому мертвому объекту - неопределенное поведение.Это часто смертельно, но, верьте или нет, хуже, когда не смертельно.Вы не знаете, что произойдет.Часто программа выглядит так, как будто она работает.И вдруг это не так.

Вам нужно динамическое выделение, а самый простой способ удержать динамическое выделение - с помощью указателя.

Примечание:

return llist = nnode;

также может быть

return nnode;

, назначение здесь ничего не делает.Указатель - это адрес объекта.Когда вы передаете указатель в функцию, указанный объект передается по ссылке, но функция получает копию адреса.llist = nnode изменяет копию адреса, а не оригинал.Вызывающая функция не имеет представления о том, что происходит с копией, и продолжает работать с ее исходным значением.

В этом случае вам отчасти повезло, потому что

return llist = nnode;

выполняет бессмысленное назначение изатем возвращает значение llist, значение, которое вы все равно хотели вернуть.

1 голос
/ 05 июня 2019

Для справки, вот фрагмент кода, который вы изменили и который, по вашему мнению, является источником ваших проблем:

Рабочий код

SinglyLinkedListNode *nnode;
nnode = new SinglyLinkedListNode(data);

Сломанный код

SinglyLinkedListNode nnode;
nnode = new SinglyLinkedListNode(data);

Статические и динамические объекты

Разница, как вы сказали, в том, что nnode - это объект указателя Node в рабочей версии, тогда как в вашей версии это объект Node. Проблема заключается в использовании ключевого слова new ( см. Здесь ).

[Ключевое слово new] создает и инициализирует объекты с динамическим сроком хранения, то есть объекты, время жизни которых не ограничено областью, в которой они были созданы.

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

SinglyLinkedListNode nnode(data);

( см. Здесь ) для более подробного объяснения создания (создания экземпляра) объекта класса.

Сообщение об ошибке

 error: no matching function for call to ‘SinglyLinkedListNode::SinglyLinkedListNode()’ SinglyLinkedListNode nnode; ^~~~~ solution.cc:10:9: note: candidate: ‘SinglyLinkedListNode::SinglyLinkedListNode(int)’ SinglyLinkedListNode(int node_data) { ^~~~~~~~~~~~~~~~~~~~ solution.cc:10:9: note: candidate expects 1 argument, 0 provided 

Судя по вашему сообщению об ошибке, похоже, что оно больше связано с вашими конструкторами.

Кажется, не удается найти конструктор по умолчанию для вашего класса SinglyLinkedListNode. Из которых вы пытаетесь вызвать в этой функции. Я предполагаю, что он видит создание экземпляра ListNode без указателя как конструктор по умолчанию для этого класса, где у вас его нет. У этого человека была такая же проблема.

0 голосов
/ 05 июня 2019

SinglyLinkedListNode * nnode;nnode = new SinglyLinkedListNode (data);

new возвращает указатель.Этот указатель содержит адрес объекта, что означает, что он указывает на объект (на общем языке).

SinglyLinkedListNode nnode;nnode = new SinglyLinkedListNode (data);

здесь nnode уже является объектом, и вы пытаетесь назначить ему тип указателя.

class_type и class_type * различаются.Каждый указатель на код любого типа имеет 4 или 8 байтов, зависит от компилятора, так как это адрес.Так что не путайте с указателем на объект и объект.

...