Newbie question about malloc

G

George

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?


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()
{
char* name;
name=(char*)malloc(16);
if (!name)
{
printf("Mem Alloc Error.");
exit (0);
}
printf("size=%d \n",sizeof(name));
printf("length=%d",strlen(name));
free(name);
return 0;
}

Many thanks in advance,George
 
G

grobbeltje

George said:
size=4 (i understand this)
length=3 (?????)
as far as i can see, you never define what is inside 'name',
so it can contain whatever it wants. strlen searches for the
first '\0' and happens to find one at the 4th positions (lucky you!).
main()
{
char* name;
name=(char*)malloc(16);
if (!name)
{
printf("Mem Alloc Error.");
exit (0);
}
printf("size=%d \n",sizeof(name));
printf("length=%d",strlen(name));
free(name);
return 0;
}

you could try 'name=calloc(16,sizeof(char));' instead of the line
with malloc, it should make strlen return 0.

good luck!
grobbeltje.
 
L

Lew Pitcher

George said:
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" ???

No. See below
(in this example 16)
Why is this happening?


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()
{
char* name;
name=(char*)malloc(16);
if (!name)
{
printf("Mem Alloc Error.");
exit (0);
}
printf("size=%d \n",sizeof(name));

sizeof is a C operator that results in a size_t value indicating the size of
the selected data item or type. You got 4 here because the C compiler you
are using implements character pointers as 4-byte quantities.
printf("length=%d",strlen(name));

strlen() is a C standard function that counts characters. It starts counting
at the address pointed to by it's argument, and stops when it encounters the
first '\0' character. The resulting value may have no correspondance to the
size of the memory block allocated by your malloc() call.

Your use here of strlen() has two flaws:
1) You haven't initialized the block of memory pointed to by name, thus the
memory contains unknown data. It is a programming error to attempt to
call strlen() against an uninitialized data area.

2) the returned value from strlen() does not represent the length of
allocated memory. Instead, it represents the length of the string
pointed to by it's argument. AFAIK, there is /no/ standard function that
will accept a pointer to a malloc()ed array, and return the length of the
malloc().
 
M

Mark A. Odell

(e-mail address removed) (George) wrote in

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?


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main()

int main(void)
{
char* name;
name=(char*)malloc(16);

name = malloc(16); /* no cast in C, only C++ */
if (!name)
{
printf("Mem Alloc Error.");
exit (0);
return EXIT_FAILURE; /* why bother with exit */
printf("size=%d \n",sizeof(name));
printf("size of pointer 'name'=%u\n", (unsinged int) sizeof name);
printf("length=%d",strlen(name));

printf("length of initialized string is bogus=%u\n",
(unsigned int) strlen(name));
free(name);
return 0;
}

Many thanks in advance,George

Now try again.

#define NEEDED_SIZE 1024

int main(void)
{
int failure = EXIT_FAILURE;
char *pName = malloc(NEEDED_SIZE);

if (pName)
{
/* Initialize to something
*/
strcpy(pName, "Hello world");

printf("Size of memblock at pName is %d\n", NEEDED_SIZE);
printf("Len of string in memblock is %u\n",
(unsigned int) strlen(name));

free(pName);
failure = EXIT_SUCCESS;
}

return failure;
}
 
A

Artie Gold

George said:
Hello to everybody !!!
Why am i getting always:
size=4 (i understand this)
length=3 (?????)

See below.
when i'm executing the following programm?
Should'nt i get always the number of bytes
allocated by "malloc" ??? (in this example 16)

No. That's just not how it works. There is no portable way to know how
many bytes were allocated given a pointer to memory.
Why is this happening?


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
int main(void)
{
char* name;
name=(char*)malloc(16);

Lose the cast. It's unnecessary.
if (!name)
{
printf("Mem Alloc Error.");
exit (0);

You probably want:

exit EXIT_FAILURE;

It failed, didn't it?

}
printf("size=%d \n",sizeof(name));

The sizeof() operator returns the size of the object, which, in this
case is an object of type `pointer to char'. On your system that size is
evidently 4.
printf("length=%d",strlen(name));

When you use malloc() to allocate memory, the contents of that memory is
indeterminate -- so looking at it produces undefined behavior. It just
so happens that in this particular case, the fourth `char' was 0 (or
'\0'). Since you invoked undefined behavior, the result could have been
*anything*, even things much too horrible to mention at this hour of the
morning.
free(name);
return 0;
}

Many thanks in advance,George

Fair enough. ;-)

HTH,
--ag
 
C

Christopher Benson-Manica

Lew Pitcher said:
You got 4 here because the C compiler you
are using implements character pointers as 4-byte quantities.

Just FMI, is this a choice of the compiler or the implementation?
The resulting value may have no correspondance to the
size of the memory block allocated by your malloc() call.

No "may" about it - the values are independent, yes?
 
L

Lew Pitcher

Christopher said:
Just FMI, is this a choice of the compiler or the implementation?




No "may" about it - the values are independent, yes?

Yes, mostly.

I thought of a caveat that I didn't want to write for fear of confusing the
issue, and not phrasing it correctly enough for the pedants in the group.

The caveat is that a programmer could write

strcpy(name,pointer_to_initialization_string);

(given proper definition and values for name and
pointer_to_initialization_string) and initialize the memory block.

Given that this results in /correct/ initialization, then strlen() would
result in a value less than the size of the allocated memory block.

However, assuming that this results in an /incorrect/ initialization (if,
for instance, pointer_to_initialization_string points to a string that is
larger than the target block of memory), then the results of strlen() will
be somewhat indeterminate (I'll let the language lawyers here decide whether
it would be an error condition, or "implementation defined" or "undefined").
/If/ strlen() returns a value in this case, it /may/ have some
correspondance to the size of the memory block allocated by the malloc() call.

And that's what I didn't want to expound on. <grin>
 
L

Lew Pitcher

Christopher said:
Just FMI, is this a choice of the compiler or the implementation?

Good question. I fear that I don't have a definitive answer for it though.

I would expect that the compiler has some restrictions wrt the target
platform, including restrictions on the size of pointers. Pointer sizes
/can/ vary at the hardware, either by type of data pointed to, or as a
result of execution environment limitations. The compiler may have to make
a choice as to /which/ pointer size to allocate a pointer to. If there's no
choice for the compiler to make, I'd expect that the pointer size is
dictated by the implementation.
 
K

Kevin Goodsell

George said:
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
 
C

Chris Torek

Should'nt i get always the number of bytes
allocated by "malloc" ??? (in this example 16)

In addition to the other responses so far, I might point out that
while the *call* says:

malloc(16)

there is no guarantee that you actually *got* 16 bytes, even if
the returned pointer is NULL. Suppose, for instance, that for some
reason your implementation has chosen never to hand out less than
some minimum number of bytes at a time via malloc(). The malloc()
on that system might include code like:

if (size < MIN_MALLOC_SIZE)
size = MIN_MALLOC_SIZE;

near the top, with MIN_MALLOC_SIZE greater than 16. Thus, you
might have gotten 20, 24, 32, or even more bytes. (Real malloc()s
often do contain this kind of code, so this is not a purely
theoretical issue.)

C has no "how much did I malloc() with this non-NULL pointer that
is suitable for use as an argument to free()" function. Such a
function might be useful, but if one were to be proposed for addition
to a future C standard (or any other "non-C" standard that acts as
a sort of add-on, such as the POSIX system-function bindings like
readdir() and such), we would have to decide: "Does this function
return the argument passed to malloc(), or does it return the actual
number of bytes malloc() handed out even if that was a larger
number?"

Also, this:
char* name; ...
printf("size=%d \n",sizeof(name));

printed 4. (Note that strlen() returns a size_t value, which is not
an int value; anything might have been printed, but for luck. Whether
this is "good luck" or "bad luck" depends on one's point of view...)
In a later followup he asked:
... is this a choice of the compiler or the implementation?

The only correct answer to this is "yes", because it might be either
one. :) (I assume here "implementation" really means "hardware
for which the C compiler compiles machine-level code.") Computer
hardware often suggests (with varying degrees of strength) particular
implementations for C code, but C compilers are not required to
produce "sensible" code, merely "code that obeys the requirements
of the C standard". As such, a compiler for a machine with 32-bit
pointers could generate 16-bit-pointer code (that can only address
65536 bytes at a time) and "run" that code via an interpreter that
simulates some other machine that only has 16-bit pointers.

(This, too, is not purely theoretical -- it is how emulators work.
One might either use a cross-compiler that runs native and produces
code for the emulated hardware, or even run under the emulator an
old "native" C compiler that works on the emulated machine. In
the latter case one might reasonably claim that the "machine" really
does have 16-bit pointers; the cross-compiler case is more
interesting, particularly if it is the cross-compiler that emits
the emulator, and can optionally run some code "native" intermixed
with other code "emulated".)
 
B

Ben Pfaff

Christopher Benson-Manica said:
"implementation" means that I'm fuzzy on my terms :) The C compiler
*is* the implementation, then...?

Yes, although the term "implementation" also includes the linker,
the C library, and execution environment (anything else?), or at
least those bits of them visible to a strict conforming program.

C99 only contains the word "compiler" once, and that's in a
footnote so it's not strictly part of the standard.
 
C

Christopher Benson-Manica

Chris Torek said:
(I assume here "implementation" really means "hardware
for which the C compiler compiles machine-level code.")

"implementation" means that I'm fuzzy on my terms :) The C compiler
*is* the implementation, then...?
 
C

Christopher Benson-Manica

Ben Pfaff said:
Yes, although the term "implementation" also includes the linker,
the C library, and execution environment (anything else?), or at
least those bits of them visible to a strict conforming program.

So would you say, then, that the implementation is the set of software
applications (compiler, linker, library, OS, etc.) responsible for
creating executable code (and executing that code) from a C source
file?
 
B

Ben Pfaff

Christopher Benson-Manica said:
So would you say, then, that the implementation is the set of software
applications (compiler, linker, library, OS, etc.) responsible for
creating executable code (and executing that code) from a C source
file?

The standard defines "implementation":

1 implementation
particular set of software, running in a particular
translation environment under particular control options,
that performs translation of programs for, and supports
execution of functions in, a particular execution
environment
 
M

Mark A. Odell

<just-kidding>
Err... Is success really a failure ?-)
</just-kidding>

Yeah, it is kind of confusing. Usually I have a 'failures' return and set
it to 0 for "no failures" and non-zero to indicate a failure. I suppose
exit_code would have been better.
 
M

Mark McIntyre

Mark A. Odell wrote:
(snip)


<just-kidding>
Err... Is success really a failure ?-)
</just-kidding>

Well, MS helpfully define a macro ERROR_SUCCESS in winerror.h.

Which, many would say, perfectly describes Windows...
 
K

Keith Thompson

Christopher Benson-Manica said:
Just FMI, is this a choice of the compiler or the implementation?

That's not really an either/or question; the compiler is part of the
implementation.

It's up to the compiler (more precisely, to the authors of the
compiler) to determine the size of a pointer, but that is influenced,
and often mandated, by the underlying hardware (and, to a lesser
extent, by the operating system).
 
C

Christopher Benson-Manica

Mark McIntyre said:
Well, MS helpfully define a macro ERROR_SUCCESS in winerror.h.

Regrettably, some of the code I'm working with includes ctErrSuccess
in an enumerated error code type...
 

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

Similar Threads

Fibonacci 0
Adding adressing of IPv6 to program 1
C language. work with text 3
malloc and maximum size 56
array-size/malloc limit and strlen() failure 26
MALLOC problem 25
Using fgets 1
malloc() and dinamic data question 4

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top