Инициализация нескольких структур в функции cpp

0

Я хочу инициализировать структуры в цикле и обновить массив. Следующий код, который я использую.

#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
  • 5
    Вам действительно не нужно делать все это ручное выделение / удаление памяти в C ++. Ваш код не использует никаких преимуществ языка C + или стандартной библиотеки.
  • 3
    Если вы не используете указатели, ваши проблемы волшебным образом исчезнут.
Показать ещё 4 комментария
Теги:
struct

2 ответа

5
Лучший ответ

Вы сохраняете указатели на локальные переменные в объектах, к которым вы обращаетесь после их удаления.

Даже если Response::records были должным образом отсортированы, эти два фактора сделали бы код недействительным.

Idiomatic C++ будет использовать std::string и std::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";
    }
}
3

Самая большая проблема здесь в том, что это C не C++, однако рассмотрим решение C:

Есть несколько проблем:

struct Response {
    Record *records[];
};

Не забудьте указать измерение для вашего массива:

Record *records[4];

Следующий:

struct Record {
    char *name;
};

Это просто объявляет указатель с именем name, для которого не указывается память. Вам нужно будет выделить память для имени в будущем или сделать ее статическим массивом здесь вместо указателя.

record->name = (char*)x;

Теперь имя указывает на статический массив x. Это будет происходить каждый раз через цикл, поэтому все экземпляры имен record-> будут указывать на один и тот же массив. Вот почему все они печатают одно и то же значение :-) Вам нужно скопировать строку в x в record-> имя, которую вы не можете сделать, потому что нет хранилища, связанного с именем record->.

2 выхода:

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, вы не должны использовать новые и удалять. malloc() и бесплатное() семейство вызовов лучше подходят для стиля C. Главное преимущество new и delete over 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;
}

EDIT: Здесь одно из возможных решений, которые больше 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";
    }

}
  • 0
    record_name должно быть передано по record_name ссылке. Вы должны использовать [const] auto& или вы делаете много копий.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню