allocating m bytes dynamically

2

2005

1) If I want to allocate m bytes dynamically would the following do?
2) What is the purpose of the for loop here - assign initial value?

int main(void)
{
int m = 100;
int *ptr = (int *) malloc(m);
for(int i =0; i <10; i++)
{
*ptr++ = i;
}
free(ptr);
}
 
A

Alexander Bartolich

2005 said:
[...]
int main(void)
{
int m = 100;
int *ptr = (int *) malloc(m);
for(int i =0; i <10; i++)
{
*ptr++ = i;
}
free(ptr);
}

This program does not work.

After the loop »ptr« has a different value than before. So you are
calling »free« with a value that was not returned by »malloc«.

--
 
S

santosh

2005 said:
1) If I want to allocate m bytes dynamically would the following do?
2) What is the purpose of the for loop here - assign initial value?

int main(void)
{
int m = 100;
int *ptr = (int *) malloc(m);

Note that in C you don't have to cast the return value of malloc/
calloc/realloc, since conversion to and from a void pointer is
implicit.

And since dynamic allocation could fail for large values, you should
make it a point to always ensure the call succeeded before moving on.
for(int i =0; i <10; i++)
{
*ptr++ = i;

You want:
ptr = i;
 
K

Keith Thompson

2005 said:
1) If I want to allocate m bytes dynamically would the following do?
2) What is the purpose of the for loop here - assign initial value?

You need:

#include <stdlib.h>

If your compiler doesn't warn you that malloc and free are undeclared,
crank up its warning level until it does.
int main(void)
{
int m = 100;
int *ptr = (int *) malloc(m);

Here you (attempt to) allocated 100 bytes worth of ints. How many
ints is that? It depends on how many bytes an int occupies, which
varies from one implementation to another.

If you're going to allocate an array of ints, you almost always want
to specify how many ints to allocate. In this case, you only use 10
of them, so:

int *ptr = malloc(10 * sizeof *ptr);

Using "sizeof *ptr" rather than "sizeof (int)" makes the code more
stable if the type changes.
for(int i =0; i <10; i++)
{
*ptr++ = i;
}
free(ptr);
}

Others have already pointed out the problems here.
 
M

Mark

Richard said:
#define MAX 100

int main(void)
{
size_t num_ints = MAX;
int *ptr = malloc(m * sizeof *ptr);
I guess it should've been:

int *ptr = malloc(num_ints * sizeof *ptr);

?
 
2

2005

2005 said:
1) If I want to allocate m bytes dynamically would the following do?

#include <stdlib.h>

#define MAX 100

int main(void)
{
   size_t num_ints = MAX;
   int *ptr = malloc(m * sizeof *ptr);
   if(ptr != NULL)
   {
     int i = 0;
     while(i < MAX)
     {
       ptr = i;
     }
     /* use those values in other ways
        if you like, and then, when you
        have finished, call free():
      */
     free(ptr);
   }
   return 0;

}

To answer your question, yes, the above will do nicely.
2) What is the purpose of the for loop here - assign initial value?

In your code, the purpose appears to have been to break your program.
(It reassigns ptr, then tries to pass that new value to free(), which
invokes undefined behaviour, as does the call to malloc - the compiler
would have warned you about this if you hadn't hobbled it with a cast).

In the above code, however, the purpose is to assign initial values to
the ints allocated by malloc.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within


Thank you Richard and everyone;

1) Am I correct "free(ptr);" could have been placed after the
bracket ?
2) I put a "printf ("ptr[%d] = %d\n", i, ptr);" after "ptr = i"
- it printed the following - ie from 1 to 5959:

1 ptr[0] = 0
2 ptr[0] = 0
3 ptr[0] = 0
........
5956 ptr[0] = 0
5957 ptr[0] = 0
5958 ptr[0] = // it did not print a value for "i"
5959 Timeout

Why "5959"? Why "Timeout" ? Irrespective of what value MAX is
assigned, it does this! I ran it on codepad.org
 
2

2005

2005 said:
1) If I want to allocate m bytes dynamically would the following do?
2) What is the purpose of the for loop here - assign initial value?
int main(void)
{
        int m = 100;
        int *ptr = (int *) malloc(m);

Note that in C you don't have to cast the return value of malloc/
calloc/realloc, since conversion to and from a void pointer is
implicit.

And since dynamic allocation could fail for large values, you should
make it a point to always ensure the call succeeded before moving on.
        for(int i =0; i <10; i++)
        {
               *ptr++ = i;

You want:
    ptr = i;
        }
        free(ptr);
}


Why "*ptr++ = i" won't work but "ptr = i" will?
 
S

Seebs

Why "*ptr++ = i" won't work but "ptr = i" will?


Pedantically:

The question should be:

Why won't "*ptr++ = i" work, but "ptr = i" will?

In English, word order is changed for questions.


Anyway, the answer is: The original, starting, value of "ptr" was returned
by malloc. To free it, you have to have the UNCHANGED original value. But
if you go through incrementing ptr, then when you leave the loop, you no
longer have the original value of ptr, so you can't correctly free it.

You could also do:

void *ptr_orig;

ptr = malloc(...);
ptr_orig = ptr;
for (blah blah)
*ptr++ = i;
free(ptr_orig);

-s
 
S

santosh

2005 said:
2005 said:
1) If I want to allocate m bytes dynamically would the following do?

#include <stdlib.h>

#define MAX 100

int main(void)
{
   size_t num_ints = MAX;
   int *ptr = malloc(m * sizeof *ptr);
   if(ptr != NULL)
   {
     int i = 0;
     while(i < MAX)
     {
       ptr = i;
     }
     /* use those values in other ways
        if you like, and then, when you
        have finished, call free():
      */
     free(ptr);
   }
   return 0;

}

To answer your question, yes, the above will do nicely.
2) What is the purpose of the for loop here - assign initial value?

In your code, the purpose appears to have been to break your program.
(It reassigns ptr, then tries to pass that new value to free(), which
invokes undefined behaviour, as does the call to malloc - the compiler
would have warned you about this if you hadn't hobbled it with a cast).

In the above code, however, the purpose is to assign initial values to
the ints allocated by malloc.

Thank you Richard and everyone;

1) Am I correct "free(ptr);" could have been placed after the
bracket ?

Which bracket?

In general you can free() a pointer value anytime after it has been
returned by malloc() and friends. But it must be the same value. You
can't modify the value, as you did above, and attempt to free() it. If
you do need to modify, save a copy of the original.

Also, though the storage returned by malloc() and co. will persist
throughout the life of the program, you should keep in mind the
lifetime of the pointer object(s) used to reference the storage, which
might be function scope or block scope.
2) I put a "printf ("ptr[%d] = %d\n", i, ptr);" after "ptr = i"
- it printed the following - ie from 1 to 5959:

1 ptr[0] = 0
2 ptr[0] = 0
3 ptr[0] = 0
.......
5956 ptr[0] = 0
5957 ptr[0] = 0
5958 ptr[0] = // it did not print a value for "i"
5959 Timeout

Why "5959"? Why "Timeout" ? Irrespective of what value MAX is
assigned, it does this! I ran it on codepad.org


Yes, well you assign MAX to num_ints but never use that object. You
instead supply 'm' to malloc(). Where does 'm' come from and what
value does it contain? Are you sure you don't want:

int *ptr = malloc(num_ints * sizeof *ptr);

Also in your loop as given above, 'i' won't magically increment itself
until MAX. You'll have to do so manually. That is why you get the
above output, since 'i' stays at zero.
 
2

2005

Ben said:
<snip>


   if(ptr != NULL)
   {
     int i = 0;
     while(i < MAX)
     {
       ptr = i;
     }

Presumably i should be changed in this loop.  This may explain, in
part, the odd "timeout" message the OP is getting.

Oh yeah. Oops.

Sometimes I do wish people wouldn't take me quite so literally. :)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within


Thanks, Santosh, Richard & Ben,

The issue was missing "i++" - I had actually replaced the "m" with
MAX;
BTW: what is the deal about size_t num_ints = MAX; // MAX is already
defined to be 10 - the code runs w/o that line too.
Also what is this "size_t"?
Also why do you say "malloc() and friends" ?

You can click the link to see/run the code: http://codepad.org/8Z8Q3pdo

Thanks
 
A

Andrew Poelstra

The issue was missing "i++" - I had actually replaced the "m" with
MAX;
BTW: what is the deal about size_t num_ints = MAX; // MAX is already
defined to be 10 - the code runs w/o that line too.

Variables hold values. They're safe. Macros, on the other hand,
make programmers feel nervous sometimes. That's probably all it
was.
Also what is this "size_t"?

size_t is an unsigned integer type that can hold the size of
any object in your C program. It's also what malloc() takes
as an argument.
Also why do you say "malloc() and friends" ?

There is also realloc(), which takes a malloc()'d pointer and
returns one to a bigger size - though be careful when it fails
that you don't lose the original!

And there is calloc(), which allocates memory and 0's it out,
though you again should be careful because for pointers and
floating point values sometimes all 0's is not actually zero.

And there is free(), which is kinda a friend of malloc().
You can click the link to see/run the code: http://codepad.org/8Z8Q3pdo

Your code is here (it's hard to use two programs at once):
#include <stdlib.h>
#define MAX 10

int main(void)
{


// size_t num_ints = MAX;

// comments are dangerous on Usenet because sometimes lines wrap
around and then your code doesn't compile. And some people here
(including myself) don't use compiler modes that support them.
int *ptr = malloc(MAX * sizeof (int));

You can use sizeof directly on *ptr, like so:
int *ptr = malloc(MAX * sizeof *ptr);
This saves you a potential bug if you decide ptr should actually
point to longs or shorts or size_ts or something.
if(ptr != NULL)
{
int i = 0;
while(i < MAX)
{
ptr = i;
printf ("ptr[%d] = %d\n", i, ptr);
i++;

}
/* use those values in other ways
if you like, and then, when you
have finished, call free():
*/

}
free(ptr);
return 0;

}


I'm a little tired, but it looks to me that this code is A-OK.
Congratulations!
 
A

Andrew Poelstra

Thanks Santosh - but why at
http://en.wikipedia.org/wiki/Malloc

they are doing it and kind of making a standard ?

Because on Wiki you get a number of silly psuedo-programmers who
use C++ syntax without realizing that they are in fact using a C
function. (In C++ the cast is necessary. But in C++ the malloc()
is not. :p)
Another question I have is that should
ptr = i; this be ptr = 0; instead?


It depends on what you're doing. I missed the context of your
question, but if you just want to zero out an array of ints
you can save yourself some time and cycles by just using
calloc() in the first place:

int *ptr = calloc(m, sizeof *ptr);

Which will give you the right number of bytes and set them
all to zero.
 
S

Seebs

they are doing it and kind of making a standard ?

"When using C, this is considered bad practice; it is redundant under the C
standard."

They explicitly disclaim that. However, it would be needed in C++, and since
the code there seems to be intended to work as either...

-s
 
S

santosh

2005 said:
Thanks Santosh - but why at
http://en.wikipedia.org/wiki/Malloc

they are doing it and kind of making a standard ?

One good reason to cast the return of malloc() would be when your code
is likely to be compiled with a C++ compiler. In C++, implicit
conversion to and from void is disallowed, so a cast is needed.
Another question I have is that should
ptr = i; this be ptr = 0; instead?


It depends on what you want to do. Your original loop assigned the
value of i to successive elements starting at ptr, but also modified
ptr, which was later passed to free(), so I changed it to analogous
code that didn't modify ptr, so that your free() invocation would not
be UB.
 
S

santosh

2005 wrote:
[...]
Thanks, Santosh, Richard & Ben,

The issue was missing "i++" - I had actually replaced the "m" with
MAX;

Just a minor point. Your malloc() call in the revised code looks like:

int *ptr = malloc(MAX * sizeof (int));

You might consider instead:

int *ptr = malloc(MAX * sizeof *ptr);

This form ensures that sizeof yields the correct size even if the type
of ptr happens to be changed.
BTW: what is the deal about size_t num_ints = MAX; // MAX is already
defined to be 10 - the code runs w/o that line too.

No idea. If the code runs without that line, then why did you include
it?

As an aside, a name like 'num_ints' is more descriptive of purpose
than 'MAX.'
Also what is this "size_t"?

The parameter to malloc() is defined to be of type size_t. This is
because this is the only type in C that is guaranteed to be able to
represent the size of the largest possible object. It's specifically
meant for holding sizes of objects. sizeof also yields a value to type
size_t. It's an unsigned integral type and is usually a typedef for
unsigned long.

So use size_t if the object is specifically for storing the size of
other objects. OTOH, it's a bit inconvenient in some types of looping
constructs and you need to be careful when mixing it with signed
values in expressions.
Also why do you say "malloc() and friends" ?

Just a short way of alluding to the other allocation functions:
calloc() and realloc().
You can click the link to see/run the code: http://codepad.org/8Z8Q3pdo

Note that you've not included the stdio.h header in your code at the
above link, though you use the print() function declared in that
header. You should always include the relevant standard header when
using any function it declares. Not doing so in asking for subtle
problems.
 
P

Phil Bradby

2005 said:
Note that in C you don't have to cast the return value of malloc/
calloc/realloc, since conversion to and from a void pointer is
implicit.

Thanks Santosh - but why at
http://en.wikipedia.org/wiki/Malloc

they are doing it and kind of making a standard ?

Another question I have is that should ptr = i; this be ptr = 0;
instead?


There is an interesting U/B discussion on the talk page of that Wikipedia
article. Maybe someone with clc expertise could help those guys out!

----------------

In the section of this page, Use after free, it is claimed that after a
pointer has been passed to free, that:

Even attempting to print the variable with printf is undefined
behavior (assuming malloc did not return a null pointer); for example:
printf("%p", (void *) ptr); /* Undefined behavior */

Is the behavior really undefined? Assuming that we discount that the
value of the pointer we get back from malloc is undefined, the call to
free() is pass by value. The value of ptr will not change as a result of
passing it to free. The printf() should print the value of the pointer as
it was before the call to free (ie. this is the defined behavior).

The only doubt to this is that, perhaps the original poster was focusing
on the %p format placeholder. The wikipedia article on printf states that
the placeholder specifies:

Print a void * (pointer to void) in an implementation-defined format.

This specification is a little generic (implementation-defined format).
If an implementation were to attempt to "pretty-print" the value pointed
to by ptr, then the assertion of undefined behavior would be reasonable.

I suggest that this is not what is meant by "implementation-defined
format", and that the scope is restricted to an arbitrary formatting of
the value of the pointer itself (not de-referenced). Even if my
suggestion is wrong, I assert that in this example, it is only the use of
the %p placeholder which presents the problem. So the claim that

Even attempting to print the variable with printf is undefined
behavior (assuming malloc did not return a null pointer);

is not correct, because other forms of printf would be defined to print
the value of the pointer as it was before the call to free. Example:

printf("%x", ptr); /* Hex value of ptr */ 148.182.52.148 (talk) 04:28, 27
October 2009 (UTC)

I agree. printf is a bad example because free should not change the
address of the pointer. A better example of an error would be the one
given on page 167 of the 2nd edition of Kernighan and Ritchie. Their
example of an error is trying to free all the elements in a linked list
with this code:
for (p = head; p!=NULL; p = p->next) /*wrong */

free(p);

This is clearly incorrect because after p is freed there is no
assurance that p->next will still point to the next element in the list.
K & R also gives the correct solution to the problem:

for (p = head; p!=NULL; p = q) { /*right */

q = p->next;
free(p);

}
Unless somneone objects I would recommend replacing the printf
example with the example from K & R, which could easily be cited for a
source. Rusty Cashman (talk) 05:25, 3 November 2009 (UTC)

I of course meant to say free should not change the address
pointed to by the ponter not the address of the pointer itself (though
that should be true as well). Rusty Cashman (talk) 06:35, 3 November 2009
(UTC)

Did anyone bother to check the C standard? If you had, you
would see that use of any pointer after free is undefined. Compilers are
free to do whatever they want with them. OrangeDog (τ • ε) 19:46, 5
November 2009 (UTC)

I think that it's better to use Rusty's example and treat the printf
example as unknown, unless OrangeDog can cite the C standard or a precise
reference like Harbison and Steele. It seems like a subtle question and I
would not bet money on either side being right. Rusty's example
illustrates where the common practical danger is, and that's what's more
important to describe in the article. But, I would not write code like
the printf example in a real program. For example, if the pointer is in a
register and the compiler understands the semantics of free, it might re-
use the register after the call to free, clobbering the pointer. Only
careful examination of the standard can say whether that is allowed.
69.228.171.150 (talk) 04:59, 14 November 2009 (UTC)
 
K

Keith Thompson

Phil Bradby said:
2005 said:
2005 wrote:
1) If I want to allocate m bytes dynamically would the following do?
2) What is the purpose of the for loop here - assign initial value?

int main(void)
{
        int m = 100;
        int *ptr = (int *) malloc(m);

Note that in C you don't have to cast the return value of malloc/
calloc/realloc, since conversion to and from a void pointer is
implicit.

Thanks Santosh - but why at
http://en.wikipedia.org/wiki/Malloc

they are doing it and kind of making a standard ?

Another question I have is that should ptr = i; this be ptr = 0;
instead?


There is an interesting U/B discussion on the talk page of that Wikipedia
article. Maybe someone with clc expertise could help those guys out!


It appears that someone with C expertise already has.
In the section of this page, Use after free, it is claimed that after a
pointer has been passed to free, that:

Even attempting to print the variable with printf is undefined
behavior (assuming malloc did not return a null pointer); for example:
printf("%p", (void *) ptr); /* Undefined behavior */

Is the behavior really undefined? Assuming that we discount that the
value of the pointer we get back from malloc is undefined, the call to
free() is pass by value.

No, the pointer we get back from malloc is well defined; it's either a
pointer to a newly created object or a null pointer.
The value of ptr will not change as a result of
passing it to free. The printf() should print the value of the pointer as
it was before the call to free (ie. this is the defined behavior).

Yes, the behavior really is undefined (which means simply that the C
standard imposes no requirements on the behavior). On most
implementations, the manifestation of that undefined behavior is
likely to be that the value is printed as if it hadn't been free()d.

Calling free(ptr) causes the lifetime of the object to which ptr
points to end. C99 6.2.4p2 says:

The value of a pointer becomes indeterminate when the object it
points to reaches the end of its lifetime.

Consider, for example, a system with special-purpose address
registers. Any access to a pointer value involves loading it into
one of these registers. Loading the value automatically checks
that it's valid. If the pointed-to object no longer exists, the
check fails, and Bad Things Happen.

That's just one of arbitrarily many ways it can go wrong.
The only doubt to this is that, perhaps the original poster was focusing
on the %p format placeholder. The wikipedia article on printf states that
the placeholder specifies:

Print a void * (pointer to void) in an implementation-defined format.

This specification is a little generic (implementation-defined format).
If an implementation were to attempt to "pretty-print" the value pointed
to by ptr, then the assertion of undefined behavior would be reasonable.

No, "%p" is not the issue. The specification is exactly as generic as
it needs to be; the standard doesn't say what the output of "%p" looks
like, but each implementation must document how it works.

The result of "%p" for a *valid* pointer value (either a null
pointer or a pointer to an object that currently exists) is
implementation-defined. (I've seen hexadecimal, upper and lower
case, with or without a leading "0x"; I've also seen octal.)
The result for an invalid pointer value, such as the value of
an uninitialized pointer object or a pointer to an object whose
lifetime has ended, is entirely undefined; the program's behavior
becomes undefined as soon as the pointer expression is evaluated,
before printf is even called.
I suggest that this is not what is meant by "implementation-defined
format", and that the scope is restricted to an arbitrary formatting of
the value of the pointer itself (not de-referenced). Even if my
suggestion is wrong, I assert that in this example, it is only the use of
the %p placeholder which presents the problem. So the claim that

Even attempting to print the variable with printf is undefined
behavior (assuming malloc did not return a null pointer);

is not correct, because other forms of printf would be defined to print
the value of the pointer as it was before the call to free. Example:

printf("%x", ptr); /* Hex value of ptr */ 148.182.52.148 (talk) 04:28, 27
October 2009 (UTC)

An implementation is permitted to define the behavior of accessing
a pointer object with an indeterminate value if it choose to do
so; behavior that's not defined by the standard might be defined
by the implementation. Most, perhaps all, implementations don't
bother to do so.
I agree. printf is a bad example because free should not change the
address of the pointer.

You mean it doesn't change the value of the pointer, or the address of
the object to which the pointer points. But that object no longer
exists.

free() takes a pointer value as an argument. Like all function
arguments, it's passed by value. So, in principle, free(ptr)
cannot change the value of ptr. (The argument needn't even be a
reference to an object.)

But what happens is this: Before the call to free(ptr), ptr contains
a certain representation, which represents a valid pointer value,
the address of some object. After the call to free(ptr), ptr still
contains that same representation[*], but that representation no
longer represents a valid pointer value. Somewhat loosely speaking,
the stored value doesn't change, but the validity of that value
does change.

[*] There's been some debate about whether free() *can* change the
representation of the pointer passed to it. In my opinion it can't,
but it shouldn't make much practical difference either way.
A better example of an error would be the one
given on page 167 of the 2nd edition of Kernighan and Ritchie. Their
example of an error is trying to free all the elements in a linked list
with this code:
for (p = head; p!=NULL; p = p->next) /*wrong */

free(p);

This is clearly incorrect because after p is freed there is no
assurance that p->next will still point to the next element in the list.

That's not a better example; it's an example of a different problem in
addition to the one we're discussing. The expression p->next
*dereferences* p, and dereferencing a freed pointer is clearly
invalid. (Actually, it refers to the current value of p before
dereferencing it, which is itself undefined.)

Here's a snippet that illustrates the issue:

int *p1;
int *p2;
p1 = malloc(sizeof *p1);
/* Unless malloc failed, p1 now points to an int object. */
free(p1);
/* p1 is now an invalid pointer */
p2 = p1; /* Undefined behavior */

In well-written code there's no reason to refer to the value of a
pointer after it's been passed to free() anyway. The only programs
affected by the fact that referring to the value of a freed pointer
invokes undefined behavior are almost certainly buggy anyway.
 
B

Barry Schwarz

Variables hold values. They're safe. Macros, on the other hand,
make programmers feel nervous sometimes. That's probably all it
was.


size_t is an unsigned integer type that can hold the size of
any object in your C program. It's also what malloc() takes
as an argument.


There is also realloc(), which takes a malloc()'d pointer and
returns one to a bigger size - though be careful when it fails
that you don't lose the original!

"and returns one to a possibly different size". It could be smaller,
it could be larger, and in poorly written code it could even be the
same size.
And there is calloc(), which allocates memory and 0's it out,
though you again should be careful because for pointers and
floating point values sometimes all 0's is not actually zero.

And there is free(), which is kinda a friend of malloc().
You can click the link to see/run the code: http://codepad.org/8Z8Q3pdo

Your code is here (it's hard to use two programs at once):
#include <stdlib.h>
#define MAX 10

int main(void)
{


// size_t num_ints = MAX;

// comments are dangerous on Usenet because sometimes lines wrap
around and then your code doesn't compile. And some people here
(including myself) don't use compiler modes that support them.
int *ptr = malloc(MAX * sizeof (int));

You can use sizeof directly on *ptr, like so:
int *ptr = malloc(MAX * sizeof *ptr);
This saves you a potential bug if you decide ptr should actually
point to longs or shorts or size_ts or something.
if(ptr != NULL)
{
int i = 0;
while(i < MAX)
{
ptr = i;
printf ("ptr[%d] = %d\n", i, ptr);
i++;

}
/* use those values in other ways
if you like, and then, when you
have finished, call free():
*/

}
free(ptr);
return 0;

}


I'm a little tired, but it looks to me that this code is A-OK.
Congratulations!
 

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,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top