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

Initializing multiple structs in cpp function

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

#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

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

即使 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";
    }
}

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

有几个问题:

struct Response {
    Record *records[];
};

不要忘记为数组指定维度:

Record *records[4];

下一个:

struct Record {
    char *name;
};

这只是声明了一个名为name的指针,并没有分配给name指向的内存。以后需要给name分配内存,或者在这里做成静态数组,而不是指针。

record->name = (char*)x;

现在 name 指向一个静态数组 x。每次循环都会发生这种情况,因此所有 record->name 实例都将指向同一个数组。这就是为什么他们都打印相同的值:-) 你需要将x中的字符串复制到record->name,这个你做不到,因为没有record->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";
    }

}