简体   繁体   中英

Is the sizeof operator needed for malloc?

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

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++);

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.

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.

The number of bytes incremented when you increment a pointer is only based on its type -- eg if you increment an int* by 1, you'll increment the address by 4 bytes. This has nothing to do with malloc or sizeof or anything.

You'll find that if you start storing values in those pointers, you'll run into strange behavior, as you haven't allocated enough space to store 3 short s, or 3 int s, or 3 long s.

You have fallen prey to a fallacy. You are not analyzing what malloc has returned, you are seeing that increment knows how to properly increment the pointer based on the size of the variable type. Nothing about a malloc call tells you how much RAM was actually allocated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM