Как передать вектор в функцию c
Перейти к содержимому

Как передать вектор в функцию c

  • автор:

Передать вектор в функцию

Author24 — интернет-сервис помощи студентам

Доброго всем здравия, телесного и духовного.
Пишу программу и понадобилось передавать в функцию вектор, и тут же запутался. В одном случаи, все работает, в другом все против меня. Дайте пожалуйста ссылку, где это объяснено для таких как я.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#include #include using namespace std; void full(vectorint> vec) { for (int i = 0; i  10; i++) { vec[i] = i + 1; } } void vivod(vectorint> vec) { cout  ; for (int i = 0; i  10; i++) cout  <'\t'  [i]  ; } int main() { vectorint> vec(10); full(vec); vivod(vec); system("pause"); return 0; }

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Как передать вектор в функцию?
Какими способами можно передать вектор в функцию? Например есть функция void asd() < .

Передать в функцию указатель на вектор
У меня есть вектор. Большой. Можно ли передать его так в ф-цию что бы не создавалась копия и что бы.

Передать итератор на шаблонный вектор в функцию
Здравствуйте. Есть два вектора std::vector<Player> players; // Player — структура с двумя.

Как передать вектор векторов в функцию?
Здравсвтуйте, проблема заключается в том, что при компиляции int func(int root, vector<.

Передача вектора в качестве аргумента функции

Здравствуйте, я только недавно начал изучать C++, поэтому проблема может показаться дурацкой, но надеюсь, что поможете.
Проблема такая, решил для практики написать простую программку, которая запрашивает количество заказанных блюд, их названия и цену, а потом выводит на экран уже с общей суммой.
Для цен и наименований блюд сделал два вектора, а вывод и подсчёт суммы выделил в отдельную функцию, но компилятор ругается на вызов этой функции и выдаёт ошибку «no matching function for call to «total»». Я пробовал сделать то же уже с обычным массивом и всё заработало, но всё же хочется узнать, что не так я делал с векторами.

#include #include #include using namespace std; void line() < for (int i=0; icout int total(int kol_vo, string dish[], int cost[]) < int sum=0; line(); for (int i=0; i int main()< cout>kol; vectordishes(kol); vectorcost(kol); for (int i=0; i>dishes[i]; cout>cost[i]; > cout 

Отслеживать

220k 15 15 золотых знаков 120 120 серебряных знаков 231 231 бронзовый знак

Как передать вектор в функцию c

Для добавления элементов в вектор применяется функция push_back() , в которую передается добавляемый элемент:

#include #include int main() < std::vectornumbers; // пустой вектор numbers.push_back(5); numbers.push_back(3); numbers.push_back(10); for(int n : numbers) cout << n << "\t"; // 5 3 10 std::cout

Векторы являются динамическими структурами в отличие от массивов, где мы скованы его заданым размером. Поэтому мы можем динамически добавлять в вектор новые данные.

Функция emplace_back() выполняет аналогичную задачу — добавляет элемент в конец контейнера:

std::vector numbers< 1, 2, 3, 4, 5 >; numbers.emplace_back(8); // numbers = < 1, 2, 3, 4, 5, 8 >;

Добавление элементов на определенную позицию

Ряд функций позволяет добавлять элементы на определенную позицию.

  • emplace(pos, value) : вставляет элемент value на позицию, на которую указывает итератор pos
  • insert(pos, value) : вставляет элемент value на позицию, на которую указывает итератор pos, аналогично функции emplace
  • insert(pos, n, value) : вставляет n элементов value начиная с позиции, на которую указывает итератор pos
  • insert(pos, begin, end) : вставляет начиная с позиции, на которую указывает итератор pos, элементы из другого контейнера из диапазона между итераторами begin и end
  • insert(pos, values) : вставляет список значений начиная с позиции, на которую указывает итератор pos
std::vector numbers< 1, 2, 3, 4, 5 >; auto iter = numbers.cbegin(); // константный итератор указывает на первый элемент numbers.emplace(iter + 2, 8); // добавляем после второго элемента numbers = < 1, 2, 8, 3, 4, 5>;
std::vector numbers1< 1, 2, 3, 4, 5 >; auto iter1 = numbers1.cbegin(); // константный итератор указывает на первый элемент numbers1.insert(iter1 + 2, 8); // добавляем после второго элемента //numbers1 = < 1, 2, 8, 3, 4, 5>; std::vector numbers2 < 1, 2, 3, 4, 5 >; auto iter2 = numbers2.cbegin(); // константный итератор указывает на первый элемент numbers2.insert(iter2 + 1, 3, 4); // добавляем после первого элемента три четверки //numbers2 = < 1, 4, 4, 4, 2, 3, 4, 5>; std::vector values < 10, 20, 30, 40, 50 >; std::vector numbers3 < 1, 2, 3, 4, 5 >; auto iter3 = numbers3.cbegin(); // константный итератор указывает на первый элемент // добавляем после первого элемента три первых элемента из вектора values numbers3.insert(iter3 + 1, values.begin(), values.begin() + 3); //numbers3 = < 1, 10, 20, 30, 2, 3, 4, 5>; std::vector numbers4 < 1, 2, 3, 4, 5 >; auto iter4 = numbers4.cend(); // константный итератор указывает на позицию за последним элементом // добавляем в конец вектора numbers4 элементы из списка < 21, 22, 23 >numbers4.insert(iter4, < 21, 22, 23 >); //numbers4 = < 1, 2, 3, 4, 5, 21, 22, 23>;

Удаление элементов

Если необходимо удалить все элементы вектора, то можно использовать функцию clear :

std::vector v < 1,2,3,4 >; v.clear();

Функция pop_back() удаляет последний элемент вектора:

std::vector v < 1,2,3,4 >; v.pop_back(); // v =

Если нужно удалить элемент из середины или начала контейнера, применяется функция std::erase() , которая имеет следующие формы:

  • erase(p) : удаляет элемент, на который указывает итератор p. Возвращает итератор на элемент, следующий после удаленного, или на конец контейнера, если удален последний элемент
  • erase(begin, end) : удаляет элементы из диапазона, на начало и конец которого указывают итераторы begin и end. Возвращает итератор на элемент, следующий после последнего удаленного, или на конец контейнера, если удален последний элемент

std::vector numbers1 < 1, 2, 3, 4, 5, 6 >; auto iter = numbers1.cbegin(); // указатель на первый элемент numbers1.erase(iter + 2); // удаляем третий элемент // numbers1 = < 1, 2, 4, 5, 6 >std::vector numbers2 = < 1, 2, 3, 4, 5, 6 >; auto begin = numbers2.cbegin(); // указатель на первый элемент auto end = numbers2.cend(); // указатель на последний элемент numbers2.erase(begin + 2, end — 1); // удаляем с третьего элемента до последнего // numbers2 =

Также начиная со стандарта С++20 в язык была добавлена функция std::erase() . Она не является частью типа vector. В качестве первого параметра она принимает вектор, а в качестве второго — элемент, который надо удалить:

std::vector numbers3 < 1, 2, 3, 1, 5, 6 >; std::erase(numbers3, 1); // numbers3 =

В данном случае удаляем из вектора numbers3 все вхождения числа 1.

Размер вектора

С помощью функции size() можно узнать размер вектора, а с помощью функции empty() проверить, путой ли вектор:

#include #include int main() < std::vectornumbers; if(numbers.empty()) std::cout

С помощью функции resize() можно изменить размер вектора. Эта функция имеет две формы:

  • resize(n) : оставляет в векторе n первых элементов. Если вектор содержит больше элементов, то его размер усекается до n элементов. Если размер вектора меньше n, то добавляются недостающие элементы и инициализируются значением по умолчанию
  • resize(n, value) : также оставляет в векторе n первых элементов. Если размер вектора меньше n, то добавляются недостающие элементы со значением value

std::vector numbers1 < 1, 2, 3, 4, 5, 6 >; numbers1.resize(4); // оставляем первые четыре элемента — numbers1 = numbers1.resize(6, 8); // numbers1 =

Важно учитывать, что применение функции resize может сделать некорректными все итераторы, указатели и ссылки на элементы.

Изменение элементов вектора

Функция assign() позволяет заменить все элементы вектора определенным набором:

std::vector langs = < "Java", "JavaScript", "C">; langs.assign(4, «C++»); // langs =

В данном случае элементы вектора заменяются набором из четырех строк «C++».

Также можно передать непосредственно набор значений, который заменит значения вектора:

std::vector langs< "Java", "JavaScript", "C">; langs.assign(< "C++", "C#", "C">); // langs =

Еще одна функция — swap() обменивает значения двух контейнеров:

std::vector clangs < "C++", "C#", "Java" >; std::vector ilangs < "JavaScript", "Python", "PHP">; clangs.swap(ilangs); // clangs = < "JavaScript", "Python", "PHP">; for(std::string lang : clangs)

Сравнение векторов

Векторы можно сравнивать — они поддерживают все операции сравнения: , =, ==, !=. Сравнение контейнеров осуществляется на основании сравнения пар элементов на тех же позициях. Векторы равны, если они содержат одинаковые элементы на тех же позициях. Иначе они не равны:

std::vector v1 ; std::vector v2 ; std::vector v3 ; bool v1v2 = v1 == v2; // true bool v1v3 = v1 != v3; // true bool v2v3 = v2 == v3; // false

Язык C++

Давайте напишем функцию add_item , которая принимает контейнер vector и добавляет в конец контейнера новый элемент. Мы могли бы начать со следующего кода:

#include #include #include using namespace std; // Здесь есть проблема void add_item(vectorstring> vec)  vec.push_back("New item!"); > int main()  vectorstring> vec; add_item(vec); for (string s : vec)  cout  <s  <'\n'; > return 0; > 

Если мы скомпилируем и запустим эту программу, то обнаружим, что после вызова функции add_item контейнер vec остался пустым. Проблема в том, что мы передали в функцию копию объекта vec . Внутри функции к этой копии был добавлен новый элемент, а после выхода из функции копия была удалена.

Следующий вариант нашей программы уже будет делать то что мы хотим:

// Здесь есть проблема vectorstring> add_item(vectorstring> vec)  vec.push_back("New item!"); return vec; > int main()  vectorstring> vec; vectorstring> vec2 = add_item(vec); for (string s : vec2)  cout  <s  <'\n'; > return 0; > 

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

Правильное решение нашей задачи в C++ выглядит следующим образом:

void add_item(vectorstring>& vec)  vec.push_back("New item!"); > int main()  vectorstring> vec; add_item(vec); for (string s : vec)  cout  <s  <'\n'; > return 0; > 

Символ амперсанд & позволяет передать в функцию ссылку на параметр. Работа с параметром внутри функции не изменяется, но вместо копии мы имеем дело именно с тем объектом, который был передан в функцию. Таким образом, мы избавились от лишнего копирования и реализовали правильную логику работы программы.

Рассмотрим другой пример. Допустим, мы хотим передать вектор в функцию, которая будет анализировать элементы вектора, но не будет его изменять. Например:

// Здесь есть проблема int count_greetings(vectorstring>& vec)  int counter = 0; for (string s : vec)  if (s == "Hello")  ++counter; > > return counter; > 

Мы уже достаточно грамотные и сразу передали вектор по ссылке, чтобы избежать ненужного копирования. Однако в текущем виде функция count_greetings имеет другую, более тонкую, проблему. Если мы нарушим договоренность и изменим вектор внутри функции count_greetings , то компилятор не увидит в этом проблемы. Проблему будем искать мы, когда поймем, что в каком-то месте нашей программы происходит неправильная манипуляция с вектором.

Хорошим стилем в данном случае является передача параметра по константной ссылке:

int count_greetings(const vectorstring>& vec)  int counter = 0; for (const string& s : vec)  if (s == "Hello")  ++counter; > > return counter; > 

Теперь компилятор не позволит изменить объект vec внутри функции count_greetings . Кроме того, теперь в коде явно выражена мысль о том, что объект передается в функцию только для чтения. Такой код проще читать и понимать логику его работы. Обратите внимание, что мы воспользовались константной ссылкой при определении переменной в цикле for . Здесь мы имеем дело с аналогичной ситуацией: в предыдущей версии в переменную s по очереди копировался каждый элемент вектора. Теперь же мы перебираем в цикле константные ссылки на объекты, не копируя их.

Иногда необходимо изменять элементы вектора в цикле. В таком случае необходимо использовать неконстантную ссылку:

for (string& s : vec)  s.push_back('!'); > 

Передача константной ссылки на объект в функцию, которая не имеет право изменять объект, имеет смысл только в том случае, если копирование объекта является дорогой операцией. В частности, нет никакого смысла в передаче по ссылке объектов int или double . Это наоборот может привести к потере производительности. Если же мы имеем дело со сложным объектом, таким как string или любым контейнером, то передача по константой ссылке является единственным верным решением.

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

Резюме

Мы обсудили три способа передачи параметров в функцию:

  • передача копии
  • передача по ссылке
  • передача по константной ссылке

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

Источники

  • isocpp.org/wiki/faq/references

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *