Home > Back-end >  Can arrays just be used as iterators in c ?
Can arrays just be used as iterators in c ?

Time:03-04

I'm just looking through std::vector constructors and seeing some people use the constructor that takes 2 iterators and just use it with arrays like:

int arr[5] = [1,2,3,4,5]
std::vector<int> v(arr, arr   arr.size()/arr[0])

Why does this work? So is an array just an iterator as well? Also one more question here:

 int a[5] = {0, 1, 2, 3, 4};
    vector<int> v4(a, *(&a   1));

What exactly is this doing and why is it different from the other thing above?

CodePudding user response:

int arr[5] = [1,2,3,4,5]
std::vector<int> v(arr, arr   arr.size()/arr[0])

Why does this work?

This doesn't work.

So is an array just an iterator as well?

An array is not an iterator. But an array can implicitly convert to a pointer to first element which is an iterator for the array.


int a[5] = {0, 1, 2, 3, 4};
vector<int> v4(a, *(&a   1));

What exactly is this doing

This is an unnecessarily complex way of writing:

std::vector<int> v4(std::begin(a), std::end(a));

CodePudding user response:

int arr[5];

int *begin=arr;
int *end=arr sizeof(arr)/sizeof(*arr);

std::vector<int> v(begin, end);

Here arr (as in begin=arr) is a "pointer", which can be used like an iterator. So begin=arr is an "iterator" to the beginning of the array and end is an "iterator" to the "beginning 5".

To be a little more precise: Here the name of the array "decays" into a pointer. In many circumstances the name can be used as a pointer and would be similar to &arr[0], i.e. a pointer to the first element.

The construction sizeof(array)/sizeof(*array) goes back to the old C days and returns the number of elements in an array. sizeof by itself only returns the size in bytes, but if you divide that by the size of a single element, you get the number of elements.

So now that you have a correct "begin" and "end" iterator, you can construct a std::vector<int> from it. It's just one of the constructors of vector, which takes two iterators.


Your other questions is completely different from the first one.

vector<int> v4(a, *(&a 1));

Now I am not sure this makes entirely sense. Perhaps you have typo here. This would try to call a vector constructor taking an int[] or int* as the first parameter and an int as the second parameter.

The signature would be std::vector<int>::vector(int*, int), but I do not see such a constructor in the cppreference.

CodePudding user response:

The first piece has several errors:

int arr[5] = [1,2,3,4,5]
std::vector<int> v(arr, arr   arr.size()/arr[0])

The correct version would be:

int arr[5] = {1,2,3,4,5};
std::vector<int> v(arr, arr   sizeof(arr)/sizeof(arr[0]));

where arr plus "the number of elements in arr is a pointer just past the end of arr.

In the second piece, *(&a 1), is a pointer. &a is a pointer to a which is an array of 5 integers. Thus adding 1 advances the pointer sizeof(a) bytes (5 times the size of an integer). Hence, again the result is a pointer just past the end of a and thus the vector is initialized with the elements of a.

CodePudding user response:

For starters there is a typo

int arr[5] = [1,2,3,4,5]
std::vector<int> v(arr, arr   arr.size()/arr[0])

It seems you mean

int arr[5] = {1,2,3,4,5};
std::vector<int> v(arr, arr   sizeof( arr ) / sizeof( arr[0] ));

Though if your compiler supports the C 17 you could write

#include <iterator>

int arr[5] = {1,2,3,4,5};
std::vector<int> v(arr, arr   std::size( arr ));

Arrays used in expressions with rare exceptions are converted to pointers to their first elements.

From the C 17 Standard (7.2 Array-to-pointer conversion)

1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The temporary materialization conversion (7.4) is applied. The result is a pointer to the first element of the array.

Consider the following demonstration program.

#include <iostream>

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

    std::cout << "sizeof( arr ) = " << sizeof( arr ) << '\n';
    std::cout << "sizeof( arr   0 ) = " << sizeof( arr   0 ) << '\n';
}

Its output might loop like

sizeof( arr ) = 20
sizeof( arr   0 ) = 4

As it is seen from the output the array designator arr was converted to a pointer in the expression arr 0.

The same way if an array is used as an argument expression and the corresponding parameter type is not a referenced type when the array is converted to a pointer to its first element.

There is no constructor in the class template std::vector that has the first parameter having a referenced type to an array.

But there is a template constructor that accepts two first arguments of the same type

template <class InputIterator>
vector(InputIterator first, InputIterator last, const Allocator& = Allocator());

So in this declaration

std::vector<int> v(arr, arr   sizeof( arr ) / sizeof( arr[0] ));

there is used two above constructor where two first arguments are converted to pointers of the type int *.

Pointers have the same operations as a random access iterator. Thus the vector is created using the range of integer values [arr, arr sizeof( arr ) / sizeof( arr[0] )

As for this expression

*(&a   1)

then the expression &a has the type int ( * )[5] that points to the array a.. The expression &a 1 points to the address pass the last element of the array. The dereferenced expression *(&a 1) has the type int[5] that denotes an array that again used as an expression is converted to pointer of the type int *.

So you have in fact two expressions of the type int * in this declaration

vector<int> v4(a, *(&a   1));

However this approach is not correct because you may not dereference a pointer that points after a valid object.

  • Related