dagger said:
Hi there. I'm using C under FreeBSD with the gcc compiler and am having a
bit of trouble using the calloc and realloc calls.
As an example the code snippet:
#include <stdio.h>
int main() {
char *ptr;
ptr = (char *) calloc(1, sizeof(char));
A few notes here: first, sizeof(char) is a fancy way of writing 1.
Second, calloc() is not a useful as it seems. Strictly speaking, it may
not give the objects you allocate the value you expect. This is
particularly true for floating point and pointer types. I need to check
the standard to be sure, but I've been told that all-bits-zero is not
guaranteed to be the representation of 0 for any type other than the
character types.
Finally, casting the return from malloc & friends is not recommended,
and your example seems to demonstrate one of the reasons why. You forgot
to #include <stdlib.h>, which means that there is no prototype in scope
for calloc. This in turn means that the compiler assumed (incorrectly) a
return type of int. ints and pointers may not be returned the same way,
so the pointer that calloc returned might be lost, and ptr might be
assigned garbage. Without the cast, the compiler would have been
required to warn you about the conversion from int to a pointer. With
the cast, there is no such guarantee.
Consider using the comp.lang.c-approved idiom for calling malloc & friends:
ptr = calloc(1, sizeof *ptr);
This has number of advantages. The most important are that it doesn't
mask the error mentioned above, it's largely self-maintaining if the
type of ptr changes (for example, of you later choose to support
internationalization using the type wchar_t instead of char), and it's
more difficult to screw up than other idioms.
printf( "initial size (1 char) = %d\n", sizeof(ptr) );
There are at least 2 apparent problems here. First, you seem to be
expecting sizeof to tell you how many characters you've allocated. It
cannot do that. sizeof is purely a compile-time construct. Here it will
give the size of the pointer ptr. If you want the size of a dynamically
allocated object, you need to keep track of it yourself.
The other problem is that you are using the wrong format specifier. %d
can never be an appropriate format specifier for type size_t. %d is ONLY
for type (signed) int. size_t cannot be an alias for (signed) int
because size_t must be unsigned.
Keep in mind that printf() is stupid. It can't determine the types of
the objects you pass to it. It relies completely on you telling it what
the types are. If you lie, all bets are off. Stack corruption leading to
a program crash or worse is a likely result. Always double-check your
format strings.
For size_t, you can cast to unsigned long and print using %lu. This is
mostly safe, but could potentially give incorrect results in C99, if the
size_t value exceeds the range of unsigned long.
ptr = (char *) realloc(ptr, sizeof(char)*10);
This is not a safe way of using realloc. If it fails and returns NULL,
you leak whatever memory you had already allocated. To realloc safely,
store the result into a temporary pointer, then assign into your
original pointer only if the result is non-NULL.
Also, all the notes about calloc apply here as well (except that realloc
doesn't initialize the bytes to all-bits-0).
printf( "new size (10 chars) = %d\n", sizeof(ptr) );
Same problems as the previous printf().
return 0;
}
and yet when I run it I get a size of 4 for each printf even though
initially I allocated only the size of 1 char, and after reallocation there
should be room for 10 bytes...? Or where am I making a mistake in my
reasoning?
Yes. You are printing the sizeof a pointer, not a dynamically allocated
object. C provides no way of determining the size of a dynamically
allocated object, post-allocation.
-Kevin