-1

My doubt is simple, when I allocated memory using malloc in my c program. Mistakenly I used this syntax

struct node {                          
    int data;
    int sat;
    int gau;
    struct node* next;
};
int main() {
    struct node *head;
    struct node *newnode;
    newnode = (struct node*)malloc(sizeof(struct node *);
    if(newnode != NULL) {
        newnode -> data = 5;
        newnode -> sat = 10;
        newnode -> gau = 15;
        newnode -> next = head;
        head = newnode;
    }
}

In line newnode = (struct node*)malloc(sizeof(struct node *); I accidently put sizeof(struct node *));` this will allocate the memory equivalent to the sizeof(pointer) = 4 or 8 bytes. But the code does not seg fault.

Why is this happening?

To understand this I tried another program with a slight change. I took a large int array inside the struct node and also this time I passed 0 to malloc.

struct node {                               
    int data;
    int sat;
    int gau;
    long long int a[1000];
    struct node* next;
};


int main() {
    struct node *head;
    struct node *newnode;
    newnode = (struct node*)malloc(0);
    if(newnode != NULL) {
        newnode -> data = 5;
        newnode -> sat = 10;
        newnode -> gau = 15;
        newnode -> next = head;
        newnode -> a[999] = 10;
        head = newnode;
    }
}

For me, this code also works. But, there should be some invalid memory access check which should make this code seg-fault or something? In this case seg-fault is not occuring, means there is definitely some memory which is getting accessed which should not be accessed by this program as it has not reserved it for itself using malloc. Why there is no error while executing this program?

  • Welcome to SO. "But, there should be some" Why do you think there should be such a check? It is your responsibility to behave correct. You cannot rely on others to catch your misbehaviour. What you do causes socalled "undefined bahaviour" which means everything can happen. It can seemingly work or it can immediately crash&burn. – Gerhardh Mar 06 '23 at 10:13
  • 1
    C have no bounds-checking. Going out of bounds of allocated memory leads to *undefined behavior*. It might cause a crash, it might seem to work if your unlucky, or it might set fire to your cat. Well, maybe not the cat-thing, but there's just no way of knowing what happens. – Some programmer dude Mar 06 '23 at 10:13
  • There is however another problem in your code: The definition but not initialization of `head`. Uninitialized local variables will just be kept uninitialized. They will have an *indeterminate* value, that you might look at as garbage. That means when you iterate over the list, the last node might not have a `NULL` next pointer, so you continue beyond the end of the list and again have undefined behavior. Simple solution: Initialize head as in `struct node *head = NULL;` – Some programmer dude Mar 06 '23 at 10:15
  • Also related: [How dangerous is it to access an array out of bounds?](https://stackoverflow.com/questions/15646973/how-dangerous-is-it-to-access-an-array-out-of-bounds) – Gerhardh Mar 06 '23 at 10:15
  • On another note, in C you [shouldn't really cast the result of `malloc`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858). Or any function returning a `void *` pointer. – Some programmer dude Mar 06 '23 at 10:17

1 Answers1

0

But, there should be some invalid memory access check which should make this code seg-fault or something?

The C standard doesn't mandate that. It is undefined behaviour¹ to access memory out of bounds; memory that you haven't allocated, or memory that you have already freed.

The underlying memory manager might detect you are accessing memory out of bounds and abort the program, or it may not. Either way, such an implementation is conforming to the C standard.

The second code snippet, which passes a size of 0 bytes to malloc() is non-portable and comes under implementation-defined behaviour:

If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object. — C11

Aside: It's unnecessary and redundant to cast the return of malloc(). malloc() and family returns a generic void * that is implicitly converted to any other pointer type. This behaviour is guaranteed by the C standard. What's crucial is to check its return value; it returns NULL to indicate failure.

Footnote:

1

behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements. — C11

Harith
  • 4,663
  • 1
  • 5
  • 20
  • Thank you for the detailed answer. I got that the malloc(0) is implementation specific. This mistake I committed in my code, then I realized it. But the code was not breaking, that's why I asked this. Thanks, @Haris for a detailed explanation. – Roshan bangar Mar 09 '23 at 04:58
  • Consider accepting the answer if it answered your question. – Harith Mar 09 '23 at 10:03