-4
#include <iostream>

using namespace std;

int main()
{
    int lists[30];
    lists[30] = 30;
    lists[0] = 31;
    cout << lists[30];
    cout << "\n";
    cout << lists[0];
    for(int a = 0; a < lists[30]+lists[0]; a++)
    {
        cout << "\n";
        cout << lists[2];
    }
}

After the for loop, it should only show the value of lists[2] for 61 times; lists[30] = 30 and lists[0] = 31, so combined they are 61. Is the expression within the for loop valid? It seems to loop forever.

Evan Carslake
  • 2,267
  • 15
  • 38
  • 56
J derpy
  • 1
  • 2

3 Answers3

5

Use lists[29], you're exceeding the bounds of the array. Remember indexes are 0-based, not 1-based.

By default C++ does not have bounds-checking on arrays, so this:

int array[100];
array[100] = 1;

Is the same as:

int* array = calloc( 100, 4 );
*(array + 100) = 1;

...which is +1 element outside the bounds of the array in memory. You're writing into in unallocated space, resulting in undefined behaviour.

Dai
  • 141,631
  • 28
  • 261
  • 374
  • Then why do they report the correct values when used to cout them outside of the loop? If they are out or range, why are the values still correct? Shouldn't they be wrong? And if they are correct, even if out of range, why can't it add them together and end the loop when the total is reached? – J derpy Aug 27 '15 at 23:25
  • this is why you should use std::array or std::vector – pm100 Aug 27 '15 at 23:32
  • @Jderpy You're invoking undefined behaviour, which means anything can happen (the compiler may omit instructions, or replace them, in fact it's even allowed to replace the whole program by an hello world if it can detect this program will always cause undefined behaviour at some point). Never rely on what the program seems to do when you're invoking undefined behaviour. For more details, I suggest you to read [this blog post](http://blog.regehr.org/archives/213). – Caninonos Aug 27 '15 at 23:47
  • What is the `calloc` case supposed to illustrate that the array case doesn't? – M.M Aug 27 '15 at 23:49
  • @MattMcNabb My example intends to illustrate that a C++ array is identical to an arbitrary buffer (i.e. no bounds-checking like in Java or .NET) and that exceeding the bounds of an array is identical to writing outside of a buffer. – Dai Aug 28 '15 at 00:33
  • Well , an array is an arbitrary buffer so the first example already illustrates that. BTW `int* array = calloc( 100, 4 );` fails to compile in C++, you must cast the return value of `calloc`. – M.M Aug 28 '15 at 00:38
2

Valid indexes into int lists[30] are 0 through 29. But you're accessing 30. Since that's undefined behavior, all kinds of weird things could happen.

Possibly what's happening in your case is that some other action (such as subsequent calls to cout) is using that memory location. So by the time your loop is running, that value is no longer 30.

TheUndeadFish
  • 8,058
  • 1
  • 23
  • 17
  • @Jderpy Perhaps it hasn't been overwritten _yet_ at that point. Trying outputing it during the loop. – TheUndeadFish Aug 27 '15 at 23:27
  • By other operations in your program, such as the very act of calling `cout`. You're accessing memory that you're not supposed to access, so its hard to say exactly what else might be making use of it. – TheUndeadFish Aug 27 '15 at 23:28
  • It's not possible to access memory outside of the program due to virtual memory and memory protection that the OS handles. If accessing "wrong memory" was as simple as going one index outside of an array in C++, you're saying basically that a segmentation fault of a GPU driver is possible this way too? – J derpy Aug 27 '15 at 23:29
  • But it's perfectly possible to access memory outside the bounds of an array. In this case that memory is inside program and in fact on or near the stack. And since the stack is used during function calls the act of using `cout <<` has a reasonable chance of making use of that location. – TheUndeadFish Aug 27 '15 at 23:30
  • What location??? And wouldn't the C++ parser/compiler be smarter to refuse to compile if out-of-bounds? If so, it's impossible to make the mistake I did and other people who are noobs might make. – J derpy Aug 27 '15 at 23:32
  • 2
    @Jderpy no, C++ contains a lot of situations where the onus is on you to follow the rules and there is no warning if you don't. There are plenty of other languages to choose from if that does not suit your tastes! – M.M Aug 27 '15 at 23:51
  • @MattMcNabb Please read my replies again to understand my wording. Thank you. – J derpy Aug 28 '15 at 03:05
0

The fundamental problem with your code is that you are using an undefined memory location, lists[30], because you declared an array with 30 elements, but address the ordinal 31st position of the array. Both C and C++ start indexing arrays from zero (0), so the actual last valid position in the array is 30-1 = 29, thus lists[30] is an invalid memory location.

Because you declared one additional variable, a, on the stack (the same memory location where lists[30] is placed), and your compiler placed that variable in memory adjacent to the array, list[30], when you assign a value to the variable a, you are also changing the value that you are addressing using the (invalid) memory location lists[30] (this is dependent upon where your compiler choose to place variables when declared, so this program may run differently on different architectures).

#include <iostream>

using namespace std;

int main()
{

This line defines an array of 30 int with valid indices 0..29

    int lists[30];

Want your program to work? change the number 30 above to 31

    int lists[30+1];

Or, you could at least make the variable a work by placing another variable on the stack between lists[30] and a,

    int filler;

This line addresses an invalid location, index 30, which is a location on the 'stack', adjacent to list[29], and assigns a value to that memory location

    lists[30] = 30;
    lists[0] = 31;

What value do you think list[2] contains?

This line addresses an invalid location, index 30, and this time references the memory at that location

    cout << lists[30];
    cout << "\n";
    cout << lists[0];

Yet again, lists[30] is invalid, same problem as before. Since int a is allocated on the stack, lists

    for(int a = 0; a < lists[30]+lists[0]; a++)
    {
        cout << "\n";

You have not yet assigned a value to lists[2], what do you think the value is?

        cout << lists[2];
    }
}

The same problem with array indexing would occur in any language that is zero-indexed and does not check array bounds.

ChuckCottrill
  • 4,360
  • 2
  • 24
  • 42