0

When I create a dynamic Array :

int *arr = (int *) malloc( 4 * sizeof(int) );

So it should hold like 4 integers ( maybe 2 or 3 more for space issues maybe ) but why does that work :

    for ( int x = 0; x < 30000; x++) {
         arr[x] = x;
     }

I mean there shouldn't be so much space for 30.000 variables and its working just fine, what could be be the reason ? Does it automatic realloc like with c++ std::vector or how can I understand it ?

If I put the loop range like 50.000 it will crash, but it should even crash like at index a[100] or before, because the array is 4 elements big.

I am using gnu / linux if that matters.

I try very hard to understand it.

Please help

JimmeyNeutron
  • 57
  • 1
  • 5
  • 2
    Have you tried to use free on arr after your loop? If not, I recommend you try it out. – QEDemonstrandum Jan 15 '20 at 14:59
  • 2
    C allows you to access the memory space after index 4, but you should definitely not do it. Accessing memory outside of your allocated space will cause undefined behavior and probably crash your program at some point. – Kevin K. Jan 15 '20 at 15:00
  • 5
    Exceeding array bounds in C causes **Undefined Behaviour** and that really means that *anything* might happen, including that everything *seems* to work – Ingo Leonhardt Jan 15 '20 at 15:01
  • 2
    C does not support (on purpose) bound checking. – ssd Jan 15 '20 at 15:02
  • @QEDemonstrandum Tried it out now, It didn't change anything, but why should it even work with that ? – JimmeyNeutron Jan 15 '20 at 15:04
  • @KevinK. -- C doesn't allow out of bounds access, it only allows _attempted_ oob access. The result is undefined behavior, as you say. – ad absurdum Jan 15 '20 at 15:20
  • 2
    @KevinK., C ***does not*** allow access (or attempted access) outside the bounds of the allocated space. It simply does not define what happens when you do that. In particular, it does not specify that such an error must be detected or cause the program to fail. It does not specify what the program must do in that case *at all* -- not even other parts of the program. Perhaps you just mean that the syntax is valid (which it is), so the UB happens at run time, not at translation time. – John Bollinger Jan 15 '20 at 15:21
  • 1
    In addition to the provided duplicate, also see [How to explain undefined behavior](https://stackoverflow.com/questions/2235457/how-to-explain-undefined-behavior-to-know-it-all-newbies). – Lundin Jan 15 '20 at 15:24
  • 3
    And the usual analogy would be "- They said I can't run across the highway during rush hour, but I did just fine and wasn't hit by any car. I can't understand why. - That's because the cars aren't obliged by some law to crash with you when you are running across the highway. Nor are they obliged to stop and inform you that your behavior is dangerous. Keep running though, and you'll get hit eventually." – Lundin Jan 15 '20 at 15:29
  • @JohnBollinger No I can even print the array with 30.000 elements , that is what is suprtising me – JimmeyNeutron Jan 15 '20 at 15:36
  • @exnihilo That is really arguing semantics. The fact that OP is able to compile their application using an index outside of the allocated range, is by definition allowing access. – Kevin K. Jan 15 '20 at 16:09
  • Irrelevant, @JimmeyNeutron. Undefined behavior can and sometimes does manifest the same way as behavior that would be defined under other circumstances. "Undefined" means exactly what it says on the tin. – John Bollinger Jan 15 '20 at 16:10
  • 1
    @KevinK., yes, it is arguing semantics, in this case the semantics of the language specification. And in this context that's something to pay careful attention to, not to dismiss. – John Bollinger Jan 15 '20 at 16:12
  • @JohnBollinger I agree. There is a distinction between being "allowed" to do something and not being "allowed" to do something. C does not "allow" you declare a variable of a type that has is not defined. You will get an error during compilation and you will not be able to run the program in the first place. If you tell someone "hey, I'm not going to say that you can't go in this room, but I don't know what will happen if you do," you are allowing them to go in the room. – Kevin K. Jan 15 '20 at 16:16
  • No, @KevinK. Saying "I'm not going to say you can't" is quite a different thing from saying "you can". Though a better analogy would be "must not" *vs*. "may". The language specification does not start from the supposition that everything not forbidden is permitted. It does, however, explicitly start from the position that everything not defined is undefined. There is no explicit sense of "allowed" in the standard, except inasmuch as one can interpret exercising defined behavior to be allowed. – John Bollinger Jan 15 '20 at 16:21
  • @JohnBollinger Logically, it is not. Negating a negative is 100% equivalent to a positive. The emphasis should be on the fact that the issue does not arise from restrictions of the language itself, but the behavior that it causes. If you tell a freshman CS major that C does not allow you to access memory outside of the allocated range, they will not know the distinction between the way that C handles bounds as apposed to a bounds-checking language. – Kevin K. Jan 15 '20 at 16:28
  • Indeed, @KevinK., my point is that one should focus on the fact that the behavior associated with an attempt to access an array out of bounds is *undefined*. The attempt is neither allowed nor disallowed (which is not the same thing as "not allowed"). The hypothetical freshman is disserved by asserting either one of those. – John Bollinger Jan 15 '20 at 16:32

2 Answers2

5

As mentioned in the comments above, C is not a "bound-checking" language (if this is what you need, there are many alternatives to choose from, ranging from D, to Nim, which can also be easily mixed with pure ANSI C).

Now, back to your question.

What you did is allocate some memory for 4 ints. So far so good.

The fact that you can access other parts of memory (or more memory than what was initially allocated - see: out of range) and get away with it, doesn't mean you should do it. It may crash or it may not. This is what one would call "undefined behavior".

Now, if you want to be on the safe side, just do it the way you should:

  1. Allocate the memory you need first
  2. Access it - always within range
  3. Free it when you're done with it
Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • 4
    It might be worth adding that, if you seem to "get away with it," you may not get away with it when new code is added elsewhere in the program, or when any number of other seemingly innocuous factors change. – ad absurdum Jan 15 '20 at 15:23
  • 1
    @exnihilo Absolutely. Basically, you open yourself to all kinds of random bugs later on... – Dr.Kameleon Jan 15 '20 at 15:24
  • 2
    And if you seem to get away with it, @exnihilo, that doesn't mean you *really* get away with it. Especially in larger programs, it may be that bounds overruns cause effects that are not immediately recognized, such as silently corrupting data on which some distant part of the program relies. – John Bollinger Jan 15 '20 at 15:32
1

C does not assume responsibility for your array's limits. If you want to ensure that you don't overrun your allocated space, you would need to create a variable that represents the size of the allocated space, and use it both in the malloc command and in the for loop.

Your understanding of C needs to improve so you understand how using a low level language has its limitations and responsibilities.

C has a pseudo-memory check for arrays of characters that is accomplished by putting a null (0) at the end of every "string", but this only applies to certain methods and techniques.

Keith Smith
  • 41
  • 1
  • 5
  • Yes I came from C++ but it was to high level, because I badly wanted to understand how everything works in detail. Now I am doing C and I love it – JimmeyNeutron Jan 15 '20 at 15:38