Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the sizeof operator needed for malloc?

Tags:

c

In this program (C, not C++), why malloc always returns the correct size regardless of the use of the sizeof operator?

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char *c = malloc(3);
    short *s = malloc(3); /* or malloc(3 * sizeof(short))? */
    int *i = malloc(3);   /* or malloc(3 * sizeof(int))? */
    long *l = malloc(3);  /* or malloc(3 * sizeof(long))? */

    printf("%p\n", c++);
    printf("%p\n", c++);
    printf("%p\n", c++);

    printf("---\n");

    printf("%p\n", s++);
    printf("%p\n", s++);
    printf("%p\n", s++);

    printf("---\n");

    printf("%p\n", i++);
    printf("%p\n", i++);
    printf("%p\n", i++);

    printf("---\n");

    printf("%p\n", l++);
    printf("%p\n", l++);
    printf("%p\n", l++);

    return 0;
}

The output is:

0x1e82010 (1 byte)
0x1e82011
0x1e82012
---
0x1e82030 (2 bytes)
0x1e82032
0x1e82034
---
0x1e82050 (4 bytes)
0x1e82054
0x1e82058
---
0x1e82070 (8 bytes)
0x1e82078
0x1e82080

Am I missing something?

4.0.4-303.fc22.x86_64 clang version 3.5.0 (tags/RELEASE_350/final) Target: x86_64-redhat-linux-gnu Thread model: posix

like image 865
lmlf Avatar asked Jun 12 '15 00:06

lmlf


3 Answers

long *l = malloc(3);

This allocates (or rather attempts to allocate) 3 bytes.

Typically malloc() will actually allocate more than you request, for alignment and bookkeeping purposes. So after calling malloc(3), you may well be able to get away with storing 3 long values in the allocated memory. But it's not guaranteed.

Yes, you do need the sizeof.

And the best way to write that is:

long *l = malloc(3 * sizeof *l);

By using the size of what the pointer points to (sizeof *l), you don't have to specify the type long twice, and the code won't break if the type changes later.

Even better:

long *l = malloc(3 * sizeof *l);
if (l == NULL) {
    /* malloc failed, recover or bail out */
}

If you prefer, you can write this as:

long *l = malloc(3 * sizeof(*l));

but the extra parentheses aren't necessary, size sizeof is a unary operator, not a function.

printf("%p\n", l++);
printf("%p\n", l++);
printf("%p\n", l++);

Incrementing a pointer advances it by the size of the type it points to. long is apparently 8 bytes on your system, so this will advance l by least 24 bytes, well past the 3 bytes you requested from malloc. The result is undefined behavior.

And by incrementing l, you've lost the original value returned by malloc; you'll need that when it's time to call free().

Finally the %p format specifier requires an argument of type void*. Passing a different pointer type is likely to "work", but you really should cast it to void*:

printf("%p\n", (void*)l++);
like image 179
Keith Thompson Avatar answered Oct 10 '22 17:10

Keith Thompson


Am I missing something?

Yes, you are totally missing the point.

You are testing pointer arithmetic, which is defined in terms of the size of the pointed-to type. That has absolutely nothing to do with the amount of memory allocated by malloc(), or even whether the pointer in question points to a valid address at all.

like image 20
John Bollinger Avatar answered Oct 10 '22 15:10

John Bollinger


Incrementing a pointer increments the stored address by the size of the base type. It does not depend on what the pointer is pointing to.

like image 33
Christoph Sommer Avatar answered Oct 10 '22 17:10

Christoph Sommer