Добавление структуры по ссылке на массив в C

#c #arrays #function #pass-by-reference

Вопрос:

Как я могу реализовать функцию в C , которая добавляет экземпляр структуры в массив по ссылке? Таким образом, после добавления структуры, хранящейся в переменной, в массив, эта переменная может быть использована в дальнейшем для изменения экземпляра массива.

псевдокод:

 struct St{
 int x
}

St* arr;
St a = {0};
append a to arr;
a.x = 1;
//expecting arr[0].x = 1

 

Вот код C с примером фильма (см. Комментарии, описывающие проблему):

 
struct Film{
    int id;
    char* name;
};

void add_film(Film *amp;films, int amp;size, Film amp;film){
    if (size == 0)
        films = new Film[1];
    else
    {
        Film *tmp = new Film[size   1];
        for (int i = 0; i < size;   i)
        {
            tmp[i] = films[i];
        }
        delete[]films;
        films = tmp;
    }
    films[size] = film;
    film = films[size]; //how to reassign passed film object to a new object in array?
    size  ;
}

int main(){
    Film *films = nullptr;
    int size = 0;
    Film film = {1, "Name1"};
    add_film(films, size, film);
    film.name = "Name2";
    std::cout << films[0].name;  //output: "Name1", expected: "Name2"
}
 

Комментарии:

1. Прежде всего, не используйте new / delete не используйте вместо этого стандартные классы, например std::vector , в вашем случае. Во-вторых, почему бы не сделать наоборот? Т. е. сначала добавьте/выделите объект в список, а затем получите его ссылку?

2. Это невозможно для данных типов. Что-то, что могло бы приблизиться, — это использовать массив указателей на фильм (или лучше std::unique_ptr<Film> ), которые позволили бы вам возвращать ссылку на новый Film объект, который остается неизменным, даже если массив растет. Я настоятельно рекомендую создать class / struct управлять данными фильма, хотя это был бы обычный способ освобождения памяти; обратите внимание, что массив, выделенный последним, никогда не освобождается вашим кодом, что плохо, если вы когда-либо планируете использовать несколько списков фильмов в одной программе (утечка памяти ключевых слов).

3. @fabian Его можно использовать std::reference_wrapper , но обычно в этом нет необходимости.

Ответ №1:

Добавление структуры по ссылке на массив в C

С этим связаны две проблемы:

  1. В C не может быть массивов ссылок.
  2. Нет никакого способа добавить в массив. Размер массива является константой. Нет никакого способа добавлять или удалять элементы.

Проблема с вашим попытанным решением заключается в том, что у вас есть массив фильмов, а не массив ссылок. Это не очень удивительно, поскольку проблема 1, описанная выше, гласит, что массивов ссылок не существует. Однако решение простое: используйте указатели вместо ссылок. Технически вы могли бы вместо этого использовать оболочку ссылок, но указатель часто проще.

Вы в основном уже нашли решение для 2. уже. То, что вы делаете, — это создаете новый массив, копируете старые элементы из старого массива в новый и уничтожаете старый массив. В целом это хороший подход, но с этой тривиальной реализацией есть ряд проблем:

  • Указатели на голое владение небезопасны и сложны в использовании.
  • Перераспределение и копирование всего массива при каждом добавлении обходится очень дорого.

Первое может быть решено с помощью идиомы RAII, а второе может быть решено путем отделения хранения объектов от создания объектов и увеличения хранилища на постоянный коэффициент, т. е. геометрически. Однако нет необходимости реализовывать такой контейнер RAII, поскольку вы охвачены стандартной библиотекой. Это называется std::vector .

В заключение: Вы можете использовать std::vector<Film*> .

Комментарии:

1. спасибо за ваш ответ. Использование std::vector не разрешено в моем проекте 🙂 Могу ли я изменить свою add_film функцию, чтобы она возвращала только что созданный экземпляр структуры массива, чтобы я мог использовать ее в одну строку, например Film film1 = add_film(...) , вместо использования двух команд add_film(...); Film film1 = films[0] ? Объявление типа возвращаемой функции Filmamp; и возврат return films[size] не работают. Тнх