Questions Regarding Null and Casting

B

BigChuck19

My textbook asserts that when checking if sufficient memory was allocated
for a
dynamic variable using malloc(), a test should be made to determine
whether
sufficient memory was actually allocated. I understand the concept of
checking
if the memory was allocated; the code confuses me, however. E.g., a
fragment
of code from the book is:

grades = (int *) malloc(numgrades * sizeof(int));
if (grades == (int *) NULL) {
printf("Failed to allocate grades array");
exit(1);

}

My question concerns the use of the cast (int *). The book states that
one
must write " if (grades == (int *) NULL) " because if there is
insufficient
memory available, malloc() returns NULL, which is then cast into a
pointer to
an integer by the (int *) preceding the call to malloc(). I do not
understand
how NULL can be cast into anything, though, since I thought NULL was the
constant 0, or I guess its value is the constant 0. To check if malloc()
returns NULL or not, why couldn't one write " if (grades == NULL) ". I
guess
the answer is that you can't write that because NULL was cast as a
pointer to
an integer in the previous statement. But what does it matter which data
type
NULL points to, as long as you determine that the address stored in
grades is
NULL?

The use of a cast on NULL raises a few more questions. Say I create a
character array called array. After initializing all its entries, I then
want
to clear the entire array by making each entry hold the null character. I
could write something like the following to accomplish this:

for(i = 0; i < MAXTENTRIES; i++)
array = '\0';

Does the following loop perform the identical operation?

for(i = 0; i < MAXENTRIES; i++)
array = (char) NULL;

And I assume if the preceding code is valid, then one can cast NULL as
any data
type; for instance,

for(i = 0; i < MAXENTRIES; i++)
array = (int) NULL;

would assign each entry the value of zero?

I am confused about the definition of NULL and the use of NULL; is it
only used
when using pointers? I am not sure, since the use of a cast on NULL
seems to
indicate that one can make NULL any data type.

My final question concerns the use of NULL with a structure.
If I define a structure, say,

typedef struct house {
int floors;
char owner[MAXSIZE];

} House;

and then declare h to be a variable of type house

House h;

Now does

h = (House) NULL;

have any meaning?? If so, what does the statement do?
Thanks for your help

Chuck
 
I

Ian Collins

My textbook asserts that when checking if sufficient memory was allocated
for a
dynamic variable using malloc(), a test should be made to determine
whether
sufficient memory was actually allocated. I understand the concept of
checking
if the memory was allocated; the code confuses me, however. E.g., a
fragment
of code from the book is:

grades = (int *) malloc(numgrades * sizeof(int));

grades = malloc(numgrades * sizeof(*)grades);

Would have been better.
if (grades == (int *) NULL) {
printf("Failed to allocate grades array");
exit(1);

}

My question concerns the use of the cast (int *). The book states that
one
must write " if (grades == (int *) NULL) " because if there is
insufficient
memory available, malloc() returns NULL, which is then cast into a
pointer to
an integer by the (int *) preceding the call to malloc().

The cast is both superfluous and in that case, confusing.

if (grades == (NULL)

is all that is required.

The use of a cast on NULL raises a few more questions. Say I create a
character array called array. After initializing all its entries, I then
want
to clear the entire array by making each entry hold the null character. I
could write something like the following to accomplish this:

for(i = 0; i< MAXTENTRIES; i++)
array = '\0';

Does the following loop perform the identical operation?

for(i = 0; i< MAXENTRIES; i++)
array = (char) NULL;


In practice, yes. But it is a confusing way of writing (and the cast is
superfluous again).
And I assume if the preceding code is valid, then one can cast NULL as
any data
type; for instance,

for(i = 0; i< MAXENTRIES; i++)
array = (int) NULL;

would assign each entry the value of zero?


There could exist systems where NULL isn't zero...
I am confused about the definition of NULL and the use of NULL; is it
only used
when using pointers?

That is is idiomatic use. Use NULL for pointers and 0 elsewhere.

I am not sure, since the use of a cast on NULL
seems to
indicate that one can make NULL any data type.

A cast is the C equivalent of a sledge hammer. If you want to force a
square peg in round hole, use a big hammer.
My final question concerns the use of NULL with a structure.
If I define a structure, say,

typedef struct house {
int floors;
char owner[MAXSIZE];

} House;

and then declare h to be a variable of type house

House h;

Now does

h = (House) NULL;

have any meaning??

No, it isn't valid.
 
K

Keith Thompson

BigChuck19 said:
My textbook asserts that when checking if sufficient memory was
allocated for a dynamic variable using malloc(), a test should be made
to determine whether sufficient memory was actually allocated. I
understand the concept of checking if the memory was allocated; the
code confuses me, however. E.g., a fragment of code from the book is:

grades = (int *) malloc(numgrades * sizeof(int));
if (grades == (int *) NULL) {
printf("Failed to allocate grades array");
exit(1);

}

This is rather poor code. I presume that grades is declared as:
int *grades;
which should have been shown along with the fragment.

Both casts are unnecessary, and can hide errors. For an explation, see
section 7 of the comp.lang.c FAQ, <http://www.c-faq.com/>.

Rather than enumerating each problem (I see nearly one per line),
here's how I'd write it:

grades = malloc(numrades * sizeof *grades);
if (grades == NULL) {
fprintf(stderr, "Failed to allocate grades array\n");
exit(EXIT_FAILURE);
}
My question concerns the use of the cast (int *). The book states
that one must write " if (grades == (int *) NULL) " because if there
is insufficient memory available, malloc() returns NULL, which is then
cast into a pointer to an integer by the (int *) preceding the call to
malloc().

The cast is an explicit conversion. It's unnecessary because the value
of NULL will be implicitly converted to the type of grades (int*) before
it's compared.

It's more accurate to say that malloc() returns a null pointer. NULL
is a macro that expands to a "null pointer constant".
I do not understand how NULL can be cast into anything,
though, since I thought NULL was the constant 0, or I guess its value
is the constant 0.

NULL expands to a null pointer constant. It could be just a literal 0,
or the expression ((void*)0), or any of a number of other possibilities.
You don't need to care exactly what it expands to, just that evaluating
it *in a pointer context* yields a null pointer value.
To check if malloc() returns NULL or not, why
couldn't one write " if (grades == NULL) ".

You can and should.
I guess the answer is
that you can't write that because NULL was cast as a pointer to an
integer in the previous statement. But what does it matter which data
type NULL points to, as long as you determine that the address stored
in grades is NULL?

The type of any pointer expression does matter a great deal. But in
this case, there's a special-case rule that says a null pointer constant
will be implicitly converted to an appropriate pointer type.
The use of a cast on NULL raises a few more questions. Say I create a
character array called array. After initializing all its entries, I
then want to clear the entire array by making each entry hold the null
character. I could write something like the following to accomplish
this:

for(i = 0; i < MAXTENTRIES; i++)
array = '\0';
Ok.

Does the following loop perform the identical operation?

for(i = 0; i < MAXENTRIES; i++)
array = (char) NULL;


It might, depending on how your implementation chooses to define NULL,
but it's a really bad idea. NULL should be used *only* when you want a
null pointer value. A null character is a very different thing.

(Unfortunately, on most systems the compiler won't warn you about
"(char) NULL".
And I assume if the preceding code is valid, then one can cast NULL as
any data type; for instance,

for(i = 0; i < MAXENTRIES; i++)
array = (int) NULL;

would assign each entry the value of zero?


Don't do this either; see above.
I am confused about the definition of NULL and the use of NULL; is it
only used when using pointers? I am not sure, since the use of a cast
on NULL seems to indicate that one can make NULL any data type.

Yes, it should be only used when you want a null pointer value.

Most casts are unnecessary, since C provides implicit conversions for
most of the cases where you need one.
My final question concerns the use of NULL with a structure. If I
define a structure, say,

typedef struct house {
int floors;
char owner[MAXSIZE];

} House;

and then declare h to be a variable of type house

House h;

Now does

h = (House) NULL;

have any meaning?? If so, what does the statement do?

No, it has no meaning at all. It's not legal to cast to a struct
type -- and it wouldn't make any sense to convert NULL to a struct
type anyway.

Incidentally, your original article was very difficult to read. It looks
like you wrote it with fairly long lines, and something split each
line into two parts, resulting in alternating long and short lines
by the time I saw it. Keep each line in a posted article down to
70 or 72 columns.
 
A

Angel

My textbook asserts that when checking if sufficient memory was allocated
for a
dynamic variable using malloc(), a test should be made to determine
whether
sufficient memory was actually allocated. I understand the concept of
checking
if the memory was allocated; the code confuses me, however. E.g., a
fragment
of code from the book is:

grades = (int *) malloc(numgrades * sizeof(int));
if (grades == (int *) NULL) {
printf("Failed to allocate grades array");
exit(1);

}

Must be a very old book, this is a code example from the time when there
was no "void *" type and malloc() returned a value of type "char *".

Nowadays, malloc() returns a value of type "void *", which can be
assigned to any pointer without a cast.


As for NULL, this is a special pointer value that points to no valid
object and can't be dereferenced. On most implementations, this is
indeed a pointer value with all bits zero, but the standard doesn't
guarantee that. Like "void *", NULL is compatible with any pointer
type and no cast is needed.
 
S

Stefan Ram

BigChuck19 said:
grades = (int *) malloc(numgrades * sizeof(int));
if (grades == (int *) NULL) {
printf("Failed to allocate grades array");
exit(1);
}

I'd write this as:

if( !grades )
fprintf( stderr, "Failed to allocate grades array." ); else ...

. I try to avoid »exit« (to show how this is done, one would
need more context, but see, for example, the program in

http://www.purl.org/stefan_ram/pub/windows_system_programming

). In library-grade code, one also would avoid

- programmer's jargon (»array«) in error messages
(a user might not know what an »array« is),

- binding to a specific environment (»stderr« assumes
a console environment), and

- binding to a specific user language (English). So

if( !grades )env->message( ERROR_NOMEM ); else ...

IIRC (can't access my reference sources right now)
»NULL« is not defined in C (except, when one also has

#include <stdlib.h>

before), so I prefer »0«, or avoid it altogether as above.
 
J

J. J. Farrell

BigChuck19 said:
My textbook asserts

Others have given good answers to your questions. Could you tell us the
title and author of the book please. Once you've done so, please destroy
or hide it and get a book written by someone who has a clue about C.

Telling you to cast the return value from malloc() could be explained by
the book having been written before 1989, but there's no excuse for
telling you to cast NULL in that situation.
 
K

Keith Thompson

Angel said:
Must be a very old book, this is a code example from the time when there
was no "void *" type and malloc() returned a value of type "char *".

Not necessarily. The code still works, it's just poor style.
Even K&R2 says to cast the result of malloc, though the errata page
says this needs to be rewritten.

[...]
 
K

Keith Thompson

IIRC (can't access my reference sources right now)
»NULL« is not defined in C (except, when one also has

#include <stdlib.h>

before), so I prefer »0«, or avoid it altogether as above.

NULL is defined in several C standard headers, including <stdlib.h>,
<stddef.h>, and <stdio.h>. Since the program calls printf(),
it's safe to assume that <stdio.h> is already included.

(Well, actually, it's *not* safe to assume that, especially given
the snippet's other problems, but it *should* be.)

Personally, I prefer to use NULL rather than 0 simply because it's more
explicit.
 
T

Tim Rentsch

Keith Thompson said:
My question concerns the use of the cast (int *). The book states
that one must write " if (grades == (int *) NULL) " because if there
is insufficient memory available, malloc() returns NULL, which is then
cast into a pointer to an integer by the (int *) preceding the call to
malloc().

The cast is an explicit conversion. It's unnecessary because the value
of NULL will be implicitly converted to the type of grades (int*) before
it's compared. [snip]

Just an amusing note here. 6.5.9p4 says:

Otherwise, at least one operand is a pointer. If one
operand is a pointer and the other is a null pointer
constant, the null pointer constant is converted to the type
of the pointer. If one operand is a pointer to an object or
incomplete type and the other is a pointer to a qualified or
unqualified version of void, the former is converted to the
type of the latter.

If NULL is defined as '(void*)0', then both of the last two
sentences apply, and each operand is converted to the type
of the other.
 
S

Shao Miller

My final question concerns the use of NULL with a structure.
If I define a structure, say,

typedef struct house {
int floors;
char owner[MAXSIZE];

} House;

and then declare h to be a variable of type house

House h;

Now does

h = (House) NULL;

have any meaning?? If so, what does the statement do?
Thanks for your help

A 'struct' is an "aggregate type" but 'NULL' must be a "scalar type", so
no. This restriction doesn't have anything to do with 'NULL'. The
type-name in a cast must be a scalar type, no matter the value being cast.
 

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
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top