0

While solving a codeforces problem, I had to make a vector of size=1. Also, I needed to iterate back from the second last element of the vector, so I used the following technique to use for loop.

for(int i = vec.size()-2; i > -1; i--){
    vec[i] = vec[i] + vec[i+1];
}

This technique throws runtime error at codeforces compiler. But, using the size of the vector by precalculating it, it runs fine. Following snippet runs successfully.

int s = vec.size();
for(int i = s-2; i > -1; i--){
    vec[i] = vec[i] + vec[i+1];
}

Can someone help me understand this phenomenon?

PS: While figuring out the issue, I did

cout << vec.size()-2;

and to my surprise, the output came out to be

18446744073709551615

when the vector size was 1. The output should have been -1, right? Is this obvious, or something else. Kindly explain.

shihack
  • 57
  • 7
  • 2
    Are you sure the second snippet works? You are iterating till `i = -1` – DeGo Jun 05 '21 at 07:13
  • 2
    Please post a [mcve]. Also, you may be shocked if you used `at()` instead of `[]` to access the vector elements. You may see that neither of the two code examples work. `vec.at(i) = vec.at(i) + vec.at(i+1);` – PaulMcKenzie Jun 05 '21 at 07:14
  • *Can someone help me understand this phenomenon?* -- It's called [undefined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior). – PaulMcKenzie Jun 05 '21 at 07:20
  • 1
    *" I had to make a vector of size=1. Also, I needed to iterate back from the second last element of the vector"* - what is the second-last element of a vector with only one element? – John Zwinck Jun 05 '21 at 07:25
  • @John Zwinck, basically, vector of size 1 is just a sub-case. Overall, I need to iterate back from the second last element of the array. You can see the reason for this operation in the same snippet, where I am adding the value of the next index element. – shihack Jun 05 '21 at 08:04
  • 1
    @shihack Your edit doesn't take away from the fact that you are invoking undefined behavior. Using `[]` to access elements that are out-of-bounds causes this. If you did as I suggested to use the `at()` function, you may be greeted with a `std::out_of_range` exception on both of those code snippets. – PaulMcKenzie Jun 05 '21 at 08:15
  • @PaulMcKenzie, I dont think, I am doing anything which can cause undefined behavior. Can u check again please? Btw, I will remember the point of using `.at` member function rather than going directly with `[]`. – shihack Jun 05 '21 at 12:25
  • @shihack -- You are invoking undefined behavior. The large number is there because a vector uses [size_t](https://en.cppreference.com/w/cpp/types/size_t) , which is an unsigned type. There is no such thing as negative numbers for an unsigned type -- what happens is for the unsigned type, the value wraps around to the end of the integer range. The compiler should have also warned you that assigning the return value of `size()` to an `int` was a signed/unsigned mismatch, but you ignored the warnings. – PaulMcKenzie Jun 05 '21 at 12:53

1 Answers1

3

Here, you trying to access vec[-1], which leads to out of range subscript.

Try to run this and look for output:

for(int i = vec.size()-2; i >= -1; i--){
    cout << i << endl; // At some point will be -1
    vector<int>::size_type j = i; // Then this will be a very large unsigned number
    cout << j << endl; // On my machine it is 18446744073709551615
    //vec[i] = vec[i] + vec[i+1];
}

When you have vec[-1], the -1 will be converted to std::vector<T>::size_type, which is unsigned. This will lead to i in effect being a very large unsigned number, which in turn leads to faulty access via subscript.

The other version is essentially the same thing, but it may execute in some way, or may not (e.g. for me it did not went well). All due to the fact that both cases are an instance of undefined behavior.

As was noted in the comments on your question, you can look toward the at() member function of std::vector (do recommend) or try to implement explicit checks for out of range subscript yourself.

As to the update of the question:

I would suggest you to implement something like the following inspection and to run it on your platform:

for(int i = vec.size()-2; i > -1; i--){
        auto a = vec[i];
        auto b = vec[i+1];
        std::cout << "i: " << i << "; " << "i+1: " << i+1 << std::endl;
        std::cout << "a:" << a << " + " << "b:" << b << " = "  << a+b  <<  std::endl;
        std::cout << std::endl;
        vec[i] = a + b;
    }

E.g. for input: std::vector<int> vec = {1,2,3,4,5}; it gives the following output:

i: 3; i+1: 4
a:4 + b:5 = 9

i: 2; i+1: 3
a:3 + b:9 = 12

i: 1; i+1: 2
a:2 + b:12 = 14

i: 0; i+1: 1
a:1 + b:14 = 15
rawrex
  • 4,044
  • 2
  • 8
  • 24
  • I am sorry, but a slight modification was needed in the snippet. Kindly, have a look!! – shihack Jun 05 '21 at 07:59
  • @shihack considering update in the question, the `i > -1` condition won't let the loop to execute for a `vector` of size 1. If the size is bigger, it should run smoothly. Are you sure there's nothing else you're missed? – rawrex Jun 05 '21 at 08:07
  • yeah, only this much to be mentioned. – shihack Jun 05 '21 at 08:13
  • @shihack edited in a suggestion. Nevertheless, try using member functions for what you can. – rawrex Jun 05 '21 at 08:19
  • Your mentioning about the declared vector of size = 5 is up to the point. But, let say, if I declare a vector of size = 1, and try doing something like this. cout << vec.size() - 2; To my surprise, the output comes out to be "18446744073709551615". Surprising? Isn't it? Can u please explain this phenomenon? – shihack Jun 05 '21 at 12:14
  • 2
    It is not surprising. A vector uses `size_t`, which is an unsigned type, not signed type. – PaulMcKenzie Jun 05 '21 at 12:58
  • @shihack exactly, please take a look at the first paragraph of the answer once again. – rawrex Jun 05 '21 at 13:02
  • @shihack please consider marking an answer as accepted if you consider one as such, so that the question will be fulfilled and considered solved. – rawrex Jun 06 '21 at 04:42
  • @PaulMcKenzie Thanks, I didn't know this size_t concept earlier. – shihack Jun 07 '21 at 05:17