【问题标题】:Array of pointers to structs指向结构的指针数组
【发布时间】:2016-06-20 07:28:09
【问题描述】:

编辑:我对 c++ 和整个编程很陌生。

我应该制作一个使用结构和结构数组的程序。

安全理事会安全理事会成员

我的任务是使用“UML 聚合”的概念来创建一个我使用结构和结构数组的程序。 (希望你能明白我的意思)

由于安理会成员是安理会的一部分,而不是相反,因此安理会的结构必须有一个成员数组。(请耐心等待)

//example
struct Member_sc{
    char * name;
    int age;
};
struct Security_council{
    Member_sc members[10];    
};

现在,我已经创建了这个程序并且一切正常(根据我的老师),但现在她告诉我创建一个精确的副本,但我必须使用指向 Member_sc 的指针数组而不是“成员”数组结构。由于我还没有完全弄清楚指针是如何工作的,所以我遇到了一些问题。

如果需要,我可以将代码发布到原始程序,但它包含 4 个文件(主文件、头文件和一些函数文件),尝试在这里发布会很痛苦。

这是原型(目前全部在一个文件中)

#include <iostream>
using namespace std;

struct member_sc{
    string name;
};

struct security_council{
    member_sc *point;
    security_council **search; // ignore this for now
    int n;
    security_council():n(0){}
};

void in_mem( member_sc &x){
    getline(cin,x.name);
}
void out_mem(member_sc &x){
    cout<<x.name<<endl;
}
void in_SC(security_council &q, member_sc &x){ 
    int num; //number of members
    cin>>num;
    for(int i=0; i<num; ++i){
        in_mem(x);
        q.point[q.n]=x;
        q.n++;
        }
}
void out_SC(security_council &q,member_sc &x){
    for(int i=0; i<q.n; ++i){
        out_mem(q.point[i]);
    }
}
int main(){

    member_sc y;
    security_council x;
    in_mem(y);              // works
    out_mem(y);             // works
    in_SC(x,y);             // crashes after i input the number of members i want
    out_SC(x,y);            // 

    system("pause");
    return 0;
}

在您输入您希望加入安全理事会的成员数量后,程序会崩溃。 我的思维方式对吗?还是应该使用动态内存分配?

除此之外(我的老师给了我一个额外的任务)使用指针创建一个搜索功能。我认为指向指针的指针可能对此有好处,但我不确定。

任何帮助或建议将不胜感激。 (我想一旦我弄清楚指向结构的指针是如何工作的,我就会弄清楚搜索的东西)

【问题讨论】:

  • 你知道vector吗?
  • 你永远不会初始化 point 成员引用的内存,但是在声明 q.point[q.n]=x; 中你尝试使用它。
  • @deviantfan 抱歉,没有
  • 基本上,在您读入成员数量之后,在您读入各个成员的for 循环之前,您需要分配一个适当的数组member_sc 对象的数量并将其存储在 q.point 中。使用完后不要忘记释放此内存。
  • 一旦你这样做了,你还可以从in_SCout_SC 中删除member_sc &amp;x 参数,因为这将变得不必要。此外,您的输入的一些验证似乎已经到位。考虑一下如果用户输入一个负数会发生什么,并且您尝试直接使用它来确定要分配的内存大小。

标签: c++ arrays pointers struct aggregation


【解决方案1】:

您的问题的第一部分是这样的:

cin >> num;

这仅读取已输入的数字并在换行处停止。然后,在in_mem 中,对getline 的调用会立即读取一个换行符。你需要做的:

cin >> num;
cin.ignore();

这将耗尽任何剩余输入的输入流,或者可以这么说。

但是您的核心问题是您没有为“point”分配任何内存来指向。

指针只是一个变量,它保存的值恰好是内存中事物的地址(从 0 偏移)。如果你要去机场,在便利贴上写“Gate 23”,便利贴就是一个指针,“Gate 23”就是值。

在您的代码中,该变量未初始化,如果幸运的话,该变量将为 0,或者如果您不那么幸运,则为内存中的某个随机地址。

以机场为例:您到达机场后,发现您的便利贴上写着“披萨”。没有帮助。

你的老师实际上已经指定了一个“指针数组”。分解:指向什么的指针? member_sc,那是member_sc*。现在把它变成一个数组

member_sc* pointers[10];

注意:这不好,现代 C++ - 在现代 C++ 中,您可能会使用称为智能指针 (std::unique_ptr) 的东西。

std::unique_ptr<member_sc[]> pointers(new member_sc[10]);

现在你有 10 个指针而不是只有一个,而且它们都需要一些分配来指向。最简单的方法是使用 new 关键字和复制构造函数:

for (int i = 0; i < num; i++) {
    in_mem(x);
    pointers[q.n] = new member_sc(x);  // make a clone of x
    q.n++;
}

或者在现代 C++ 中

for (int i = 0; i < num; i++) {
    in_mem(x);  // x is temporary for reading in
    pointers[q.n] = std::make_unique<member_sc>(x);
    q.n++;
}

但是,这种方法有一个限制:您最多只能有 10 个安全理事会成员。你如何解决这个问题?好吧,现代 C++ 的答案是使用 std::vector

std::vector<member_sc> members;
// ditch n - vector tracks it for you.

// ...

for (int i = 0; i < num; ++i) {
    in_mem(x);
    q.members.push_back(x);
    // q.n is replaced with q.members.size()
    // which is tracked automatically for you
}

但我猜你的老师希望你在用现代奢侈品忘记它们之前真正理解指针。

我们需要重新使用上面刚刚使用的指针,并将“指针”更改为指针数组。

这意味着我们需要一个指向一组指针成员sc的指针。

member_sc** pointers;

我们需要为此分配一些内存来指向:

cin >> num;
cin.ignore();
if (num == 0) {
    // do something
    return;
}
pointers = new member_sc[num];

幸运的是,使用指向数组的指针与使用数组一样简单,唯一的主要区别是您丢失了数组的大小信息——您所拥有的只是地址,而不是维度。

for (int i = 0; i < num; i++) {
    in_mem(x);
    q.pointers[i] = new member_sc(x);
    q.n++;
}

我故意没有为您提供完整的工作示例,因为这显然是针对课程的。

【讨论】:

  • 让我补充一点:指针很容易,但学习指针很难。不要害怕与您的老师谈论您对指针的任何困惑,他们绝对会理解。
  • 我会去看看我能做些什么。非常感谢:D
  • 恕我直言 member_sc** pointers = new member_sc[num]; 不正确。您创建一个 nummember_sc 结构的数组,并尝试将其分配给一个指向member_sc 结构的指针数组。
  • @kfsone 当我尝试释放内存时,由于某种原因它不起作用。我在 main.cpp 中的代码末尾使用delete[] q.pointers,但是当我使用sizeof() 检查时,大小保持不变,即使在解除分配后它仍会输出数据...
  • 使用动态分配,您会丢失自动大小信息,sizeof() 只会告诉您指针的大小。 delete[] 所做的只是将内存返回给系统以供后续重用,它不会将其归零。因此,在分配后仍然能够看到数据 - 在一段时间内 - 并不罕见,但您不应该利用这一点。
【解决方案2】:

你从不初始化点成员引用的内存,然后在语句q.point[q.n]=x;中你尝试使用它。

基本上,在您读入成员数量之后,在您读入各个成员的 for 循环之前,您需要分配一个包含适当数量的 member_sc 对象的数组并将其存储在 q.point 中。使用完后不要忘记释放此内存。

完成此操作后,您还可以从 in_SCout_SC 中删除 member_sc &amp;x 参数,因为这将变得不必要。

最后,您的输入的一些验证似乎已经到位。考虑一下如果用户输入一个负数会发生什么,而您尝试直接使用它来确定要分配的内存大小。


下面是一个简单的例子,展示了如何使用动态分配的结构数组:

#include <iostream>
#include <string>

struct member_sc {
    std::string name;
};

void test_array(int count)
{
    if (count <= 0) {
        return; // Error
    }

    // Allocate an array of appropriate size
    member_sc* members = new member_sc[count];
    if (members == nullptr) {
        return; // Error
    }

    // ... fill in the individual array elements
    for(int i(0); i < count; ++i) {
        // ... read from input stream
        // I'll just generate some names to keep it simple
        members[i].name = "User A";
        members[i].name[5] += i; // Change the last character, so we have different names
    }

    // Now let's try printing out the members...
    for(int i(0); i < count; ++i) {
        std::cout << i << ": " << members[i].name << "\n";
    }

    delete[] members;   

}


int main(int argc, char** argv)
{
    for(int count(1); count <= 10; ++count) {
        std::cout << "Test count=" << count << "\n";
        test_array(count);
        std::cout << "\n";
    }

    return 0;
}

Example on Coliru


当然,这种代码风格还有很多其他问题,但我相信这与这个问题无关。例如:

  • 与其使用裸指针,不如使用某种智能指针更合适。
  • 不要使用简单的数组,而是使用某种集合,例如向量。

【讨论】:

    【解决方案3】:

    因为你被要求使用一个指针数组,所以这样做:替换

    Member_sc members[10];
    

    Member_sc* members[10];
    

    然后使用动态内存分配填充该数组。作为一个好的形式,在程序结束时记得释放你使用的动态内存。

    【讨论】:

    • 我忘了说的是指针数组不能有预定义的大小。
    猜你喜欢
    • 1970-01-01
    • 2017-06-03
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多