Search code examples
c++cpointersmemorymemory-address

Why are malloc-allocated memory values assigned with i++ instead of i+4 (in the case of an int being 4 bytes large)?


My mind is confused and blown right now and hopefully someone can help me deconfuse it /put me on the right path again.

Correct me if I'm wrong but in C, you use malloc to 'reserve' / get a certain amount of space in memory in bytes.

So int* ptr = malloc(10 * sizeof(int)); would allocate 40 Bytes of memory / assign a pointer to that region in memory to the variable/pointer ptr (suppose that on this machine an int is 4 bytes large).


What I don't understand is when you assign the array with values why i is i++ (1 increment) instead of i + 4 aka the size of an int. It would make sense since we have a 40 Bytes block of memory and we iterate 10 times à +4 Bytes => 40 Bytes.

Code Example: Suppose, for the sake of simplicity, a function random() returns a random integer.

(The correct way -> 10 random ints):

for(int i = 0; i < 10; i++) {
    *(ptr + i) = random();
}

(My thought of i+4 Bytes, produces weird results, wrong way):

for(int i = 0; i < 10; i+=4) {
    *(ptr + i) = random();
}

My question is, why does ptr + i (i+1) select the correct address of each int when an int is 4 bytes large and we even reserve 40 Bytes of memory, not 10. aka why is ptr + i (i+4) wrong?

(To my brain it makes sense to iterate i+4 instead of 1. start / ptr assigned through malloc => 0x400, an int is 4 bytes large so the next address / next int is at 0x404, 0x408 etc.... not 0x401, 0x402 ....)


Solution

  • Pointer arithmetic, and memory allocation, are two different things.

    Pointer arithmetic is always done based on the type of the pointed-to object. That is, pointer arithmetic always incorporates an automatic, implicit multiplication by that size. So

    int *p;
    /* ... */
    p++;
    

    is always going to increment the address in p by sizeof(int) bytes.

    It has to be this way because, among other things, pointer arithmetic simulates array access. So it has to take the size of the pointed-to object into account in order for notations like

    *(p + 1)
    

    and

    p[1]
    

    to work properly.

    The malloc function, on the other hand, always deals in bytes. One reason -- perhaps the reason -- is precisely that malloc is a function. When you say something like

    malloc(10 * sizeof(int))
    

    the number received by the malloc function on your machine is just 40. malloc has no way of knowing whether that's 40 things of size 1, or 10 things of size 4, or one thing of size 40. All it knows is it has to allocate 40 bytes. (There are also requirements pertaining to alignment.)

    If you wanted it to work differently -- if you wanted something like

    int *ip = malloc(10);
    

    to automatically scale by sizeof(int) -- it's hard to see how it could work in C. (By contrast, in C++ there's new[], which can and does take the size of the allocated object into account.)