0

i am new in c, and i can not understand following piece of code. If anyone can explain it, i am really happy. Thanks in advance.

 if( ! ( st_cur = (struct ST_info *) malloc(sizeof( struct ST_info ) ) ) )
    {
        perror( "malloc failed" );
        return( 1 );
    }
HelloWorld
  • 39
  • 4
  • 10
  • Bad code. BTW is allocating `sizeof( struct ST_info)` byte into heap memory and assign the its address to `st_cur` pointer. The it checks if the returned address is valid `!= NULL ` Take a look at [the F...ine Man](http://man7.org/linux/man-pages/man3/malloc.3.html) – LPs Jun 15 '16 at 08:57
  • 1
    Break it down into smaller components. And remember that if `malloc` fails it returns `NULL` which is implicitly comparable to zero, and zero is equivalent to "false", and also remember that the logical not operator `!` gives you "true" if the expression is "false". – Some programmer dude Jun 15 '16 at 08:57
  • thanks for comments. I have one more question. After run this code, should i free st_cur ? In other words, if i don't free st_cur, it causes memory leak? – HelloWorld Jun 15 '16 at 09:03
  • 2
    @LPs I wouldn't call this bad code, it's quite common practice (IIRC, K&R also used similar constructs). – Leandros Jun 15 '16 at 09:03
  • @Leandros Using [tag:c] cast of `malloc` return is not required and should be avoided. My personal opinion: assign into `if` statement make the code less friendly and check `!= NULL` is more readable. – LPs Jun 15 '16 at 09:06
  • @HelloWorld You shouldn't, you **have to** free heap allocated memory. – LPs Jun 15 '16 at 09:07
  • Means someone was fond of superfluous parenthesis. Just throw that code out the window and use: `st_cur = malloc(sizeof(struct ST_info)); if(st_cur == NULL) { perror("malloc failed"); return 1; }`. (but with proper indention, obviously) – Lundin Jun 15 '16 at 09:08
  • @LPs Whether the result of `malloc` should be casted or not is totally based on opinion, neither way is "correct" nor "incorrect". And yes, I totally agree that the check should've been rewritten is `!= NULL`, it's a lot more readable! – Leandros Jun 15 '16 at 10:34
  • @Lundin They're not really superfluous, they're required due to the precedence of `=`. – Leandros Jun 15 '16 at 10:35
  • If an answer solved your problem or helped you, please consider to accept it, see also: http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – terence hill Jun 22 '16 at 11:40

8 Answers8

1

Let's start by taking a look at the malloc manual:

The malloc() function allocates size bytes and returns a pointer to the allocated memory.

If we dig in a little bit more and read the "return value" section of the manual:

The malloc() and calloc() functions return a pointer to the allocated memory that is suitably aligned for any kind of variable. On error, these functions return NULL.

With that in mind, what your code does is:

  • call malloc to allocate memory for the size of a struct ST_info.
  • cast the return value of malloc (void *, or generic pointer) to a struct ST_info.
  • assign it to the variable st_cur.
  • checks whether st_cur is null (that's what the "!" is used for) in case malloc somehow failed, in which case the code within the curly braces is executed.

As for all the parenthesis, they are here to ensure the code is executed in this order.

Sulli
  • 356
  • 2
  • 8
1

Let's break it down a bit.

if( ! ( st_cur = (struct ST_info *) malloc(sizeof( struct ST_info ) ) ) )
{
    perror( "malloc failed" );
    return( 1 );
}

Is equivalent to:

struct ST_info * st_cur = NULL;
//...

/* Assign heap memory of native byte size equal to that 
 * of struct ST_info and save a pointer to the allocated 
 * memory. */
st_cur = malloc( sizeof( struct ST_info ) ); 

/* If the malloc succeeded it will have returned a valid 
 * pointer to some part of the heap, otherwise it returns 
 * NULL so we check for NULL here. */
if (st_cur == NULL) { 
    /* Print a relevant error message to stderr. */
    perror("malloc failed"); 
    /* Return a non-zero value to indicate that something failed. */
    return(1); 
}

If you later wish to free the memory, which one should do for all dynamically allocated memory before finishing a program, you can use free(). here you do not need to first check for NULL as A) the if above should have caught it, and B) if passed NULL then free safely does nothing.

malloc can fail due to the system not being able to allocate the amount of memory requested. If the size passed to malloc is zero then the return value is implementation dependent but the returned pointer shall not be dereferenced.

Additionally, it has become good practice to not explicitly cast the value returned by malloc, thus

 st_cur = (struct ST_info *) malloc(sizeof( struct ST_info ) )

becomes

 st_cur = malloc(sizeof( struct ST_info ) )
Toby
  • 9,696
  • 16
  • 68
  • 132
0

In , an assignment will always return the assigned value.

In your specific case, st_cur is assigned, and after being assigned it's checked if it returned a valid value.

It's equivalent to this.

 st_cur = (struct ST_info*)malloc(sizeof(struct ST_info));
 if (!st_cur) {
     perror("malloc failed");
     return 1;
 }

If you wonder, why there are so many parentheses, they're required due to = having the lowest precedence of all operators in C.

Leandros
  • 16,805
  • 9
  • 69
  • 108
0

This is an assignment:

st_cur = (struct ST_info *) malloc(sizeof(struct ST_info))

that allocates memory and returns the pointer to that chunk of memory. If the allocation fails, malloc returns NULL, which is equivalent to 0 (post on NULL and 0). (BTW cast of malloc is pointless, see this post)

Then the result of the assignement, stored in st_cur is tested, so we can se it like in the follwing:

if (! st_cur )

which is equivalent to:

if (st_cur == NULL)

And thus if the allcation fail the perror function is called and the code return with 1

I would rewrite it:

st_cur = malloc(sizeof(struct ST_info));
if (st_cur == NULL) {
    perror( "malloc failed" );
    return(1);
}
Community
  • 1
  • 1
terence hill
  • 3,354
  • 18
  • 31
0

Inside if condition there can be any statement, that has value, which can be identified 0 or not-0, false or true .

st_cur = (struct ST_info *) malloc(sizeof( struct ST_info ) )

In this statement malloc is called and it's return value is assigned to st_cur. Value of all statement is value of st_cur. !st_cur is true, when st_cur is NULL So, equivalent code is

st_cur = (struct ST_info *) malloc(sizeof( struct ST_info ) ) 
if( ! st_cur )
{
    perror( "malloc failed" );
    return( 1 );
}
V. Kravchenko
  • 1,859
  • 10
  • 12
0
  1. malloc(sizeof( struct ST_info ) --> Allocate memory of given size.
  2. st_cur = (struct ST_info *) malloc... --> store the pointer returned by malloc in st_cur. Note that the cast (struct ST_info *) is unnecessary and sometimes dangerous. See more information at this answer.
  3. if( ! st_cur .. --> After the malloc has completed, check the value of st_cur. If it is 0 (NULL), then report an error, and return.
Community
  • 1
  • 1
Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
0

Malloc function is used to dynamically allocate some memory as required. Syntax to use malloc function is as follows:

(void *) malloc(size_of_memory_block)

Where argument size_of_memory_block is the amount of memory requested in bytes which you can find using sizeof(data_type) function. And it returns a pointer (of type void *) to the block of memory allocated.

In your case:

st_cur = (struct ST_info *) malloc( sizeof (struct ST_info) )

It allocates a memory block of size of your structure (struct ST_info) and returns a pointer to it which you are assigning to st_cur. Sometimes Malloc may fail (primarily due to system being out of memory) to allocate the memory size requested. Then it returns NULL which you are handling in your code with if condition.

Malloc functions return type is always void * which you can cast to the type as required. In your code, you are casting it to type struct ST_info *.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
0

In plain words, it is saying

Hey malloc, give me enough memory for the size of the ST_info struct (Let's say ST_info struct has N bytes).

If there isn't enough memory left for N bytes, malloc() will return NULL. But if there is enough, malloc() will return you a void pointer (void *) to the chunk of memory.

Then you are casting that void pointer to a struct ST_Info pointer (struct ST_info *) and storing it in the variable st_cur.

Then the ! is checking whether or not st_cur is NULL. If st_cur is NULL (meaning malloc() failed to give you memory), the if statement would be true and you would see perror() and return(1)

If st_cur is not NULL, it means malloc() successfully allocated memory and the whole if statement is bypassed

ygongdev
  • 264
  • 3
  • 19