Can a vector::iterator also function as a vector - c++

So I am trying to load a binary file into a Vector, so I can use it like a Buffer.
ifstream binaryFile;
vector<unsigned char> fileBuffer(istreambuf_iterator<char>(binaryFile), {});
vector<unsigned char>::iterator fileIter = fileBuffer.begin();
Now my question is, if I use the fileIter variable, can I access all the elements in the fileBuffer vector ?
I want to know, because I need to edit the contents of the fileBuffer only at certain Positions, that is why I am working with iterators in the first place.
In a nutshell, I want to know if the content of the vector fileBuffer will change, according to edits made to the fileIter with code like
*(fileIter + 2) = 'a';
I have researched this Topic but I have not yet found an answer.

The standard class template std::vector has a random access iterator. So you can use it the same way as a pointer. For example
fileIter[10] = 'A';
or
fileIter += 10;
and so on.
Here is a demonstrative program.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
auto it = v.begin();
it[1] = -it[1];
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
it += 2;
*it *= 10;
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Its output is
1 2 3 4 5
1 -2 3 4 5
1 -2 30 4 5

Related

How are pairs stored in memory in C++?

I was just reading about pairs in C++ when this doubt stroke my mind that how the pairs are stored in memory and id the identifier assigned to the pairs a object or something else.
pls explain how an array containing pair uses memory to save the pairs and how can we iterate through the that array, by accessing each pair;
As for the pair itself, if you take a look at the standard library source code you'll just notice, that after cutting all the boilerplate, the for the most trivial case std::pair is just a simple class template:
template<typename First, typename Second>
struct pair
{
First first;
Second second;
};
Now, all the boilerplate is there to ensure the all the special functions like comparison, assignment, copy construction etc. are performed with minimal overhead.
But for the sake of mental model one can think of this simple struct.
As for "array of pairs" - I'm not sure I follow, really.
std::array<std::pair<X,Y>, SIZE>/std::vector<std::pair<X,Y>> behaves just as it would for any other type, i.e. it store the pairs in contiguous memory block, end of story.
Same about iteration, there's nothing special about it:
std::array<std::pair<char, int>, 3> pairs{
std::pair{'a', 1},
std::pair{'b', 2},
std::pair{'c', 3}};
for (const auto& p:pairs){
std::cout << p.first << " " << p.second << "\n";
}
demo
Take a look at this example:
#include <iostream>
#include <array>
#include <iterator>
int main( )
{
std::array< std::pair<char, char>, 10 > arrayOfPairs { };
std::cout << "size of array: " << sizeof( arrayOfPairs ) << "\n\n";
for ( size_t idx { }; idx < arrayOfPairs.size( ); ++idx) // fill the array with
// std::pair objects
{
arrayOfPairs[ idx ] = std::make_pair<char, char>( 'a', 'b' + idx );
}
std::cout << "key" << " " << "value" << '\n';
for ( const auto& p : arrayOfPairs ) // print the keys and values
{
std::cout << " " << p.first << " " << p.second << '\n';
}
return 0;
}
Output:
size of array: 20
key value
a b
a c
a d
a e
a f
a g
a h
a i
a j
a k
In this example, each pair object consists of two chars, so the size is 2 bytes. arrayOfPairs has the space for 10 pair objects which means that its size is 10 * 2 == 20 bytes. In an std::pair object, the key and its value are stored besides each other. It acts like a simple struct.

C++ finding uint8_t in vector<uint8_t>

I have the following simple code. I declare a vector and initialize it with one value 21 in this case. And then i am trying to find that value in the vector using find. I can see that the element "21" in this case is in the vector since i print it in the for loop. However why the iterator of find does not resolve to true?
vector<uint8_t> v = { 21 };
uint8_t valueToSearch = 21;
for (vector<uint8_t>::const_iterator i = v.begin(); i != v.end(); ++i){
cout << unsigned(*i) << ' ' << endl;
}
auto it = find(v.begin(), v.end(), valueToSearch);
if ( it != v.end() )
{
string m = "valueToSearch was found in the vector " + valueToSearch;
cout << m << endl;
}
are you sure it doesn't work?
I just tried it:
#include<iostream> // std::cout
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
vector<uint8_t> v = { 21 };
uint8_t valueToSearch = 21;
for (vector<uint8_t>::const_iterator i = v.begin(); i != v.end(); ++i){
cout << unsigned(*i) << ' ' << endl;
}
auto it = find(v.begin(), v.end(), valueToSearch);
if ( it != v.end() )
{// if we hit this condition, we found the element
string error = "valueToSearch was found in the vector ";
cout << error << int(valueToSearch) << endl;
}
return 0;
}
There are two small modifications:
in the last lines inside the "if", because you cannot add directly a
number to a string:
string m = "valueToSearch was found in the vector " + valueToSearch;
and it prints:
21
valueToSearch was found in the vector 21
while it's true that you cannot add a number to a string, cout
support the insertion operator (<<) for int types, but not uint8_t,
so you need to convert it to it.
cout << error << int(valueToSearch) << endl;
This to say that the find is working correctly, and it is telling you that it found the number in the first position, and for this, it != end (end is not a valid element, but is a valid iterator that marks the end of your container.)
Try it here

Most 'functional' way to sum pairs of elements from a vector using C++17 or later?

I'd like some suggestions for the most terse and 'functional' way to gather pairs of successive elements from a vector (1st and 2nd, 3rd and 4th, etc.) using modern C++. Assume the vector is of arbitrary but even length. For the examples I'm pulling together, I'm summing the elements of each pair but that's not the main problem. I should add I'll use STL only, no Boost.
In Python I can zip them into 2-tuples via an iterator with
s = range(1,11)
print([(x + y) for x,y in zip(*[iter(s)] * 2)])
In Perl 5 I can peel off pairs with
use List::Util qw/pairs sum/;
use feature 'say';
#s = 1 .. 10;
say sum #$_ foreach (pairs #s);
In Perl 6 I can shove them two at a time into a block with
my #s = 1 .. 10;
for #s -> $x, $y { say $x + $y; }
and in R I can wrap the vector into a 2-column array and sum the rows with
s <- 1:10
print(apply(matrix(s, ncol=2, byrow=TRUE), 1, sum))
I am not fluent in C++ and my solution uses for(;;). That feels too much like C.
#include <iostream>
#include <vector>
#include <numeric> // std::iota
int main() {
std::vector<int> s(10);
std::iota(s.begin(), s.end(), 1);
for (auto p = s.cbegin(); p != s.cend(); p += 2)
std::cout << (*p + *(p + 1)) << std::endl;
}
The output of course should be some variant of
3
7
11
15
19
Using range-v3:
for (auto v : view::iota(1, 11) | view::chunk(2)) {
std::cout << v[0] + v[1] << '\n';
}
Note that chunk(2) doesn't give you a compile-time-fixed size view, so you can't do:
for (auto [x,y] : view::iota(1, 11) | view::chunk(2)) { ... }
Without using range-v3 I was able to do this with either a function or a lambda template. I'll show the lambda version here.
#include <iostream>
#include <string>
#include <vector>
template<typename T>
auto lambda = [](const std::vector<T>& values, std::vector<T>& results) {
std::vector<T> temp1, temp2;
for ( std::size_t i = 0; i < values.size(); i++ ) {
if ( i & 1 ) temp2.push_back(values[i]); // odd index
else temp1.push_back(values[i]); // even index
}
for ( std::size_t i = 0; i < values.size() / 2; i++ )
results.push_back(temp[i] + temp[2]);
};
int main() {
std::vector<int> values{ 1,2,3,4,5,6 };
for (auto i : values)
std::cout << i << " ";
std::cout << '\n';
std::vector<int> results;
lambda<int>(values, results);
for (auto i : results)
std::cout << i << " ";
std::cout << '\n';
std::vector<float> values2{ 1.1f, 2.2f, 3.3f, 4.4f };
for (auto f : values2)
std::cout << f << " ";
std::cout << '\n';
std::vector<float> results2;
lambda<float>(values2, results2);
for (auto f : results2)
std::cout << f << " ";
std::cout << '\n';
std::vector<char> values3{ 'a', 'd' };
for (auto c : values3)
std::cout << c << " ";
std::cout << '\n';
std::vector<char> results3;
lambda<char>(values3, results3);
for (auto c : results3)
std::cout << c << " ";
std::cout << '\n';
std::vector<std::string> values4{ "Hello", " ", "World", "!" };
for (auto s : values4)
std::cout << s;
std::cout << '\n';
std::vector<std::string> results4;
lambda<std::string>(values4, results4);
for (auto s : results4)
std::cout << s;
std::cout << '\n';
return EXIT_SUCCESS;
}
Output
1 2 3 4 5 6
3 7 11
1.1 2.2 3.3 4.4
3.3 7.7
a d
┼
Hello World!
Hello World!
At the risk of sounding like I'm trying to be clever or annoying, I say this is the answer:
print(sums(successive_pairs(range(1,11))));
Now, of course, those aren't built-in functions, so you would have to define them, but I don't think that is a bad thing. The code clearly expresses what you want in a functional style. Also, the responsibility of each of those functions is well separated, easily testable, and reusable. It isn't necessary to use a lot of tricky specialized syntax to write code in a functional style.

Slicing a vector in C++

Is there an equivalent of list slicing [1:] from Python in C++ with vectors? I simply want to get all but the first element from a vector.
Python's list slicing operator:
list1 = [1, 2, 3]
list2 = list1[1:]
print(list2) # [2, 3]
C++ Desired result:
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;
v2 = v1[1:];
std::cout << v2 << std::endl; //{2, 3}
This can easily be done using std::vector's copy constructor:
v2 = std::vector<int>(v1.begin() + 1, v1.end());
In C++20 it is pretty easy:
#include <span>
#include <vector>
#include <iostream>
template<int left = 0, int right = 0, typename T>
constexpr auto slice(T&& container)
{
if constexpr (right > 0)
{
return std::span(begin(std::forward<T>(container))+left, begin(std::forward<T>(container))+right);
}
else
{
return std::span(begin(std::forward<T>(container))+left, end(std::forward<T>(container))+right);
}
}
int main()
{
std::vector v{1,2,3,4,5,6,7,8,9};
std::cout << "-------------------" << std::endl;
auto v0 = slice<1,0>(v);
for (auto i : v0)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v1 = slice<0,-1>(v);
for (auto i : v1)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v2 = slice<1,3>(v);
for (auto i : v2)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v3 = slice<1,-1>(v);
for (auto i : v3)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v4 = slice<3,3>(v);
for (auto i : v4)
{
std::cout << i << std::endl;
}
}
Result:
Program returned: 0
-------------------
2
3
4
5
6
7
8
9
-------------------
1
2
3
4
5
6
7
8
-------------------
2
3
-------------------
2
3
4
5
6
7
8
-------------------
You can also add boundary checks and other cases like negative left indices etc... but this is only an example.
Run in compiler explorer: https://godbolt.org/z/qeaxvjdbj
I know it's late but have a look at valarray and its slices. If you are using a vector of some sort of NumericType, then it's worth giving it a try.
It depends on whether you want a view or a copy.
Python's slicing for lists copies references to the elements, so it cannot be simply regarded as a view or a copy. For example,
list1 = [1, 2, 3]
list2 = list1[1:]
list2[1] = 5
print(list1) # does not change, still [1, 2, 3]
list1 = [1, 2, [3]]
list2 = list1[1:]
list2[1][0] = 5
print(list1) # changes, becomes [1, 2, [5]]
See this post for details.
DimChtz's anwer models the copy situation. If you just want a view, in C++20, you can use ranges (besides std::views::drop, std::views::take and std::views::counted are also useful):
auto v2 = v1 | std::views::drop(1); // #include <ranges>
for (auto &e: v2) std::cout << e << '\n';
or std::span:
std::span v2{v1.begin() + 1, v1.end()}; // #include <span>
for (auto &e: v2) std::cout << e << '\n';
You can follow the above answer. It's always better to know multiple ways.
int main
{
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2{v1};
v2.erase( v2.begin() );
return 0;
}
It seems that the cheapest way is to use pointer to the starting element and the number of elements in the slice. It would not be a real vector but it will be good enough for many uses.

How to clear out element inside an array?

I want to clear out all the element inside my array but I don't know how to automatically clear it out. is there a function for it? Like the clear() for lists??
int array[5] = {2,5,4,8,6};
then I want to clear out everything and add a new set of values
Your question isn't valid because you can't clear out an array. An array has a fixed size and there always will be some value in it.
If you want to re-use an array, just overwrite the existing values.
Perhaps consider using std::vector. Using clear() function, you can clear all the values from the std::vector.
Learn about std::vector Here
To clear an array means to set all values to T() that for arrays of fundamental arithmetic types is equivalent to set all elements to zeroes.
You can do it in several ways. The first one is to use standard C function std::memset declared in header <cstring>. For example
#include <iostream>
#include <cstring>
int main()
{
int array[] = { 2, 5, 4, 8, 6 };
const size_t N = sizeof( array ) / sizeof( *array );
for ( int x : array ) std::cout << x << ' ';
std::cout << std::endl;
std::memset( array, 0, N * sizeof( int ) );
for ( int x : array ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
Another way is to use standard algorithm std::fill declared in header <algorithm>. For example
#include <iostream>
#include <algorithm>
int main()
{
int array[] = { 2, 5, 4, 8, 6 };
const size_t N = sizeof( array ) / sizeof( *array );
for ( int x : array ) std::cout << x << ' ';
std::cout << std::endl;
std::fill( array, array + N, 0 );
for ( int x : array ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
In the both cases the program output is
2 5 4 8 6
0 0 0 0 0
If you need a variable length array then use standard container std::vector<int>.
For example
#include <iostream>
#include <iomanip>
#include <vector>
int main()
{
std::vector<int> array = { 2, 5, 4, 8, 6 };
for ( int x : array ) std::cout << x << ' ';
std::cout << std::endl;
array.clear();
std::cout << "array is empty - " << std::boolalpha << array.empty() << std::endl;
return 0;
}
The program output is
2 5 4 8 6
array is empty - true
Instead of array.clear(); there could be also used array.resize( 0 ); in the program.