27

I'm using a vector in a C++ program and I need to pass a part of that vector to a function.

If it was C, I would need to do the following (with arrays):

int arr[5] = {1, 2, 3, 4, 5};
func(arr+2);  // Pass the part of the array {3, 4, 5}

Is there any other way than creating a new vector with the last part?

honk
  • 9,137
  • 11
  • 75
  • 83
mohit
  • 5,696
  • 3
  • 24
  • 37
  • 2
    "*If it was c I need to do this (with arrays):*" That would assume that `func` knew that it took an array of 3 elements (or fewer). If it expects an array of 5, you're screwed. – Nicol Bolas Jun 07 '13 at 12:02
  • It's quite possible you should be doing something else entirely. Why are you passing raw data around? What does the vector represent? I would encapsulate it and perform operations on it, instead of passing it elsewhere. – Peter Wood Jun 07 '13 at 12:09

7 Answers7

32

A common approach is to pass iterator ranges. This will work with all types of ranges, including those belonging to standard library containers and plain arrays:

template <typename Iterator>
void func(Iterator start, Iterator end) 
{
  for (Iterator it = start; it !=end; ++it)
  {
     // do something
  } 
}

then

std::vector<int> v = ...;
func(v.begin()+2, v.end());

int arr[5] = {1, 2, 3, 4, 5};
func(arr+2, arr+5);

Note: Although the function works for all kinds of ranges, not all iterator types support the increment via operator+ used in v.begin()+2. For alternatives, have a look at std::advance and std::next.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 3
    I'd say it more broadly: the function works for all **ranges**. Containers and arrays are one way of managing ranges, but they are not the only way. – Pete Becker Jun 07 '13 at 18:10
  • @juanchopanza don't we need to pass the array or vector in this case or else we need to make to them global so that it can accessible by function? – sakshi singhal Feb 05 '22 at 12:18
8

The latest (C++20) approach is to use std::span. Create a std::span that views a part of std::vector and pass it to functions. Note: the elements must be continuous in memory to use std::span on a container, and std::vector is continuous in memory.

#include <span>

std::vector<int> int_vector = {1, 2, 3, 4, 5};
std::span<int> a_span(int_vector.data() + 2, int_vector.size() - 2);
for(const int a : a_span);
for(const int& a : a_span);
function(a_span);
6

Generically you could send iterators.

static const int n[] = {1,2,3,4,5};
vector <int> vec;
copy (n, n + (sizeof (n) / sizeof (n[0])), back_inserter (vec));

vector <int>::iterator itStart = vec.begin();
++itStart; // points to `2`
vector <int>::iterator itEnd = itStart;
advance (itEnd,2); // points to 4

func (itStart, itEnd);

This will work with more than just vectors. However, since a vector has guaranteed contigious storage, so long as the vector doesn't reallocate you can send the addresses of elements:

func (&vec[1], &vec[3]);
John Dibling
  • 99,718
  • 31
  • 186
  • 324
4

As of C++20, I would make use of a range from the Ranges library, because it offers a variety of range adaptors for creating different views on you vector. For your use case, I would use the range adaptor std::views::drop as follows:

int main() {
    std::vector<int> arr {1, 2, 3, 4, 5};

    // Ignore the first two elements and pass only {3, 4, 5} to func().
    func(arr | std::views::drop(2));

    return 0;
}

This way you don't have to bother with interators or pointer/iterator arithmetic. Also, no temporary vector is created for your shortened arr, because the view adaptor drop() creates a range that doesn't contain elements. The resulting range is just a view over the original vector arr, but with a customized iteration behavior.

For the declaration of func() I would use the placeholder type auto for the function parameter, because the type of the resulting range is quite complex. This makes func() a function template, though:

void func(auto range) {
    for (int i : range)
        std::cout << i << std::endl;
}

(Alternatively, you could pass arr by reference to func() and apply the range adaptor inside func().)

Output:

3
4
5

Code on Wandbox

honk
  • 9,137
  • 11
  • 75
  • 83
1
std::vector<char> b(100); 
send(z,&b[0],b.size(),0);

Try out this.

Read this too.

  • You mean `&b[2]`, don't you? `&b[0]` yields the wrong result. –  Jun 07 '13 at 11:49
  • This works great for vectors, as they are contiguous. http://stackoverflow.com/questions/849168/are-stdvector-elements-guaranteed-to-be-contiguous. Just be careful not to try this type of thing with a non-contiguous storage containers. – kmort Jun 07 '13 at 11:50
0

As some others already stated you can use iterators for that. You'll have to pass the start of the sequence and the end of the sequence to your worker function.

If you need more flexibility, you should take a look at slice. With slice you can for example retrieve every n-th entry of the vector.

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
0

I was also stuck to same problem.I found one really nice trick.Suppose you want to find the minimum in range L to R (both inclusive) of arr then you can do something like this:

vector<int>arr = {4,5,1,3,7};

int minVal = *min_element(begin(arr)+L,begin(arr)+(R+1));

Means you pass the complete array and range and then you can apply the above trick.

Khatri
  • 616
  • 6
  • 19