-3

I am running the following code where I declare a dynamic 2D array, and then go on to assign values at column indexes higher than the number columns actually allocated for the dynamic array. However, when I do this the code runs perfectly and I don't get an error, which I believe I should get.

 void main(){


        unsigned char **bitarray = NULL;
        bitarray = new unsigned char*[96];

        for (int j = 0; j < 96; j++)
        {
                bitarray[j] = new unsigned char[56];
            if (bitarray[j] == NULL)
            {
                cout << "Memory could not be allocated for 2D Array.";
                return;// return if memory not allocated
            }
        }

        bitarray[0][64] = '1';
        bitarray[10][64] = '1';

        cout << bitarray[0][64] << " " << bitarray[10][64];

        getch();
        return;
    }

The link to the output I get is here (The values are actually assigned accurately, don't know why, though).

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261

3 Answers3

5

In C++, accessing a buffer out of its bounds invokes undefined behavior (not a trapped error, as you expected).

The C++ specification defines the term undefined behavior as:

behavior for which this International Standard imposes no requirements.

Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • Anyways, I should get an error. Why am I not getting it? – Muhammad Faique Shakeel Jul 01 '15 at 10:00
  • 1
    @MuhammadFaiqueShakeel "*Should* get an error" is a requirement. An implementation has *no requirements* when you program invokes undefined behavior (as yours does). In other words, you are wrong to expect an error. – Theodoros Chatzigiannakis Jul 01 '15 at 10:02
  • 1
    @MuhammadFaiqueShakeel On a more practical level, an access violation error is thrown by the OS when your process attempts to access memory it does not own. Accessing a buffer out of its bounds *does not necessarily access memory that your process doesn't own*. You may simply be accessing the memory of another variable *in your program*, for example. The OS can't know whether this is or isn't what you intended because (a) it doesn't know about C++ and (b) even if it did, it's not its job to protect your process from itself. – Theodoros Chatzigiannakis Jul 01 '15 at 10:03
  • Is there anyway to avoid this undefined behaviour. Or it won't cause any problems? – Muhammad Faique Shakeel Jul 01 '15 at 10:06
  • 2
    @MuhammadFaiqueShakeel To avoid undefined behavior, you need to know the rules of C++ well enough and be careful enough so you don't write a program that invokes undefined behavior. Undefined behavior should be avoided at all costs, because it is unpredictable and because it can and will cause serious problems, including crashes, strange program flow, data corruption, security vulnerabilities, and more. As you have noticed in this example, trial and error is an especially bad way to learn C++, because valid implementations can vary greatly, unfortunately. – Theodoros Chatzigiannakis Jul 01 '15 at 10:10
  • I can't seem to figure what mistake I am making here. I have allocated arrays like this before and it has never caused problems. Why now? Sorry for bugging you again and again. – Muhammad Faique Shakeel Jul 01 '15 at 10:14
  • @MuhammadFaiqueShakeel As I said, trial and error is a bad way to learn C++. For other languages (e.g. Java, C#, etc), it's mostly okay - but for C++ (and C), it simply isn't. In other words, you can't draw conclusions from what seemed to work in the past - *all* programs that invoke undefined behavior are invalid, even if they seem to work. They can fail in subtle ways you don't notice soon enough. The best you can do is (a) read and understand the C++ specification and (b) use static and dynamic analyzers that will warn you if something is wrong (even if you would have missed it otherwise). – Theodoros Chatzigiannakis Jul 01 '15 at 10:25
4

In your code, both

    bitarray[0][64] = '1';
    bitarray[10][64] = '1';

are accessing memory out-of-bound,. i.e., those memory locations are "invalid". Accessing invalid memory invokes undefined behaviour.

The access violation error or segmentation fault is one of the many possible outcomes of UB. Nothing is guaranteed.

From the wiki page for segmentation fault,

On systems using hardware memory segmentation to provide virtual memory, a segmentation fault occurs when the hardware detects an attempt to refer to a non-existent segment, or to refer to a location outside the bounds of a segment, .....

so, maybe, just maybe, the memory area for bitarray[0][64] is inside the allocated page (segment) which is accessible (but invalid anyway) by the program , in this very particular case. That does not mean it will be, always.

That said, void main() is not a correct signature of main() function. The recommended (C++11,§3.6.1) signature of main() is int main(void).

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
3

C++11 introduced std::array and the method at() provides out of bounds checking.

Simon
  • 1,616
  • 2
  • 17
  • 39