Почему длина массива изменяется, когда массив, содержащий указатель, является параметром метода? - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть класс Node, и когда я создал массив указателей Node (Node *) и передал его через метод, у меня была другая длина массива в качестве параметра.

Node* hands[4];
Deal(deck,hands,4,"one-at-a-time",13);

void Deal(Node* &deck, Node* hands[], int people, std::string type, int count){
    Node*& temp = deck;
    for (int i = 0; i < count; ++i) {
        for (int j = 0; j < people; ++j) {
            append(hands[j], CopyDeck(temp));
            temp = temp->after;
        }
    }
}

Когда я использую отладчик Clion, чтобы увидеть значение переменных, я обнаружил, что создаваемые руки имеют значения

hands[0] = 0x746365667265700e
hands[1] = NULL
hands[2] = NULL
hands[3] = 0x00007fc44b402430

И когда он передается через метод, в методе руки получают

*hands=0x746365667265700e
hands[1]=NULL
hands[2]=NULL
hands[3]=0x00007fc44b402430
hands[4]=0x00007fc44b402570

Что означает "* руки"? И почему начальное значение в руках не NULL? На самом деле минимальный пример, который я могу иметь, выглядит примерно так:

class Node{};

void test(Node* list[]){}

int main(int argc, char* argv[]){
    Node * temp[4];
    test(temp);
}

Но это работает. И я уже написал тот же код в других файлах и работает так, как я думал.

Колода - просто двусвязный список Node. Узел имеет атрибут «после», указывающий на следующий узел. Мой отладчик сказал мне до того, как

Node* &temp = deck;

параметр "руки" уже становится массивом из 5 элементов. Я думаю, что нашел возможную причину, но я не могу понять отношения между ними. В моей основной функции есть два метода тестирования. Первый называется «SortingTest», а второй - «DealingTest». Когда я комментирую первый тестовый метод, мой DealingTest работает правильно, но после того, как я раскомментирую его, DealingTest не работает. После завершения SortingTest в основном методе не остается атрибута или чего-либо еще. Кто-нибудь может мне это объяснить? Спасибо вам всем. Или, может быть, мой метод очистки неверен, поэтому он не освобождает память правильно?

void DeleteAllCards(Node* root){
    Node *current, *next;
    current = root;
    while (current != nullptr){
        next = current->after;
        delete current;
        current = next;
    }
}

1 Ответ

0 голосов
/ 27 февраля 2020

Созданный вами массив представляет собой массив C -Style, представляющий собой массив фиксированного размера с 4 элементами. В вашем случае тип элемента - указатель узла.

C - Массивы не инициализируются значениями по умолчанию, в отличие от многих других популярных языков. Поэтому значения указателя, которые вы видите в руках, являются либо указателем на Node *, либо производным типом, либо адресом мусорной памяти с некоторыми исключениями из этого правила (см. Ниже крайние случаи, определенные Стандартом. Для тех, которые говорят NULL, их адрес памяти находится в ox0000 ...

Обновление правки Чтобы отразить комментарий, сделанный @AlgirdasPreidZius - для C и C ++ существует стандартное правило, где стандарт C -Массив должен заполняться значениями по умолчанию при инициализации. Стандартный раздел C ++ 6.8.3.2.2 ([basi c .start.static]): "Если константа инициализации не выполняется, переменная со значением stati c storage длительность или длительность хранения потока инициализируется нулями. "

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

Ваш для l oop, судя по переданным параметрам, представляет собой N ^ 2 временную сложность l oop с 4 * 4 итерациями. C -Array Узел * также был передан по ссылке, поэтому, когда вы назначаете Узлу * & деки, адрес памяти, обозначающий начало массива, меняется на местоположение массива деки. Таким образом, он будет иметь значения, которые содержит колода C -Array of Node *, предполагая, что копия является копией 1: 1, глубокая или мелкая

...