Memory question

M

Mohanasundaram

Hi All,

As per the standard what is the result of passing NULL to both malloc and free?

Regards,
Mohan.
 
V

Victor Bazarov

Mohanasundaram said:
As per the standard what is the result of passing NULL to both malloc
and free?

'free' does nothing if you pass null pointer there. 'malloc' does not
accept pointers.
 
R

Ron Natalie

Victor Bazarov said:
and free?

'free' does nothing if you pass null pointer there. 'malloc' does not
accept pointers.
In C++ NULL isn't a pointer. Passing NULL to malloc is legal. However
the return value is implementation defined. It may either return a null pointer
or a unique (but non-derferencable) pointer value.

You can't use NULL as the operand of new or delete.
 
A

Alf P. Steinbach

In C++ NULL isn't a pointer. Passing NULL to malloc is legal. However
the return value is implementation defined. It may either return a null pointer
or a unique (but non-derferencable) pointer value.

You can't use NULL as the operand of new or delete.

You can pass a NULL pointer value to delete, but not directly; it needs
to be typed as a pointer.

In C++ literal 'NULL' as a token is equivalent to literal '0' as a token.

Sorry to pick nits, but that statement was just too easy to misinterpret.
 
R

Ron Natalie

Alf P. Steinbach said:
You can pass a NULL pointer value to delete, but not directly; it needs
to be typed as a pointer

That was my point. NULL doesn't have pointer type, so it can't be passed
to delete. It can be passed to malloc as it has an integral zero value.
In C++ literal 'NULL' as a token is equivalent to literal '0' as a token.

Sorry to pick nits, but that statement was just too easy to misinterpret.

To pick nits. NULL as a token is equivalent to NULL. It's required to be
a macro evaluating to an integral constant expression of value 0. It could
be anything like:

#define NULL 0 // my favorite
#define NULL (0L) // unfortunately also quite common

// the following are legal but weird.
#define NULL (!true)
#define NULL '\0'
#define NULL (5 - 4 - 1)*(34L)/true
 
S

Steve Clamage

Mohanasundaram said:
Hi All,

As per the standard what is the result of passing NULL to both malloc and free?

The rules in the C++ standard for malloc and free are the same as in C.

The malloc function takes an integer argument representing size, not NULL, which
is a null pointer constant.

Assuming you meant malloc(0), the results depend on the implementation. An
implementation is allowed always to return a null pointer, or to return a unique
pointer if it can (it's possible to run out of address space). It cannot return
a pointer to an existing object. Whatever the return, you are not allowed to
dereference the pointer, because it need not point to allocated memory. (You
asked for 0 bytes, after all.)

I don't find anything in either standard that disallows always returning the
same non-null address for malloc(0), as long as that address is not othewise used.

The short answer is that malloc(0) is allowed, but you can't depend on doing
much with the result. Allowing malloc(0) simplifies some algorithms.

Passing a null pointer to free() is allowed, and has no net effect.

The net result of these rules is that you can always call free (once) with the
result you got from malloc.
 
J

James Kuyper

Mohanasundaram said:
Hi All,

As per the standard what is the result of passing NULL to both malloc and free?

In C, the behavior of malloc(NULL) depends upon your implementation.
1. NULL can be an integer constant expression with a value of 0, in
which case you've done the eqivalent of calling malloc(0). Per 7.20.3p1
of the C standard:

"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."

2. NULL can be an integer constant expression with a value of 0, cast to
void* (this is not permitted in C++). In that case, malloc(NULL) is
equivalent to malloc((void*)0), which in turn is equivalent to
malloc((size_t)(void*)0). The result of (size_t)(void*)0 is
implementation-defined; it can be any valid size_t value. On a great
many implementations, it will be 0, but there are real implementations
where it might not be, and portable code should not count on that.

free(NULL) is much simpler. Per 7.20.3.2p2 of the C standard: "If ptr is
a null pointer, no action occurs.".

The C++ standard incorporates by reference most of the C standard
library's description. The only changes it makes are to specify that
malloc() does not call ::eek:perator new(), and free() does not call
::eek:perator delete().
 
A

Anubis

Ron said:
#define NULL 0 // my favorite
#define NULL (0L) // unfortunately also quite common

// the following are legal but weird.
#define NULL (!true)
#define NULL '\0'
#define NULL (5 - 4 - 1)*(34L)/true

I sometimes see

#define NULL ((void*)0)
 
A

Alf P. Steinbach

I sometimes see

#define NULL ((void*)0)

In C, perhaps, not in C++.

Unless you have a _very_ old, non-conforming compiler.

It would be nice if C++ not only allowed that (which it doesn't) but
required it, so that certain errors could be detected, but alas...
 
D

Dylan Nicholson

Steve Clamage said:
The net result of these rules is that you can always call free (once) with the
result you got from malloc.
So I take it MSVC 6's crash on:

char* x = new char[0];
delete [] x;

is most definitely non-compliant...?

Dylan
 
L

lawrence.jones

In comp.std.c Steve Clamage said:
I don't find anything in either standard that disallows always returning the
same non-null address for malloc(0), as long as that address is not othewise used.

C99 7.20.3:

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.

C90 contained slightly different language that was more easily misread,
but the intent was the same.

-Larry Jones

It's either spectacular, unbelievable success, or crushing, hopeless
defeat! There is no middle ground! -- Calvin
 
S

Stephen Clamage

C99 7.20.3:

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.

C90 contained slightly different language that was more easily misread,
but the intent was the same.

Yes, and as I said, I don't see anything that prohibits always
returning the same non-null address.

Suppose the malloc/free implementation reserves one byte, malloc(0)
always returns the address of that byte, and free() of that address is
a no-op. I don't see any rule violation.
 
S

Stephen Clamage

Steve Clamage said:
The net result of these rules is that you can always call free (once) with the
result you got from malloc.
So I take it MSVC 6's crash on:

char* x = new char[0];
delete [] x;

is most definitely non-compliant...?

Bear in mind the following differences:

A new-expression like
new T // T is some type
new T[size}
is a syntactical construct that causes memory to be allocated by the
memory allocation function associated with type T, followed by
contructor invocation(s) for the allocated object(s).

The C++ standard library contiains six different overloads of operator
new, a function that can be called explicitly to allocate raw memory.
You can also write your own overloads, and replace some of the default
versions. The rules are given in the C++ standard section 18.4.1 and
3.7.3. A new-expression invokes some version of operator new, as
explained in section 5.3.4.

C++ also inherits library functions malloc and free from C, which can
be called explicitly to manage raw storage. The C++ standard does not
require that malloc (or free) be used in the implementation of new (or
delete) expressions, or of operator new (or operator delete).

The code you show involves a new-expression and a delete-expression,
not direct calls to malloc or free.

I read section 5.3.4 to say that the expression
new T[0]
is ill-formed, for any type T. The standard requires a strictly
positive value for the constant-expression giving the array size. But
I tried a couple of compilers at full warning levels, and neither
complained about new char[0].

If the code is invalid, the standard imposes no requirements on the
behavior of the program. But it seems to me that an implemention
allowing the expression should also allow deleteing the pointer that
was returned.

Calling the operator new function explicitly is a different story,
however. The expression
operator new(0)
is valid. If the operation succeeds, it must return a unique address
for each call, which can be passed to the corresponding operator
delete().
 
K

Keith Thompson

Steve Clamage said:
The net result of these rules is that you can always call free
(once) with the result you got from malloc.
So I take it MSVC 6's crash on:

char* x = new char[0];
delete [] x;

is most definitely non-compliant...?

I'm posting in comp.std.c. From that point of view, I'm not sure
whether crashing (at run-time?) on a syntax error is non-compliant.
As long as it generates a diagnostic during compilation, it's probably
all right.

As far as C++ is concerned, I don't know whether the delete []
operator follows the same rules as free(). I've redirected followups
to comp.lang.c++.
 
V

Victor Bazarov

Keith Thompson said:
Steve Clamage said:
The net result of these rules is that you can always call free
(once) with the result you got from malloc.
So I take it MSVC 6's crash on:

char* x = new char[0];
delete [] x;

is most definitely non-compliant...?

I'm posting in comp.std.c. From that point of view, I'm not sure
whether crashing (at run-time?) on a syntax error is non-compliant.
As long as it generates a diagnostic during compilation, it's probably
all right.

As far as C++ is concerned, I don't know whether the delete []
operator follows the same rules as free(). I've redirected followups
to comp.lang.c++.

If the expression in brackets in 'new' evaluates to 0, the pointer
returned is not a null pointer and is different from an address of
any other object in the program.

If a pointer was obtained from new[] (in a normal way, that is), it
has to be deletable with delete[].

According to those two statements, the code "Dylan" asked about is
fine as long as it's part of a function. It's not a valid program
by itself, though. More questions on VC++'s behaviour should be
addressed to microsoft.public.vc.language

V
 
K

kanze

2. NULL can be an integer constant expression with a value of 0, cast
to void* (this is not permitted in C++). In that case, malloc(NULL) is
equivalent to malloc((void*)0), which in turn is equivalent to
malloc((size_t)(void*)0). The result of (size_t)(void*)0 is
implementation-defined; it can be any valid size_t value. On a great
many implementations, it will be 0, but there are real implementations
where it might not be, and portable code should not count on that.

However, the conversion of ((void*)0) to an integral type requires an
explicit cast. If this is the definition of NULL, then malloc(NULL)
should not compile.
free(NULL) is much simpler. Per 7.20.3.2p2 of the C standard: "If ptr
is a null pointer, no action occurs.".
The C++ standard incorporates by reference most of the C standard
library's description. The only changes it makes are to specify that
malloc() does not call ::eek:perator new(), and free() does not call
::eek:perator delete().

Yes, but the removal of the liberty to define NULL as ((void*)0) means
that in C++, malloc(NULL) is always legal, where as in C, there are
implementations where it may fail.
 
D

Douglas A. Gwyn

Stephen said:
Yes, and as I said, I don't see anything that prohibits always
returning the same non-null address.

Since Standard C doesn't include 0-sized objects, if there
is a successful malloc(0) in a conforming implementation,
the associated object will occupy at least one byte,
although a s.c. program isn't allowed to access it.
It would be folly for an implementation to return a pointer
to *the same* 0-sized region for multiple concurrent live
allocations, because those allocations can be free()d and
how then would it know when the last free() occurs (unless
it adds the overhead of a reference count, which would have
no other purpose).
 
L

lawrence.jones

In comp.std.c Stephen Clamage said:
Yes, and as I said, I don't see anything that prohibits always
returning the same non-null address.

It says that malloc(0) behaves like, for example, malloc(1). Do you
think that malloc(1) is allowed to return the same value all the time?

-Larry Jones

They say winning isn't everything, and I've decided
to take their word for it. -- Calvin
 
K

kanze

[...]
I read section 5.3.4 to say that the expression
new T[0]
is ill-formed, for any type T. The standard requires a strictly
positive value for the constant-expression giving the array size.

I'm not sure. I presume you are referring to §5.3.4/6: "Every
_constant-expression_ in a _direct-new-declarator_ shal be an integral
constant expression evaluating to a strictly positive value." The
following sentence reads "The _expression_ in a _direct-new-declarator_
shall have integral type with a non-negative value." The grammar at the
top of §5.3.4 reads:

[...]
direct-new-declarator:
[ expression ]
direct-new-declarator [ constant-expression ]

Because of the hypen, and because the expression is written in italics,
I would interpret "constant-expression" in the first quote to refer to
the gramatical construct in the second production for
direct-new-declarator, and not to be the equivalent of a simple
"constant expression". In "new char[0]", the [0] matches the first
production above, and not the second, so the constraints of "expressin"
in §5.3.4/6 apply: it must have a non-negative value (but 0 is OK).

In this case, §5.3.4/7 applies: "When the value of the expression in a
direct-new-declarator is zero, the allocation function is called to
allocate an array with no elements. The pointer returned by the
new-expression is non-null."
But I tried a couple of compilers at full warning levels, and neither
complained about new char[0].
If the code is invalid, the standard imposes no requirements on the
behavior of the program. But it seems to me that an implemention
allowing the expression should also allow deleteing the pointer that
was returned.

The closest I could find is §5.3.5/2: "[...] In the second alternative
(delete array), the value of the operand of delete shall be the pointer
value which resulted from a previous array new-expression." I can find
nothing which requires that the number of elements be greater than 0, so
I would assume that the delete is legal.

I might add that, unlike the poster you were responding to, when I
tried:

char* x = new char[0] ;
delete [] x ;

with VC++ 6.0, it worked as expected.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,427
Latest member
HildredDic

Latest Threads

Top