473,753 Members | 8,053 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

General method for dynamically allocating memory for a string

I have searched the internet for malloc and dynamic malloc; however, I still
don't know or readily see what is general way to allocate memory to char *
variable that I want to assign the substring that I found inside of a
string.

Any ideas?
Aug 30 '06
94 4761
Richard Bos said:
Ben Pfaff <bl*@cs.stanfor d.eduwrote:
>rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
<snip>
The reasoning given in the comment is also bogus. It is a very _bad_
programming habit to start expecting that you can free pointers twice.

You can free a null pointer any number of times you like. I
think that is what the "it" in "delete it more than once" means.

Yes, you can. My point was that relying on this capability by setting
pointers to null after you're done with them is a bad programming habit,
not a good one, because you _will_ get in the habit of calling free() on
any which pointer, with the reasoning that "it'll either be a valid
pointer or null".
True enough - you shouldn't *rely* on it, in the sense of arbitrarily
littering your code with calls to free(). Nevertheless, setting pointers to
NULL after you're done with them is a /good/ habit, not a bad one. It's
called "defence in depth".
The truly good programming habit, in this case, is to do your bleedin'
bookkeeping, and keep in mind which pointers you have free()d, and which
you haven't.
That's certainly true, but it is also a good idea to recognise that you
might be fallible, and to take precautions against that fallibility. A null
pointer is far more useful than a pointer with an indeterminate value.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 1 '06 #21
jacob navia said:

<snip>
>
Besides, if you want to use modern programming techniques, i.e. a
GARBAGE COLLECTOR and forget about free() accounting and all this mess,
this is

a VERY good habit
So far, so good...
since setting a pointer to NULL tells the GC that
the associated memory is free to reuse.
Oh deary deary me. Consider the following code fragment:

T *p = malloc(n * sizeof *p);
if(p != NULL)
{
T *q = p;
p = NULL;
dosomethingwith (q);

This is legal C, and although it may seem pretty pointless as written,
that's only because all the detail that would make it make sense - perhaps
a great deal of code - has been omitted. In real life, such code could well
form part of a well-written program, and might well be the best way to
express the programmer's intent.

If setting a pointer to NULL told the GC that the associated memory is free
to re-use, writing code like the above would become impossible.
It is interesting that none of the posters considers GC and how
it would enormously SIMPLIFY the writing of this code.
Garbage collection is too important to be left to the system - or, at least,
in comp.lang.c it is. The Lithp people will no doubt have a different
opinion, but that's their problem.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 1 '06 #22
Richard Heathfield wrote:
jacob navia said:

<snip>
>>Besides, if you want to use modern programming techniques, i.e. a
GARBAGE COLLECTOR and forget about free() accounting and all this mess,
this is

a VERY good habit


So far, so good...

>>since setting a pointer to NULL tells the GC that
the associated memory is free to reuse.


Oh deary deary me. Consider the following code fragment:

T *p = malloc(n * sizeof *p);
if(p != NULL)
{
T *q = p;
p = NULL;
dosomethingwith (q);
???

The GC will find that q is not NULL. Then it will not release any
memory and everything will work as expected.

BUT

consider this

char *p;

int fn(void)
{
p = GC_malloc(1024) ;
// use of p
return 0;
}

This means this function leaves p pointing to a 1024 byte
memory block. The GC has NO way to know if this memory is used
or not, and will not reuse the block.

If you are done with the block, you set p to NULL and then the
GC knows that the 1024 byte block can be reused.

That's what I wanted to point out.
This is legal C, and although it may seem pretty pointless as written,
that's only because all the detail that would make it make sense - perhaps
a great deal of code - has been omitted. In real life, such code could well
form part of a well-written program, and might well be the best way to
express the programmer's intent.

If setting a pointer to NULL told the GC that the associated memory is free
to re-use, writing code like the above would become impossible.

Yes, Indeed. But this will not produce the effect of fooling the GC.
>>It is interesting that none of the posters considers GC and how
it would enormously SIMPLIFY the writing of this code.


Garbage collection is too important to be left to the system - or, at least,
in comp.lang.c it is. The Lithp people will no doubt have a different
opinion, but that's their problem.
GC works in C and is in the standard distribution of lcc-win32. If by
"Lithp" you mean Lisp, yes, they use a GC, as do other languages
beside Lisp and C, for instance C#, Java, Eiffel and many others.

The problem with manual Garbage collection (malloc/free) is that is VERY
error prone. AND VERY BORING. The ideal task to be done by a machine
and not by people.

But this is an old discussion here.
Sep 1 '06 #23
jacob navia said:
Richard Heathfield wrote:
>jacob navia said:
<snip>
>>
>>>since setting a pointer to NULL tells the GC that
the associated memory is free to reuse.


Oh deary deary me. Consider the following code fragment:

T *p = malloc(n * sizeof *p);
if(p != NULL)
{
T *q = p;
p = NULL;
dosomethingwith (q);

???

The GC will find that q is not NULL. Then it will not release any
memory and everything will work as expected.
You said "setting a pointer to NULL tells the GC that the associated memory
is free to reuse". Now you appear to be making a different claim - i.e.
that *all* pointers to that memory have to be set to NULL before the GC can
assume the associated memory is free to reuse. So now the programmer has to
*ensure* that, if he sets up multiple pointers that all end up at the same
address, he *has* to set *all* of them to NULL, to appease the garbage
collector; and if he misses even one, he'll have a memory leak.

Personally, I find it far more convenient to call free() when I'm done with
the memory block. Then, if I am in a tricksy part of the code and wish to
set pointers to NULL as a safety precaution, I can do that, and if I am in
a simple but performance-critical part of the code, I can choose not to do
it. The way you describe automatic garbage collection, I would be denied
those choices.

<snip>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 1 '06 #24
Randall wrote:
>
I corrected the code to reflect all the feedback. Special thanks to:
Jay, Frederick - pointing out my off-by-one array index error.
Richard - questioning the gratuitous NULLing of already
NULLed pointers.
Frederick - explicitly making a string immutable.
Richard - bringing up the issue of freeing or deleting memory twice.

The points requiring further clarification:
Issue 1: #include <sys/types.hvs. <stddef.h>
As a Unix programmer I am accustomed to writing the following code:
#include <sys/types.h>
#include <unistd.h>
As unistd.h requires sys/types.h to be used correctly. Only _unistd.h
includes sys/types.h directly (the implementation file).

For straight C coding (platform independent) I would prefer <stddef.h>
because it is smaller. Both are correct; this issue comes down to
taste and personal preference.
This is c.l.c, where we discuss the standard C language, as defined
by the various ISO standards and K&R. None of these standardizes
sys/types.h, nor _unistd.h. Thus they are off topic here. Their
use significantly impedes portability.

--
Chuck F (cb********@yah oo.com) (cb********@mai neline.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.netUSE maineline address!
Sep 1 '06 #25
Richard Heathfield wrote:
jacob navia said:

>>Richard Heathfield wrote:
>>>jacob navia said:

<snip>
>>>>since setting a pointer to NULL tells the GC that
the associated memory is free to reuse.
Oh deary deary me. Consider the following code fragment:

T *p = malloc(n * sizeof *p);
if(p != NULL)
{
T *q = p;
p = NULL;
dosomethingwith (q);

???

The GC will find that q is not NULL. Then it will not release any
memory and everything will work as expected.


You said "setting a pointer to NULL tells the GC that the associated memory
is free to reuse". Now you appear to be making a different claim - i.e.
that *all* pointers to that memory have to be set to NULL before the GC can
assume the associated memory is free to reuse. So now the programmer has to
*ensure* that, if he sets up multiple pointers that all end up at the same
address, he *has* to set *all* of them to NULL, to appease the garbage
collector; and if he misses even one, he'll have a memory leak.
Yes, this can be a problem with the GC.

As you may know, I am not selling anything here, and I am not saying
that the GC is a "solve it all" magic bullet.

The algorithm of a conservative GC is that if a block of memory
is *reachable* from any of the roots (and in this case a global pointer
is a root) then that block can't be reused.

Setting pointers to NULL after you are done with them is a harmless
operation, nothing will be destroyed unles it can be destroyed.

It is MUCH simpler than calling free() only ONCE for each block.

If you have several dozen *ALIASES* for a memory block, as you did
in the code above, you must free the block ONLY ONCE, what can be
extremely tricky in a real life situation.
Personally, I find it far more convenient to call free() when I'm done with
the memory block.
If you have visibility, as in this example, OK. But if you don't,
i.e. you are passing memory blocks around to all kinds of routines that
may store that pointer in structures, or pass it again around, it
can be extremely tricky to know how many aliases you already have
for that memory block and to invalidate ALL of them.

Then, if I am in a tricksy part of the code and wish to
set pointers to NULL as a safety precaution, I can do that, and if I am in
a simple but performance-critical part of the code, I can choose not to do
it. The way you describe automatic garbage collection, I would be denied
those choices.
Setting a pointer to NULL is such a CHEAP operation in ALL machines
that it is not worth speaking about. It means zeroing a
memory location.
Sep 1 '06 #26
Richard Heathfield wrote:
jacob navia said:
>Richard Heathfield wrote:
>>jacob navia said:
<snip>
>>>
since setting a pointer to NULL tells the GC that
the associated memory is free to reuse.

Oh deary deary me. Consider the following code fragment:

T *p = malloc(n * sizeof *p);
if(p != NULL)
{
T *q = p;
p = NULL;
dosomethingwith (q);

???

The GC will find that q is not NULL. Then it will not release any
memory and everything will work as expected.

You said "setting a pointer to NULL tells the GC that the
associated memory is free to reuse". Now you appear to be making
.... snip ...

Revise the example:

T *p;

if (p = malloc(n * sizeof *p) {
T *q;

q = p+1; p = NULL;
dosomethingwith (q);
q--;
....
}

--
Some informative links:
news:news.annou nce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
Sep 1 '06 #27
jacob navia said:

<snip>
Yes, this can be a problem with the GC.
So let's not do that, then.
>
As you may know, I am not selling anything here,
No, I don't know that. There is considerable evidence to the contrary.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 1 '06 #28
CBFalconer wrote:
Revise the example:

T *p;

if (p = malloc(n * sizeof *p) {
T *q;

q = p+1; p = NULL;
dosomethingwith (q);
q--;
....
}
The revised example will not fool the GC since the block can be reached
from q, since it points between the beginning and the end of the block.
Sep 1 '06 #29
jacob navia said:
CBFalconer wrote:
>Revise the example:

T *p;

if (p = malloc(n * sizeof *p) {
T *q;

q = p+1; p = NULL;
dosomethingwith (q);
q--;
....
}

The revised example will not fool the GC since the block can be reached
from q, since it points between the beginning and the end of the block.
<shrugFinding ways to fool it is a moderately trivial exercise:

p = malloc(n * sizeof *p);
pos = ftell(fp);
fwrite(&p, sizeof p, 1, fp);
p = NULL;
fseek(fp, pos, SEEK_SET);
fread(&p, sizeof p, 1, fp);

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Sep 1 '06 #30

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.