Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Correct use of malloc (http://www.velocityreviews.com/forums/t959563-correct-use-of-malloc.html)

idkfaidkfaidkfa@gmail.com 04-09-2013 11:59 AM

Correct use of malloc
 
Hi,
do you think that this is a correct use of malloc function?

void foo(void)
{
.....
prt++;
}

void main()
{
int *ptr=malloc(5*sizeof(int));
....
foo();
free(ptr);
}

Can i use ptr in foo() function without passing it?
Thanks



Nobody 04-09-2013 12:06 PM

Re: Correct use of malloc
 
On Tue, 09 Apr 2013 04:59:46 -0700, idkfaidkfaidkfa wrote:

> do you think that this is a correct use of malloc function?
>
> void foo(void)
> {
> ....
> prt++;
> }
>
> void main()
> {
> int *ptr=malloc(5*sizeof(int));
> ....
> foo();
> free(ptr);
> }
>
> Can i use ptr in foo() function without passing it?


You don't declare "prt" anywhere. Assuming that you meant "ptr", it's
local to main(), so you can't reference it outside main(). And if it was a
global variable, incrementing it within foo() would mean that you can't
pass it to free() as it no longer contains the value returned from the
call to malloc().


James Kuyper 04-09-2013 03:29 PM

Re: Correct use of malloc
 
On 04/09/2013 07:59 AM, idkfaidkfaidkfa@gmail.com wrote:
> Hi,
> do you think that this is a correct use of malloc function?


No, for several reasons, detailed below.

> void foo(void)
> {
> ....
> prt++;


I assume that was intended to be ptr++.

> }
>
> void main()


Conforming implementations of C are not required to accept main() being
declared as returning void. Many books have been written as if this were
a good idea; if you have such a book, and are free to choose to use a
different book, do so - there's no telling how many other bad habits
that book may be teaching you. Many compilers have been designed to
accept it, but you should not use it. You should always declare main()
as returning int.

> {
> int *ptr=malloc(5*sizeof(int));


It's generally better to use sizeof *ptr. That way, if at some point in
the future you decide to change the type that ptr points at, you only
need to change the type in one location.

If the declaration of ptr is in a different location than the place
where you call malloc() (an issue that will become important down below)
then it's even more important to use this method. Given the following
statement:

car_list = malloc(num_cars * sizeof *car_list);

The fact that the correct size is being referred to can determined just
by looking at that one statement. If you use sizeof(type), you must also
look at the declaration of car_list to make sure that it's the size of
the right type.

You should always check whether malloc() returns a null pointer. If it
does, it means that malloc() failed, and the behavior of a program that
dereferences a null pointer is undefined.

> ....
> foo();
> free(ptr);
> }
>
> Can i use ptr in foo() function without passing it?
> Thanks


No. C variables can only be accessed by name within their scope. The
scope of ptr starts immediately after the "ptr" in it's declaration in
main(), and extends all the way to the '}' that ends the body of main()
- but it does not include functions that are called from within main().
The other issues I'm raising in this message are just a matter of "best
practices"- you'll often get away with writing code this sloppy - but
that's not the case here. You simply cannot use ptr that way.

Passing the pointer value as an argument to foo() is the single best way
to deal with this issue. However, on rare occasions that might not be
possible, such as when writing callback functions with a fixed
interface, such as the comparison functions used by qsort() or
bsearch(). If that's the case, one alternative is to use a file scope
variable, which can be used anywhere in the same file below the the
point where it's declared:

int *ptr;

void foo(void)
{
...
ptr++;
}

int main()
{
ptr = malloc(5*sizeof *ptr);
if(ptr)
{
foo();
free(ptr);
ptr = NULL;
}
return 0;
}

When you free() a piece allocated memory, all pointers that used to
refer to any part of that memory have indeterminate values. That means
that you cannot safely use them for ANY purpose, not even checking them
for equality with another pointer value. If there's any chance that a
pointer object might be used again after you free the memory it refers
to, you should re-set it to a null value, which can at least be safely
checked for equality. The code which uses that value can check whether
it's null, and use that fact to avoid doing anything else with it. In
this particular case, it's easy to see that ptr will never be used again
- but I make it a habit to always null such pointers unless the pointer
object's lifetime is guaranteed to end before the very next statement
gets executed; ptr's lifetime continues after the return statement is
executed (though not for very long after that point).

Explicitly returning 0 from main() is not strictly necessary; special
rules were added to C99 to allow it. However, those special rules were a
concession to a popular piece of bad programming - it's a bad idea to
take advantage of those rules. You should develop a habit of always
making sure that any function declared as returning a value does in fact
return a value (unless you're certain that the value will not be used -
but the value returned by the initial call to main() in a program is
always used).
--
James Kuyper

Eric Sosman 04-09-2013 03:48 PM

Re: Correct use of malloc
 
On 4/9/2013 11:29 AM, James Kuyper wrote:
> [...]
> int *ptr;
>
> void foo(void)
> {
> ...
> ptr++;
> }
>
> int main()
> {
> ptr = malloc(5*sizeof *ptr);
> if(ptr)
> {
> foo();
> free(ptr);


Undefined behavior here, because `ptr' is no longer the
value returned by malloc(): It was modified by foo().


> ptr = NULL;
> }
> return 0;
> }


--
Eric Sosman
esosman@comcast-dot-net.invalid

James Kuyper 04-09-2013 03:55 PM

Re: Correct use of malloc
 
On 04/09/2013 11:48 AM, Eric Sosman wrote:
> On 4/9/2013 11:29 AM, James Kuyper wrote:
>> [...]
>> int *ptr;
>>
>> void foo(void)
>> {
>> ...
>> ptr++;
>> }
>>
>> int main()
>> {
>> ptr = malloc(5*sizeof *ptr);
>> if(ptr)
>> {
>> foo();
>> free(ptr);

>
> Undefined behavior here, because `ptr' is no longer the
> value returned by malloc(): It was modified by foo().


You're right - I mistakenly copied that mistake from the original code.
Having so many mistakes in a single piece of code is pretty impressive
(and possibly suspicious).

The simple fix is free(ptr-1). However, in the more general case, a
program like this really should have two separate variables: one that
contains the value returned by malloc(), which should never be changed,
and should be passed to free() when you're done with it. A separate
variable should be used to keep track of a particular place within the
allocated array.
--
James Kuyper

James Kuyper 04-09-2013 03:56 PM

Re: Correct use of malloc
 
On 04/09/2013 11:48 AM, Eric Sosman wrote:
> On 4/9/2013 11:29 AM, James Kuyper wrote:
>> [...]
>> int *ptr;
>>
>> void foo(void)
>> {
>> ...
>> ptr++;
>> }
>>
>> int main()
>> {
>> ptr = malloc(5*sizeof *ptr);
>> if(ptr)
>> {
>> foo();
>> free(ptr);

>
> Undefined behavior here, because `ptr' is no longer the
> value returned by malloc(): It was modified by foo().


You're right - I mistakenly copied that mistake from the original code.
Having so many mistakes in a single piece of code is pretty impressive
(and possibly suspicious).

The simple fix is free(ptr-1). However, in the more general case, a
program like this really should have two separate variables: one that
contains the value returned by malloc(), which should never be changed,
and should be passed to free() when you're done with it. A separate
variable should be used to keep track of a particular place within the
allocated array.
--
James Kuyper

Malcolm McLean 04-09-2013 04:38 PM

Re: Correct use of malloc
 
On Tuesday, April 9, 2013 12:59:46 PM UTC+1, idkfaid...@gmail.com wrote:
> Hi,
>
> do you think that this is a correct use of malloc function?
>
> void foo(void)
> {
>
> ....
>
> prt++;
>
> }
>
>
> void main()
> {
> int *ptr=malloc(5*sizeof(int));
>
>
> foo();
>
> free(ptr);
> }
>
>
> Can i use ptr in foo() function without passing it?
>

You can make ptr global, then foo can operate on it. But, as others have
said, if you increment it you have to decrement it again before freeing
it.
Generally both of these things are a bad idea. Allocate as much space as
you need in a high level function, pass the pointer to your lower
level functions, and the free it in the high level function. Globals
should be rare.

The problem with malloc, and pointers generally, is that it's hard to
show correct use in small snippets of code. Pointers come into their
own with real problems where N depends on input data.



Eric Sosman 04-09-2013 05:06 PM

Re: Correct use of malloc
 
On 4/9/2013 11:56 AM, James Kuyper wrote:
> On 04/09/2013 11:48 AM, Eric Sosman wrote:
>> On 4/9/2013 11:29 AM, James Kuyper wrote:
>>> [...]
>>> int *ptr;
>>>
>>> void foo(void)
>>> {
>>> ...
>>> ptr++;
>>> }
>>>
>>> int main()
>>> {
>>> ptr = malloc(5*sizeof *ptr);
>>> if(ptr)
>>> {
>>> foo();
>>> free(ptr);

>>
>> Undefined behavior here, because `ptr' is no longer the
>> value returned by malloc(): It was modified by foo().

>
> You're right - I mistakenly copied that mistake from the original code.
> Having so many mistakes in a single piece of code is pretty impressive
> (and possibly suspicious).
>
> The simple fix is free(ptr-1). However, in the more general case, a
> program like this really should have two separate variables: one that
> contains the value returned by malloc(), which should never be changed,
> and should be passed to free() when you're done with it. A separate
> variable should be used to keep track of a particular place within the
> allocated array.


I'm sure *you* knew that, but I pointed it out because I
wasn't sure "idkfaidkfaidkfa" does. (If "idkfaidkfaidkfa"
cares, that is.)

However, the need in cases like this to maintain multiple
pointers to (or into, or near) an allocated block somewhat
diminishes the value of NULL'ing a pointer variable after
free(). You can zap the particular variable that supplied
the value for the free() call, but finding and zapping other
related variables will not always be possible. NULL'ing the
proximate variable doesn't hurt, of course, but if it confers
a feeling of safety I fear the feeling is unfounded. It may
be better to know you're unarmored than to put too much faith
in a chiffon shield.

--
Eric Sosman
esosman@comcast-dot-net.invalid

James Kuyper 04-09-2013 05:41 PM

Re: Correct use of malloc
 
On 04/09/2013 01:06 PM, Eric Sosman wrote:
....
> However, the need in cases like this to maintain multiple
> pointers to (or into, or near) an allocated block somewhat
> diminishes the value of NULL'ing a pointer variable after
> free(). You can zap the particular variable that supplied
> the value for the free() call, but finding and zapping other
> related variables will not always be possible.


Well, the rule I apply in that case requires that all such variables be
nulled, if possible, unless their lifetime is about to end, anyway.

> ... NULL'ing the
> proximate variable doesn't hurt, of course, but if it confers
> a feeling of safety I fear the feeling is unfounded. ...


If, for any reason, it's not possible to null all of the relevant
pointers, believe me, "safe" is not what I'm feeling.

Malcolm McLean 04-10-2013 09:56 AM

Re: Correct use of malloc
 
On Tuesday, April 9, 2013 6:41:32 PM UTC+1, James Kuyper wrote:
> On 04/09/2013 01:06 PM, Eric Sosman wrote:
>
>
> > However, the need in cases like this to maintain multiple
> > pointers to (or into, or near) an allocated block somewhat
> > diminishes the value of NULL'ing a pointer variable after
> > free(). You can zap the particular variable that supplied
> > the value for the free() call, but finding and zapping other
> > related variables will not always be possible.

>
>
> Well, the rule I apply in that case requires that all such variables be
> nulled, if possible, unless their lifetime is about to end, anyway.
>

The rule I apply is that you either have matching mallocs and frees,
with the frees almost always the last statements in the function,
or if this isn't possible because you are creating a tree or similar
structure, you have a constructor / destructor function set up.

So I don't worry about aliases to the pointers in local variables.

There might be situations where this pattern can't be followed,
but they are few and far between. I do find it's more important
to null pointers before allocation, so if an allocation fails, it's
easier to free the rest neatly.
--
Malcolm's webpage, lots of C programming resources
http://www.malcolmmclean.site11.com/www


All times are GMT. The time now is 08:55 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.