#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
С этим связаны две проблемы:
- В C не может быть массивов ссылок.
- Нет никакого способа добавить в массив. Размер массива является константой. Нет никакого способа добавлять или удалять элементы.
Проблема с вашим попытанным решением заключается в том, что у вас есть массив фильмов, а не массив ссылок. Это не очень удивительно, поскольку проблема 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]
не работают. Тнх