0

I was writing some code in XCode and noticed something interesting when I was partially filling an array. My code was basically something like this (this is just an example for the sake of simplicity):

#include <iostream>
using namespace std;

int main(){
    int** array = new int*[20];
    for(int k = 0; k < 20; k+=3){
        array[k] = &k;
    }

    for(int k = 0; k < 20; k++){
        bool ptrVal = (array[k] == nullptr);
        cout << k << ": " << ptrVal << endl;
    }
}

This snippet of code ended up printing out this:

0: 0
1: 0
2: 0
3: 0
4: 0
5: 0
6: 0
7: 1
8: 1
9: 0
10: 1
11: 1
12: 0
13: 1
14: 1
15: 0
16: 1
17: 1
18: 0
19: 1

I was expecting this:

0: 0
1: 1
2: 1
3: 0
4: 1
5: 1
6: 0
7: 1
8: 1
9: 0
10: 1
11: 1
12: 0
13: 1
14: 1
15: 0
16: 1
17: 1
18: 0
19: 1

Afterwards I read the article below about how the OS is overcommitting memory: C++ memory allocation for an array of pointers

Does the OS deliberately allocate non-contiguous blocks of memory for an array of pointers that has been partially filled? If so why does it do this and what could be the reasons for the results shown in my sample code?

Community
  • 1
  • 1
Jamaal
  • 1,469
  • 1
  • 16
  • 32
  • 2
    `array[k]` in the second loop causes undefined behaviour - the pointer pointed to a variable that no longer exists. The two `k` are different variables (with non-overlapping scopes) – M.M Oct 07 '16 at 05:03
  • 2
    Also you cause undefined behaviour by using uninitialized pointers (the loop skips in steps of 3) – M.M Oct 07 '16 at 05:04
  • 2
    @Eichhörnchen evaluating dangling pointers is undefined behaviour already (before we get so far as comparing) – M.M Oct 07 '16 at 05:07
  • @M.M So if you have uninitialized/dangling pointers how come when the elements of the array are printed out 0s and 1s appear in random order? – Jamaal Oct 08 '16 at 19:53
  • [undefined behaviour](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) means anything can happen – M.M Oct 08 '16 at 21:32

2 Answers2

2

You have:

int** array = new int*[20];
for(int k = 0; k < 20; k+=3){
    array[k] = &k;
}

after that, k[1], k[2], [k4], k[5] .. are left uninitialized. They are not set to nullptr by the line that allocates the pointers.

As a consequence the line,

    bool ptrVal = (array[k] == nullptr);

is cause for undefined behavior.

You can make the pointers equal to nullptr at allocation time by using:

int** array = new int*[20]{};
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • @R Sahu your suggestion results in a compile time error. This is the compiler I'm using if you're curious: Apple LLVM version 8.0.0 (clang-800.0.38) Target: x86_64-apple-darwin15.5.0 Thread model: posix – Jamaal Oct 08 '16 at 19:45
  • @Jamaal that compiler defaults to 2003 mode , use `-std=c++14` flag, or change `{}` to `()` – M.M Oct 08 '16 at 21:36
1

You are assuming uninitialized elements of array are set to 0. They are not. If you add

    memset(array, 0, sizeof(*array)*20);

Before the first loop, then your output will be what you were expecting.

Victor Havin
  • 1,023
  • 7
  • 11
  • I understand that memset would result in the desired output. But I'm wondering if an array does not have all its elements initialized, why do the elements appear to have 0s and 1s appear in random order when printed out? – Jamaal Oct 08 '16 at 19:51
  • In general, uninitialized heap contains random data. Therefore, when you use uninitialized heap, output from uninitialized portions of it is random. The heap implementation depends on the operating system and compiler. However, if you want deterministic behavior, of your code, the heap has to be initialized after allocation. Period. – Victor Havin Oct 10 '16 at 16:11