I'm new to C and currently learning iterators.
I wrote the following code, which adds the first and last digit in a vector.
In order to decrement the iterator, I've had to decrement the variable dec_pointer
twice for the correct results. I'm obviously doing something wrong, but what?
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<int> vec{1,4,2,6,9,10,17,13,15};
size_t first_last =0;
size_t dec_pointer = vec.size()-1;
for(auto it =vec.cbegin(); it !=vec.cend() && !vec.empty(); it)
{
first_last = *it *(it (dec_pointer--));
std::cout<<"Add First and Last Digit : "<<first_last<<std::endl;
dec_pointer--;
}
return 0;
}
CodePudding user response:
If you were adding the first and last elements (as per your text), you wouldn't need a loop, you could just do (after checking minimum size, of course):
first_plus_last = *(vec.cbegin()) *(vec.cend()-1);
It looks however that you're trying to add the first and last, second and second last, and so on. The reason why you would have to decrement twice is because you're getting the second iterator value by adding something to the current iterator value (not the start iterator).
For example, let's for the purposes of understanding just pretend they're indexes rather than iterators:
index: 0 1 2 3 4 5 6 7 8
value: 1 4 2 6 9 10 17 13 15
To correctly add the first (moving) index and a delta value to get the second index, you would need:
index1 index2 index2 as (index1 delta)
------ ------ --------------------------
0 8 0 8
1 7 1 6
2 6 2 4
... and so on
You can see that the required delta is decreasing by two each time: 8, 6, 4, ...
.
But, rather than doing iterator calculations, I would opt for just running an iterator from both ends, toward the middle. In other words, something like this:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec{1, 4, 2, 6, 9, 10, 17, 13, 15};
if (vec.size() > 0) {
auto left = vec.cbegin();
auto right = vec.cend() - 1;
while (left < right) {
auto num1 = *left ;
auto num2 = *right--;
auto sum = num1 num2;
std::cout << "Add (" << num1 << ", " << num2 << "): " << sum << '\n';
}
if (left == right) {
std::cout << "One number left in middle: " << *left << '\n';
}
}
}
That seems like cleaner (as in "easier to understand") code to me, and the output is:
Add (1, 15): 16
Add (4, 13): 17
Add (2, 17): 19
Add (6, 10): 16
One number left in middle: 9
It also works with all the possible vector sizes (empty, one element, even number of elements, and odd number of elements greater than one).
CodePudding user response:
If you used vec.cbegin()
instead of it
when calculating the last pointer, you would not have this issue.
first_last = *it *(vec.cbegin() dec_pointer--)
CodePudding user response:
On the 1st loop iteration, it
refers to the first element, and dec_pointer
is 8, so you have:
-----------------------------------------
| 1 | 4 | 2 | 6 | 9 | 10 | 17 | 13 | 15 |
-----------------------------------------
^ ^
it it 8
If you then increment it
by 1 and decrement dec_pointer
by 1 not 2, on the 2nd iteration dec_pointer
is now 7
and you have this:
-----------------------------------------
| 1 | 4 | 2 | 6 | 9 | 10 | 17 | 13 | 15 |
-----------------------------------------
^ ^
it it 7
If you then increment it
by 1 and decrement dec_pointer
by 1 not 2, on the 3rd iteration dec_pointer
is now 6
and you have this:
-----------------------------------------
| 1 | 4 | 2 | 6 | 9 | 10 | 17 | 13 | 15 |
-----------------------------------------
^ ^
it it 6
And so on. So, as you can see, the last
value you refer to with it dec_pointer
is always the same element 15
. That is why you have to decrement dec_pointer
by 2 instead of 1 to get the correct result:
-----------------------------------------
| 1 | 4 | 2 | 6 | 9 | 10 | 17 | 13 | 15 |
-----------------------------------------
^ ^ ^ ^ ^ ^
it | | | | it 8
| | | |
it 1 | | (it 1) 6
| |
it 2 (it 2) 4
That being said, I would suggest an alternative and simpler solution - use a reverse_iterator
from vec.crbegin()
to access the 2nd value, instead of offsetting a forward iterator
from vec.cbegin()
, eg:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<int> vec{1,4,2,6,9,10,17,13,15};
auto last_it = vec.crbegin();
for(auto it = vec.cbegin(); it != vec.cend(); it, last_it)
{
int first_last = *it *last_it;
std::cout << "Add First and Last Digit : " << first_last << std::endl;
}
return 0;
}
Or even simpler, just get rid of the it
loop iterator completely:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<int> vec{1,4,2,6,9,10,17,13,15};
auto last_it = vec.crbegin();
for(int first : vec)
{
int first_last = first *last_it ;
std::cout << "Add First and Last Digit : " << first_last << std::endl;
}
return 0;
}