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

Как вернуть vector из функции c

  • автор:

Возвращаемый вектор из функции C++

Я пытаюсь вернуть вектор со значениями в обратном порядке (например, я ввожу вектор с 0,1,2,3,4 и функция возвращает вектор с 4,3,2,1,0).

Компилятор говорит: Segmentation fault.

В моих тестах я заметил, что, вероятно, моя проблема заключается в присваивании new2 = ret_vec(числа); , но я не знаю, что происходит.

#include #include #include using namespace std; vector ret_vec(vectorn) < vector n2; for (int i = 0; i < n.size(); ++i)< n2[i] = n[i]; >return n2; > void initializer(int s, vector& n) < for (int i = 0; i< s; ++i)< n.push_back(i); >> void print_vector(vector n) < for (int i = 0; i> int main () < vector numbers; int size; cin >> size; initializer(size,numbers); vector new2(numbers.size()); cout

Поделиться Источник 13 мая 2015 в 21:11

2 ответа

Я пытаюсь вернуть вектор со значениями в обратном порядке

Самый простой подход — использовать C++:

vector reverse_vec(const vector& n) < vectorret(n.rbegin(), n.rend()); return ret; > 

Здесь обратные итераторы используются для создания вектора с содержимым входного вектора, обращенного в обратном порядке. В качестве альтернативы, если вы хотите обратить вектор на месте, используйте std::reverse :

vector v = . std::reverse(v.begin(), v.end()); // v is now reversed 

Что касается проблем с вашим кодом, очевидным является то, что вы получаете доступ к вектору вне границ здесь:

vector n2; // empty vector for (int i = 0; i < n.size(); ++i)< n2[i] = n[i]; // oops! n2 accessed out of bounds! >

Исправление заключается в том, чтобы не использовать этот код вообще и искать простой вариант.

Поделиться 13 мая 2015 в 21:12

В следующей функции

vector ret_vec(vectorn) < vector n2; for (int i = 0; i < n.size(); ++i)< n2[i] = n[i]; >return n2; > 

Вы просто копируете содержимое вектора параметров. (Я думаю, вы забыли пробел между параметром и типом его)

Вы также можете изменить порядок таким образом (его можно изменить «по рукам»):

vector ret_vec(vector n) < vector n2; for(int i=n1.size()-1; i return n2; > 

Как вернуть vector из функции 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

Как вернуть vector из функции c

Загрузка. Пожалуйста,
подождите.

Здравствуйте, Гость ( Вход | Регистрация | Что даёт регистрация на форуме? )

Дата 15.10.2008, 12:27 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50

Как вернуть из функции пустой вектор?

Код
std::vector Func(const std::string &sStr) if (sStr.empty() == true) //как здесь вернуть пустой вектор?
>
std::vector Vec;
//.
return Vec;
>
Дата 15.10.2008, 12:31 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25

Код
return std::vector();

user posted image

Дата 15.10.2008, 12:59 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50

Спасибо, то что надо!

Дата 15.10.2008, 13:28 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 45
Всего: 134

а что мешало написать

Код
std::vector Func(const std::string &sStr) std::vector Vec;
if (sStr.empty() == true) return Vec;
>
//.
return Vec;
>

Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.

Дата 15.10.2008, 13:41 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50

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

Дата 23.1.2023, 20:07 (ссылка) | (нет голосов) Загрузка .

Профиль
Группа: Участник
Сообщений: 18
Регистрация: 23.1.2023

Репутация: нет
Всего: нет

Модератор: Сообщение скрыто.

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ 🙂
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе — для этого существует «Центр Помощи».
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »

[ Время генерации скрипта: 0.1216 ] [ Использовано запросов: 21 ] [ GZIP включён ]

Как вернуть vector из функции: по значению или по ссылке?

Есть функция, создающая каким-то определенным образом экземпляр vector . Вопрос: как вернуть этот экземпляр вызывающему?

Правильное с точки зрения логики и стройности программы решение выглядит так:

std::vectorint> create_vector(const size_t N) std::vectorint> v; v.resize(N, 0xDEADC0DE); return v; > 

Тут экземпляр вектора возвращается по значению, что означает потенциальное глубокое копирование локального объекта в контекст вызывающей функции. Сразу возникает сомнение: а что, если вектор огромен — его ж надо будет побайтно перекладывать из одного места в другое? Гораздо “разумнее” было бы написать:

void create_vector(const size_t N, std::vectorint>* v) v->resize(N, 0xDEADC0DE); > 

Тут вектор передается по указателю, и стопроцентно ненужного полного копирования не будет. Но такой код выглядит откровенно плохо.

Сравним скорости работы на векторе длиной 100MB. Например, на компиляторе:

Apple clang version 3.1 (tags/Apple/clang-318.0.45) (based on LLVM 3.1svn) Target: x86_64-apple-darwin11.3.0 
#include #include std::vectorint> __attribute__((noinline)) create_vector(const size_t N) std::cout  <"by value"  ::endl; std::vectorint> v; v.resize(N, 0xDEADC0DE); return v; > int main(int argc, char* argv[]) for (size_t i = 0; i  10; ++i) const size_t N = 1024 * 1024 * 100; std::vectorint> v = create_vector(N); if (v[i] != 0xDEADC0DE) std::cout  <"Test is rubbish"  ::endl; return 0; > > return 0; > 
clang++ -O3 -o by_value by_value.cpp && time ./by_value 
0m4.933s 

Теперь по указателю:

#include #include void __attribute__((noinline)) create_vector(const size_t N, std::vectorint>* v) std::cout  <"by pointer"  ::endl; v->resize(N, 0xDEADC0DE); > int main(int argc, char* argv[]) for (size_t i = 0; i  10; ++i) const size_t N = 1024 * 1024 * 100; std::vectorint> v; create_vector(N, &v); if (v[i] != 0xDEADC0DE) std::cout  <"Test is rubbish"  ::endl; return 0; > > return 0; > 
clang++ -O3 -o by_pointer by_pointer.cpp && time ./by_pointer 
0m4.852s 

Время в обоих случаях одинаково. Получается, что стоит выбрать первый, “красивый” вариант.

Объяснений тут два. Первый, и возможно самый важный — это RVO, Return value optimization. Это когда компилятор догадывается, что создаваемый локальный экземпляр вектора предназначен для возврата из функции, и сразу создает его в контексте вызывающего кода, чтобы потом не копировать туда. Фактически компилятор реализует передачу по ссылке, но неявно, не портя красоту исходного кода. Данный трюк будет работать для любого класса, не обязательно класса из STL.

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

Ну а в контексте C++11, где есть семантика перемещения, вообще не будет лишних копирований, если класс “правильно” реализован (что верно для классов из STL).

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

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

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