Re: Newbie question about malloc

From: Kevin Goodsell (usenet1.spamfree.fusion_at_neverbox.com)
Date: 12/17/03


Date: Wed, 17 Dec 2003 20:24:30 GMT

George wrote:

> Hello to everybody !!!
> Why am i getting always:
> size=4 (i understand this)
> length=3 (?????)
> when i'm executing the following programm?
> Should'nt i get always the number of bytes
> allocated by "malloc" ??? (in this example 16)
> Why is this happening?

Here's a few more details about things that were glossed over in some of
the replies.

>
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> main()

int main(void)

"Implicit int" no longer exists in C. Under the latest standard you must
specify the return type for all functions. In the case of main(), the
return type must be 'int' (contrary to popular belief, 'void' has never
been an acceptable return type for main() in any version of C).

As for the voided parameter list, you should never use empty parameter
lists in C unless you really know what you are doing. In C (unlike C++)
an empty parameter list is very different from a void parameter list,
and empty parameter lists can be very dangerous.

> {
> char* name;
> name=(char*)malloc(16);

It's generally recommended to NOT cast the return from malloc(). At
least one very notable book on C incorrectly states that the cast is
required, but it is not.

The main reasons to not cast are: 1) It can suppress a useful
diagnostic, thus hiding an error in the code (the error in question is a
failure to provide a correct declaration for malloc() - the result of
forgetting to #include <stdlib.h>). 2) The cast is an extra maintenance
concern. If the type of 'name' were to change (say, to unsigned char, or
wchar_t), you'd need to locate and fix every cast expression involving
'name'.

The comp.lang.c-approved method of calling malloc() looks like this:

name = malloc(16 * sizeof(*name) );

(Alternatively, remove the parens on the sizeof operator - they aren't
necessary in this case.)

This form automatically adjusts to changes in the type of 'name', and is
generally more difficult to get wrong than other forms.

> if (!name)
> {
> printf("Mem Alloc Error.");

No one else mentioned this (that I saw), but a portable program needs to
terminate its output with a newline:

printf("Mem Alloc Error.\n");

It's not uncommon for the last line of output to mysteriously disappear,
or to appear with the system prompt tagged onto the end if it is not
correctly terminated.

Also, error output should usually go to the standard error stream:

fprintf(stderr, "Mem Alloc Error.\n");

> exit (0);
> }
> printf("size=%d \n",sizeof(name));
> printf("length=%d",strlen(name));

Both of these printfs are wrong. As before, you should end your lines
with a newline character, but more importantly you have used the wrong
format specifiers. This can be a very serious problem, and most
compilers won't warn you about it.

Both sizeof and strlen give a result of type size_t. size_t is an
unsigned type. The %d format specifier is for (signed) int ONLY. It's
possible that size_t could be an alias for unsigned int, but not signed
int. Therefore, %d can never be the correct format specifier for a size_t.

Keep in mind that printf is stupid. It cannot determine the actual types
of the objects you pass it. It relies completely on you telling it the
correct type. If you lie to it about the type, all bets are off. Stack
corruption leading to a program crash or worse is very likely. Even if
it "seems to work", bad things may be happening that aren't easily
observed - mysterious, very difficult to find bugs can pop up. The
behavior can appear random, and may be completely different on a
different system, or when using a different compiler.

In other words, it's very important to get your format strings right.
Always double-check them.

In this case, there probably isn't a format string you can use for
size_t. C99 introduced %zu for this purpose, but you probably aren't
using a C99 compiler. The safest way to print a size_t is to cast it to
a known type first:

printf("length=%lu\n", (unsigned long)strlen(name));

This is guaranteed safe in C versions prior to C99, since size_t can be
no wider than unsigned long. As of C99, size_t can be wider (it can even
be wider than the new 'long long' type, I think), so this is not
completely safe under C99 (it is safe in the sense that it cannot lead
to undefined behavior, but the results may be inaccurate).

-Kevin

-- 
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.


Relevant Pages

  • Re: Four or Two Bytes?
    ... Martin writes: ... You should cast the value to int (one of the few cases ... when C99 is widely implemented and that code is reasonably portable. ...
    (comp.lang.c)
  • Re: doubt regarding sizeof operator
    ... int main ... This looks like a typo in a program that prints the size of floating point ... The format specifier for size_t is ... but it is c99 specific. ...
    (comp.lang.c)
  • Re: what will happen after i use free()???
    ... Inserting a cast before malloc is not needed, ... 56 bits while int is only 48 bits. ... So casting that value requires some ... Use cast only if you are absolutely sure that yor really needs the ...
    (comp.lang.c)
  • Re: about the array
    ... 3- If you cast to the wrong type by accident, ... are malloc and free. ... the compiler should issue a diagnostic - gcc ... unknown set of arguments, and return an int. ...
    (comp.lang.c)
  • Re: Simple Casting Question
    ... only in the form (int to float),,, ... or just casting identical types, so I hope that I can avoid some ... None of the conversions you describe ... In most cases where a cast is used, ...
    (comp.lang.c)

Loading