I was asked this in an interview today:

Q: malloc(0); /* What does it do? */

It's a great question because it covers a subtlety in the standard and a condition that not many people will consider. Unfortunately, I wasn't 100% confident that I remembered what the standard said about it. With full understanding that I brought the question on myself by arrogantly describing myself as an expert in C, I gave my answer as follows: "A valid pointer will be returned, but that pointer cannot be dereferenced."

My answer was wrong. The interviewer said that the result was undefined behavior, which seemed slightly off to me at the time though I didn't challenge him on a nuance I wasn't assured of. As it turns out, my answer was partially correct, though in being partially correct it was still wrong. However, the interviewer wasn't correct either. The standard states the condition of a zero size request as follows:

"If the size of the space requested is zero, the behavior is implementation-deļ¬ned: 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."

Note that implementation-defined is very different from undefined. Undefined means that the very act of calling malloc(0) invokes undefined behavior and as a result makes the entire program henceforth undefined as well. Implementation-defined means that malloc(0) is legal and doesn't affect the legality of the rest of the program, but you must take all possible results into account when making the call if you want your code to be portable. As such, the following is portable and legal, but completely useless because the pointer cannot be dereferenced:

p = malloc(0);

if (!p)
{
    /* Don't dereference p */
}
else
{
    /* Still don't dereference p */
}

If malloc(0) were undefined, the above code would be horribly broken...and still completely useless. ;) The reason my partially correct answer was wholely wrong is I neglected to account for one of two possible outcomes. And while the interviewer was technically incorrect in saying that malloc(0) is undefined, he was practically correct because thinking of a useless situation as being undefined keeps you from creating that situation. In practice, he'd potentially write better code by avoiding sending in a zero size than by accounting for the implementation-defined behavior of sending in a zero size.

Robust code is the goal. I'm not sure there's a lesson to be learned from this interview, but it is what it is. Discuss. :)

Comments
awesome!! learnt something new!!

If we're doing tales from the interview, which is always something good to do, I have a tale from after the interview; after being told for over a week "we'll tell you tomorrow" they apparently had a review today in which they discovered that rather than needing multiple people in both permanent and contract positions, actually they aren't recruiting anyone at the moment.

Total amateur hour.

A chum who already works there told me he wasn't at all surprised, and to expect a phone call in a fortnight when they realise that actually they ARE hiring at the moment (and the intermediary recruiter independently told me the same thing - what a bunch of jokers). I do hope they don't expect me to answer the phone.

This is vaguely C related because the actual interview asked me about IPC in Linux, and the kernel is totally written in C :p

Edited 3 Years Ago by Moschops

rather than needing multiple people in both permanent and contract positions, actually they aren't recruiting anyone at the moment.

Was this a large corporation? That would still be sad, but a bit more understandable than a smaller company.

It was a sub-part of a company that is in the world's top 50 by revenue, capitalisation, employees, probably all the standard ways of measuring a company's size; so yes, very large, but the particular project only has 250 or so on it, so they really should know if they need to hire someone (my man on the inside says "Yes, oh God yes we need to hire people!"). They've had a bit of a bad run in the last decade or so and frankly, if this is typical, I'm not surprised. :)

Edited 3 Years Ago by Moschops

@deceptikon sir, you and that too in an interview ? :-o what is the result now ? yoo! am damn excited to know. ^_^.

sir, i wana clearify that undefined and implementaion dependent, both are not defined by C standard ?

secondly, i have read somewhere that malloc may use sbrk() in which when we pass 0, it returns pointer to location at which current heap is there. can't we relate this to that ?

thirdly, can you please give one more example to exemplify the difference between these 2 things ? thanks.

P.S best of luck sir!!

undefined and implementaion dependent, both are not defined by C standard ?

Undefined means all bets are off, the program could do anything and has no restrictions, nor does it have to behave predictably. Implementation-defined means the compiler must choose a predictable behavior and document it, even if the standard doesn't provide options on what the behavior might be.

Further, unspecified means that the compiler must choose a predictable behavior but doesn't need to document it.

i have read somewhere that malloc may use sbrk() in which when we pass 0

sbrk() is a Unix-ism. Talking about portability while also depending on a specific underlying implementation is silly.

can you please give one more example to exemplify the difference between these 2 things ?

I'm not sure I understand what you want to see. Which 2 things need further example?

firstly, the 2 things i am talking about are undefined and implementaion dependent. can you explain it with one more example like above ?

secondly, what is meant by "document it" ? this is the key to understand difference between unspecified and implementation dependent. thanks alot.

P.S I don't know i am capable to say you this , but people like you can be placed any where you want. but seriously, it is very good to see something which you are not able to answer correctly. :p (joking) hehe

Edited 3 Years Ago by nitin1

the 2 things i am talking about are undefined and implementaion dependent. can you explain it with one more example like above ?

An example of implementation-defined would be support of void main(), or the oft supported envp parameter to main():

/*
    Implementation-defined:
        * void return from main()
        * envp parameter
*/
void main(int argc, char *argv[], char *envp[])
{
}

If the compiler supports both of these, the above code is perfectly legal, but not portable. Further, the compiler's documentation must explicitly state support of these options or the compiler vendor must be able to adequately answer questions about such support. That's what I meant by "document".

A classic example of undefined behavior is the modification of an object multiple times between sequence points:

i = ++i + 1; /* Undefined */

This is wrong because i is modified twice (once from the increment operator and once from the assignment operator) before the semicolon sequence point. The compiler vendor not only doesn't need to document the behavior when that statement is executed, it doesn't even need to choose a single behavior. In other words, you could run the same program twice and get two completely different results. The only solution is to break up the expression into two statements:

++i;
i = i + 1;

it is very good to see something which you are not able to answer correctly. :p

There's far too much information to memorize at any given time, even if you restrict yourself to a "small" language like C. On Daniweb I look better than I really am because when posting I have the whole internet, and often my extensive library, at my disposal for quick reference.

In an interview one has to rely on one's memory and experience, so it's much more limiting.

Edited 3 Years Ago by deceptikon

This article has been dead for over six months. Start a new discussion instead.