[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Questions Regarding Null and Casting

BigChuck19

6/3/2011 9:53:00 PM

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[i] = '\0';

Does the following loop perform the identical operation?

for(i = 0; i < MAXENTRIES; i++)
array[i] = (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[i] = (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
12 Answers

Ian Collins

6/3/2011 10:14:00 PM

0

On 06/ 4/11 09:52 AM, BigChuck19 wrote:
> 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.

<snip>

> 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[i] = '\0';
>
> Does the following loop perform the identical operation?
>
> for(i = 0; i< MAXENTRIES; i++)
> array[i] = (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[i] = (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.

--
Ian Collins

Ian Collins

6/3/2011 10:16:00 PM

0

On 06/ 4/11 10:13 AM, Ian Collins wrote:
> On 06/ 4/11 09:52 AM, BigChuck19 wrote:
>> 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);

Oops,

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

or

grades = malloc(numgrades * sizeof *grades);

> Would have been better.

--
Ian Collins

Keith Thompson

6/3/2011 10:26:00 PM

0

BigChuck19 <bc19@mailinator.com> writes:
> 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-fa....

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[i] = '\0';

Ok.

> Does the following loop perform the identical operation?
>
> for(i = 0; i < MAXENTRIES; i++)
> array[i] = (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[i] = (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.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

pete

6/3/2011 10:39:00 PM

0

BigChuck19 wrote:

> To check if malloc() returns NULL or not,
> why couldn't one write " if (grades == NULL) ".

One could; there's absolutely nothing wrong with it.


> 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[i] = '\0';
>
> Does the following loop perform the identical operation?
>
> for(i = 0; i < MAXENTRIES; i++)
> array[i] = (char) NULL;

No.


> I am confused about the definition of NULL and the use of NULL;

It is best to use NULL in a pointer context
regardless of how any particular implementation defines NULL.

NULL expands to an implementation-defined null pointer constant.

An integral constant expression with the value 0, or such an
expression cast to type void * , is called a null pointer constant.

An integral constant expression shall have integral type and shall
only have operands that are integer constants, enumeration constants,
character constants, sizeof expressions, and floating constants that
are the immediate operands of casts. Cast operators in an integral
constant expression shall only convert arithmetic types to integral
types, except as part of an operand to the sizeof operator.

--
pete

Angel

6/3/2011 11:23:00 PM

0

On 2011-06-03, BigChuck19 <bc19@mailinator.com> wrote:
> 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.


--
"C provides a programmer with more than enough rope to hang himself.
C++ provides a firing squad, blindfold and last cigarette."
- seen in comp.lang.c

ram

6/3/2011 11:26:00 PM

0

BigChuck19 <bc19@mailinator.com> writes:
>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_p...

). 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. Farrell

6/3/2011 11:45:00 PM

0

BigChuck19 wrote:
> 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.

Keith Thompson

6/4/2011 12:25:00 AM

0

Angel <angel+news@spamcop.net> writes:
> On 2011-06-03, BigChuck19 <bc19@mailinator.com> wrote:
>> 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 *".

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.

[...]

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson

6/4/2011 12:27:00 AM

0

ram@zedat.fu-berlin.de (Stefan Ram) writes:
[...]
> 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.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

pete

6/4/2011 1:13:00 AM

0

Stefan Ram wrote:
>
> BigChuck19 <bc19@mailinator.com> writes:
> >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 ...

That string literal might be better
if it had a newline character at the end.

--
pete