Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does malloc(sizeof(pointer)) work?

This following code works fine:

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

int main()
{
    struct node{
        int a, b, c, d, e;
    };
    struct node *ptr = NULL;
    printf("Size of pointer ptr is %lu bytes\n",sizeof (ptr));
    printf("Size of struct node is %lu bytes\n",sizeof (struct node));
    ptr = (struct node*)malloc(sizeof (ptr));               //Line 1
//    ptr = (struct node*)malloc(sizeof (struct node));    //Line 2

    ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;
    printf("a: %d, b: %d, c: %d, d: %d, e: %d\n",
            ptr->a,ptr->b,ptr->c,ptr->d,ptr->e);
    return 0;
}

When complied as:

gcc -Wall file.c

My question is: why is this fine?

malloc allocates the number of bytes which are specified in it's argument. Here sizeof ptr is 8 bytes on my 64-bit linux machine. I thought malloc will provide 8 bytes but then how is it accessing all the variables a,b,c,d,e? Is it with gcc only or am I missing something with standard C?

As far as I know "Line 2" should be there instead of "Line 1" but either of the line works fine. Why?

like image 216
Bharat Kul Ratan Avatar asked Jul 31 '12 17:07

Bharat Kul Ratan


2 Answers

You have undefined behavior here.

malloc will allocate 8 bytes (as you say), but this cast is "bad":

ptr = (struct node*)malloc(sizeof (ptr));

After this line, ptr will point to a memory block, which has only 8 allocated bytes, the rest are some "random" bytes. So, making

ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;

you actually change some memory, not only the allocated by malloc.

In other words, you are rewriting memory, you're not supposed to touch.

like image 87
Kiril Kirov Avatar answered Nov 15 '22 15:11

Kiril Kirov


Line 1 is incorrect and won't allocate sufficient space. If you can access the structure members later it is only because C does nothing to prevent you from accessing memory that doesn't belong to you.

Accessing ptr->b, ptr-c, etc., when you haven't allocated enough space for the entire structure is undefined behavior, and the next time that you run your code it could crash, or you could end up overwriting data in another part of your program.

To demonstrate the problem, allocate a second struct node immediately after the first. This isn't guaranteed to demonstrate the problem, but you're likely to see results similar to the following:

struct node *ptr = NULL;
struct node *ptr2 = NULL;

ptr = (struct node*)malloc(sizeof (ptr));  // Your Line 1
ptr2 = malloc(sizeof(struct node));        // alloc another struct on the heap

ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;
ptr2->a = 11; ptr->b = 12; ptr->c = 13; ptr->d = 14; ptr->e = 15;

printf("ptr:  a: %d, b: %d, c: %d, d: %d, e: %d\n",
        ptr->a, ptr->b, ptr->c, ptr->d, ptr->e);
printf("ptr2: a: %d, b: %d, c: %d, d: %d, e: %d\n",
        ptr2->a, ptr2->b, ptr2->c, ptr2->d, ptr2->e);

Output:

ptr:  a: 1, b: 2, c: 3, d: 4, e: 11
ptr2: a: 11, b: 12, c: 13, d: 14, e: 15

Note that ptr->e has been modified by the assignment to ptr2->a, so you can see that one improperly-allocated structure is stepping on the memory of another. This certainly isn't what you want.

like image 42
pb2q Avatar answered Nov 15 '22 16:11

pb2q