2014-11-03 3 views
1

У меня возникли проблемы с доступом к объектам, которые я создал в массиве указателей. У меня есть тестовый код, который показывает, что объекты создаются, но в моей функции ShowCluster() она висит на первой итерации через петлю второго уровня.Не удается получить доступ к объектам, созданным в массиве указателей

Способ, которым я считаю, что он закодирован, заключается в том, что у меня есть объект Node **, который по существу становится массивом 2d. Поскольку я использую оператор new, мне не нужно беспокоиться о возможности внутри функции.

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

main.cpp

#include <iostream> 
#include "Node.h" 

void Test(std::string message){ 
    static int testNumber = 0; 
    std::cout << "[+] Test: " << testNumber << " : " << message << std::endl; 
    testNumber++; 
} 

void Default2dNodeArray(Node** myCluster, int height, int width, int vecLength){ 
    Test("Start of array creation."); 

    myCluster = new Node*[height]; 

    for(int i=0; i<height; i++){ 
     myCluster[i] = new Node[width]; 
    } 

    Test("End of array creation."); 

} 

void ShowCluster(Node **myCluster, int height, int width){ 
    Test("Start of Display array."); 
    for(int i=0; i<height; i++){ 
     Test("Outer for loop"); 
     for(int j=0; j<width; j++){ 
      Test("Inner for loop"); 
      std::cout << myCluster[i][j].myNodeString << " : " << myCluster[i][j].myNodeInt << std::endl; 
     } 
    } 
    Test("End of Display array."); 

} 


int main(){ 

    int myHeight = 5; 
    int myWidth =8; 
    int myVecLength = 4; 
    Node** myNodeArray; 

    std::cout << "Starting pointer test" << std::endl; 

    Test("In main."); 
    Default2dNodeArray(myNodeArray, myHeight, myWidth, myVecLength); 
    Test("In main."); 
    ShowCluster(myNodeArray, myHeight, myWidth); 
    Test("In main."); 

    std::cout << "Ending pointer test" << std::endl; 

    return 1; 
} 

node.cpp

#include "Node.h" 
#include <stdlib.h> 
#include <stdio.h> 
#include <sstream> 
#include <iostream> 


int Node::globalCounter = 0; 

Node::Node(){ 

    std::cout << "Node created." << std::endl; 

    std::stringstream ss; 
    ss << "Default: " << globalCounter; 

    myNodeString = ss.str();; 
    myNodeInt = globalCounter; 
    myVecLength = new int[3]; 

    globalCounter++; 

} 

Node::Node(std::string myString, int myInt, int vecLength){ 
    myNodeString = "Non-Default:" + myString; 
    myNodeInt = globalCounter; 

    myVecLength = new int[vecLength]; 
    globalCounter++; 
} 

node.h

#ifndef NODE_H_ 
#define NODE_H_ 

#include <string> 

class Node { 

public: 

    static int globalCounter; 
    std::string myNodeString; 
    int myNodeInt; 
    int* myVecLength; 

    Node(); 
    Node(std::string, int, int); 


}; 

#endif /* NODE_H_ */ 
+0

http://markgodwin.blogspot.com/2009/08/c-reference-to-pointer.html – NDEthos

ответ

1

Все, что вы делаете для вашей Node** myCluster переменной в функции Default2dNodeArray, она не будет видимый в вашей основной функции, потому что вы проходите в myCluster по стоимость. Таким образом, myNodeArray в main не будет изменен. Если вы хотите изменить его, либо вернуть новую переменную из функции или изменить функцию подписи

void Default2dNodeArray(Node**& myCluster, int height, int width, int vecLength) 

(обратите внимание на ссылку в первом аргументе). Использование тройного указателя также было бы возможно, но я думаю, что намерение изменять переданную переменную гораздо лучше выражено посредством ссылки, тем более, что вы уже имеете дело с двойным указателем здесь. Кроме того, он оставляет остальную часть кода незатронутой.

+0

Так что, если бы я не использовал оператор «Новый», я мог бы просто передать указатель так, как он есть, а затем изменить элементы объекта, все, сохраняя эти изменения, когда я вышел из функции? – NDEthos

+0

Все ниже уровня 'myCluster' сохраняется, даже если вы только передаете значение. 'myCluster' указывает на первый элемент массива указателей. Каждый указатель в этом массиве указывает на первый элемент массива объектов «Node». Вы можете изменить то, на что указывают указатели в массиве указателей, вы можете изменить то, что объекты «Node» в массивах, на которые они указывают, содержат. Но (без ссылки) вы не можете изменить значение 'myCluster' вне функции (т. Е.' MyNodeArray' в вашем случае). 'myNodeArray' в объеме основных остатков неинициализируется и указывает на мусор. – Oguk

+0

'myNodeArray' должен был бы указывать на что-то действительное (по крайней мере, на массив указателей, т. Е.' Node * '), даже если он не инициализирован, если вы настаиваете на передаче его функции по значению, так как вы не можете изменить то, что он указывает к. Тем не менее, я думаю, что это плохая идея разделить работу по распределению таким образом. Более последовательная идея без использования ссылки заключается не в том, чтобы передать «myNodeArray» из основной функции, а в том, чтобы сделать «Default2dNodeArray' * return * a« Node ** », который указывает на новый (и полностью) выделенный массив. Затем просто инициализируйте 'myNodeArray' с этим возвращаемым значением. – Oguk

0

Вы пытаетесь создать массив указателей на объекты Node и инициализировать каждый из этих указателей объекту Node, выделенному в куче, и передать это как параметр.

Передача указателя на функцию может выполняться по значению (т. Е. Указатель копируется, вы можете получить доступ к памяти, отмеченной разыменованием, но вы не можете изменить исходное значение указателя), взяв его адрес и передать его функции, например

Node *ptr = 0x10; 
function(&ptr);  

void function(Node** ptr_to_ptr) { 
    (*ptr_to_ptr) = 0x20; // This will modify ptr 
} 

или по ссылке (что будет также изменить первоначальное значение указателя)

Node *ptr = 0x10; 
function(ptr);  

void function(Node*& ref_to_ptr) { 
    ref_to_ptr = 0x20; // This will modify ptr 
} 

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

void Default2dNodeArray(Node*** myCluster, int height, int width, int vecLength) { 
    Test("Start of array creation."); 

    // Dereference to access the original double pointer value 
    *myCluster = new Node*[height]; 

    for (int i = 0; i<height; i++){ 
     (*myCluster)[i] = new Node[width]; 
    } 
    Test("End of array creation."); 
} 

void ShowCluster(Node*** myCluster, int height, int width) { 
    Test("Start of Display array."); 
    for (int i = 0; i<height; i++){ 
     Test("Outer for loop"); 
     for (int j = 0; j<width; j++){ 
      Test("Inner for loop"); 
      std::cout << (*myCluster)[i][j].myNodeString << std::endl; 
     } 
    } 
    Test("End of Display array."); 
} 

int main(){ 
    int myHeight = 5; 
    int myWidth = 8; 
    int myVecLength = 4; 
    Node** myNodeArray; // Double pointer 

    std::cout << "Starting pointer test" << std::endl; 

    Test("In main."); 
    Default2dNodeArray(&myNodeArray, myHeight, myWidth, myVecLength); 
    Test("In main."); 
    ShowCluster(&myNodeArray, myHeight, myWidth); 
    Test("In main."); 

    std::cout << "Ending pointer test" << std::endl; 
    return 1; 
} 

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

Если вы поняли, в приведенном выше примере, это будет намного легче получить, что вы могли бы также сделать это со ссылкой на двойной указатель:

void Default2dNodeArray(Node**& myCluster, int height, int width, int vecLength) 
// etc.. 

Один последний кусок совет: хотя это просто тест, не забудьте освободить всю выделенную память, иначе вы закончите утечку!

Смежные вопросы