【问题标题】:Cannot access objects created in array of pointers无法访问在指针数组中创建的对象
【发布时间】:2014-11-03 18:20:40
【问题描述】:

我无法访问在指针数组中创建的对象。我有一些测试代码显示正在创建对象,但在我的ShowCluster() 函数中,它通过第二级循环的第一次迭代挂起。

我认为我对其进行编码的方式是我有一个 Node** 对象,它本质上变成了一个二维数组。由于我使用的是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;
}

节点.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++;
}

节点.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_ */

【问题讨论】:

标签: c++ arrays pointers multidimensional-array


【解决方案1】:

无论你对Default2dNodeArray 函数中的Node** myCluster 变量做什么,它在你的主函数中都不会可见,因为你通过值传入myCluster。所以main中的myNodeArray不会被修改。如果要修改它,要么从函数中返回新变量,要么将函数签名更改为

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

(注意第一个参数中的引用)。也可以使用三重指针,但我认为通过引用更好地表达修改传递变量的意图,特别是因为您已经在此处处理双指针。此外,它使其余代码保持不变。

【讨论】:

  • 因此,如果我不使用“New”运算符,我可以直接传递指针,然后更改对象的成员,同时在退出函数时保留这些更改?跨度>
  • myCluster 级别以下的所有内容都会保留,即使您仅按值传递。 myCluster 指向指针数组的第一个元素。该数组中的每个指针都指向Node 对象数组的第一个元素。您可以更改指针数组中的指针指向的内容,您可以更改它们指向的数组中的Node 对象包含的内容。但是(没有参考),您不能在函数之外更改 myCluster 的值(即在您的情况下为 myNodeArray)。 myNodeArray 在 main 范围内未初始化并指向垃圾。
  • myNodeArray 必须指向有效的东西(至少指向一个指针数组,即Node*),即使未初始化,如果您坚持按值将其传递给函数,如你不能改变它指向的东西。但是,我认为以这种方式拆分分配工作是一个坏主意。不使用引用的更一致的想法是不从 main 函数传递 myNodeArray,而是使 Default2dNodeArray return 指向一个新(并且完全)分配的数组的 Node** .然后用那个返回值初始化myNodeArray
【解决方案2】:

您正在尝试创建一个指向 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;
}

上面的签名看起来比实际要可怕得多。试着找出我一开始贴的小sn-ps,然后继续看这段代码。

如果你理解了上面的例子,你会更容易明白你也可以通过引用双指针来做到这一点:

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

最后一条建议:虽然这只是一个测试,但请记住释放所有分配的内存,否则您最终会泄漏它!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    相关资源
    最近更新 更多