在cpp函数中初始化多个结构

时间:2015-02-13 15:37:07

标签: c++ struct

我想在循环中初始化结构并更新到数组。我正在使用以下代码。

#include <iostream>

struct Record {
    char *name;
};

struct Response {
    Record *records[];
};


int main()
{
    Response *response = new Response;

    for(int i=0; i<4; i++) {

        Record *record= new Record();

        char x[20];sprintf(x, "%d", i);

        record->name = (char*)x;

        response->records[i] = record;

        std::cout << "Inserting: " <<  x << "\n";

        //Not sure if I have to delete.
        delete record;
    }

    for(int i=0; i<4; i++) {
        std::cout << "Fetching: " << response->records[i]->name << "\n";
    }
}

奇怪的是,打印数组中的所有项目都打印相同的值。关于什么可能出错的任何想法,评论或想法?

示例输出:

Inserting: 0
Inserting: 1
Inserting: 2
Inserting: 3
Fetching: 3
Fetching: 3
Fetching:
Fetching: 3

2 个答案:

答案 0 :(得分:5)

您将指向删除它们后访问的对象中的局部变量的指针存储起来。

即使Response::records的大小合适,这两个因素也会导致代码无效。

惯用C ++会使用std::stringstd::vector<Record>,但如果你真的想要C风格的字符串和数组,这应该可行:

struct Record {
    char name[20];
};

struct Response {
    Record records[4];
};

int main()
{
   Response response;

    for(int i = 0; i < 4; i++) {
       Record record;
       sprintf(record.name, "%d", i);
       response.records[i] = record;
       std::cout << "Inserting: " <<  record.name << "\n";
    }

    for(int i = 0; i < 4; i++) {
       std::cout << "Fetching: " << response.records[i].name << "\n";
    }
}

答案 1 :(得分:3)

这里最大的问题是C不是C ++,但是,让我们考虑一个C解决方案:

有一些问题:

struct Response {
    Record *records[];
};

别忘了为你的阵列提供尺寸:

Record *records[4];

下一步:

struct Record {
    char *name;
};

这只是声明一个名为name的指针,没有为name指定的内存。您将来需要为name分配内存,或者在此处将其设置为静态数组而不是指针。

record->name = (char*)x;

现在name指向静态数组x。每次循环都会发生这种情况,因此所有记录 - &gt;名称实例都将指向同一个数组。这就是他们为什么都打印相同价值的原因:-) 您需要将x中的字符串复制到record-&gt; name,这是您无法做到的,因为没有与record-&gt; name关联的存储空间。

两种出路是:

struct Record {
    char name[20]; // static array
};
...
char x[20] = {0}; // initialise so we're sure of a terminating null
strcpy(record->name, x);

或者

struct Record {
    char *name;
};
...
record->name = new char[20];
strcpy(record->name, x);

最后,

//Not sure if I have to delete.
delete record;

不,你不能在这里删除,因为这些记录将在之后使用。如果你必须删除,设置类似你的初始化循环,但在main()结束之前,只有这一次你将被破坏。 当然,严格地说,因为这是C,你不应该使用new和delete。 malloc()和free()系列调用更适合C风格。 new和delete相对于malloc()和free()的主要优点是在适当的时候调用已分配对象的构造函数和析构函数,但是您还没有使用这些函数中的任何一个。

这在C ++中会更容易,更简单,更安全。你必须用C语言做,还是考虑C ++?

#include <iostream>
#include <cstring>

struct Record {
    char *name;
};

struct Response {
    Record *records[4];
};


int main()
{
    Response *response = new Response;

    for(int i=0; i<4; i++) {

        Record *record= new Record();

        char x[20];sprintf(x, "%d", i);

        record->name = new char[20];
        strcpy(record->name, x);

        response->records[i] = record;

        std::cout << "Inserting: " <<  x << "\n";

        //Not sure if I have to delete.
        //delete record;
    }

    for(int i=0; i<4; i++) {
        std::cout << "Fetching: " << response->records[i]->name << "\n";
    }


    // the program is about to exit and the resources will be freed by the system, so this is not strictly necessary
    for(int i=0; i<4; i++) {
        delete [] response->records[i]->name;
        delete response->records[i];
    }

    delete response;
}

编辑:这是一个可能的解决方案,它更加C ++友好,没有原始指针,所有内存分配都由字符串和向量中的标准库处理。

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Record {
    Record(string record_name) : name (record_name) {}
    string name;
};

struct Response { 
    vector<Record> records;
};

int main()
{
    Response response;
    for(int i=0; i<4; i++) {
        response.records.push_back(Record(to_string(i)));
        std::cout << "Inserting: " << i << "\n";
    }

    for (auto r : response.records) {
        cout << "Fetching: " << r.name << "\n";
    }

}