By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
444,208 Members | 1,592 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 444,208 IT Pros & Developers. It's quick & easy.

General method for dynamically allocating memory for a string

P: n/a
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 #1
Share this Question
Share on Google+
94 Replies


P: n/a
"smnoff" <34**************@hotmail.comwrites:
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.
If you want to allocate memory for a string, pass the number of
non-null characters in it, plus one, to malloc, then copy the
string into it, being sure to null-terminate the result.

If you can be more specific about what you're trying to do,
perhaps we can help with some details.
--
"I hope, some day, to learn to read.
It seems to be even harder than writing."
--Richard Heathfield
Aug 30 '06 #2

P: n/a
smnoff posted:
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?

Unchecked code, may contain an error or two:

#include <stdlib.h>
#include <stddef.h>
#include <assert.h>

char *to_release;

void ReleaseLastString(void)
{
free(to_release);
}

char const *CreateSubstring(char const *const p,
size_t const istart,size_t const iend)
{
int assert_dummy = (assert(!!p),assert(!!istart),assert(!!iend),0);

if(!p[iend+1]) return to_release = 0, p + istart;

to_release = malloc(iend - istart + 1);

memcpy(to_release,p,iend - istart);

to_release[iend - istart] = 0;

return to_release;
}

int main()
{
puts(CreateSubstring("abcdefghijklmnop",2,7));
ReleaseLastString();

puts(CreateSubstring("abcdefghijklmnop",4,15));
ReleaseLastString();
}

--

Frederick Gotham
Aug 31 '06 #3

P: n/a

"Frederick Gotham" <fg*******@SPAM.comwrote in message
news:r9*******************@news.indigo.ie...
smnoff posted:
>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?


Unchecked code, may contain an error or two:

#include <stdlib.h>
#include <stddef.h>
#include <assert.h>

char *to_release;

void ReleaseLastString(void)
{
free(to_release);
}

char const *CreateSubstring(char const *const p,
size_t const istart,size_t const iend)
{
int assert_dummy = (assert(!!p),assert(!!istart),assert(!!iend),0);


Why are there double exclamation marks in the line show above?


Aug 31 '06 #4

P: n/a
Frederick's code is hard to read and harder to learn from. Here is
some fully checked code with lots of comments.
///////////////////////////////////////////////////////////////////////////////
// file: substr.c
// Note: C++ style comments are allowed for C99 compliant compilers.
///////////////////////////////////////////////////////////////////////////////
#include <stdlib.h // for malloc() and free()
#include <string.h // for strncpy()
#include <sys/types.h // for size_t
#include <stdio.h // for printf()

char * substr( char * string, size_t start, size_t end);

int main( void ) {

char *str1 = substr("abcdefghijklmnop",2,7);
char *str2 = substr("abcdefghijklmnop",4,15);

if( str1 != NULL ) {
printf( "str1: %s\n", str1);
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str1 = 0;
}

if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}

free( str1 );
free( str2 );

return 0;
}

/**
* Note: this function will return a newly allocated string. It
* is your responsibility to delete this memory to prevent a leak.
*
* param "string" - the string you want to extract a substring from.
* param "start" - the array index to begin your substring.

* param "start" - the array index to begin your substring.
* param "end" - the array index to terminate your substring.
*
* On Error: this function returns null;
*/
char * substr( char * string, size_t start, size_t end) {
// pointer to the substring on the heap
char *subString;

// calculate the total amount of memory needed
// to hold the substring.
// Algo: end - start + null terminator
size_t subStringSize = end - start + 1;

// request enough bytes to store the entire
// substring and null terminator.
subString = malloc( subStringSize );

// test to make sure we got the memory
// from malloc
if( subString != NULL ) {
// Note this copies one extra byte (the
// null terminator's spot) which is garbage.
// We have to terminate this string.
strncpy( subString, string + start, subStringSize );

subString[subStringSize] = '\0';
}

// This will either be NULL if we didn't get the
// memory from malloc or it will have our substring.
return subString;

} // end function substr
I hope this helps you.

-Randall
Frederick Gotham wrote:
smnoff posted:
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?


Unchecked code, may contain an error or two:

#include <stdlib.h>
#include <stddef.h>
#include <assert.h>

char *to_release;

void ReleaseLastString(void)
{
free(to_release);
}

char const *CreateSubstring(char const *const p,
size_t const istart,size_t const iend)
{
int assert_dummy = (assert(!!p),assert(!!istart),assert(!!iend),0);

if(!p[iend+1]) return to_release = 0, p + istart;

to_release = malloc(iend - istart + 1);

memcpy(to_release,p,iend - istart);

to_release[iend - istart] = 0;

return to_release;
}

int main()
{
puts(CreateSubstring("abcdefghijklmnop",2,7));
ReleaseLastString();

puts(CreateSubstring("abcdefghijklmnop",4,15));
ReleaseLastString();
}

--

Frederick Gotham
Aug 31 '06 #5

P: n/a
"smnoff" <34**************@hotmail.comwrites:
"Frederick Gotham" <fg*******@SPAM.comwrote in message
news:r9*******************@news.indigo.ie...
>smnoff posted:
>>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?


Unchecked code, may contain an error or two:

#include <stdlib.h>
#include <stddef.h>
#include <assert.h>

char *to_release;

void ReleaseLastString(void)
{
free(to_release);
}

char const *CreateSubstring(char const *const p,
size_t const istart,size_t const iend)
{
int assert_dummy = (assert(!!p),assert(!!istart),assert(!!iend),0);

Why are there double exclamation marks in the line show above?
The assert() macro doesn't necessarily accept an argument of a type
other than int. (It does in C99, but not all compilers support C99.)

The ! (logical not) operator, applied to any scalar operand, yields
the int value 1 if the operand compares equal to 0, 0 if it doesn't.
A pointer value compares equal to 0 only if it's a null pointer. So
!p means "p is a null pointer". Applying it a second time reverses
the result, so !!p means "p is not a null pointer". !! normalizes a
scalar value, mapping 0 to 0 and anything else to 1.

So the declaration asserts that each of the pointers is non-null.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Aug 31 '06 #6

P: n/a
On 30 Aug 2006 21:04:57 -0700, "Randall" <ra*************@gmail.com>
wrote:
>Frederick's code is hard to read and harder to learn from. Here is
some fully checked code with lots of comments.
///////////////////////////////////////////////////////////////////////////////
// file: substr.c
// Note: C++ style comments are allowed for C99 compliant compilers.
///////////////////////////////////////////////////////////////////////////////
#include <stdlib.h // for malloc() and free()
#include <string.h // for strncpy()
#include <sys/types.h // for size_t
#include <stdio.h // for printf()

char * substr( char * string, size_t start, size_t end);

int main( void ) {

char *str1 = substr("abcdefghijklmnop",2,7);
char *str2 = substr("abcdefghijklmnop",4,15);

if( str1 != NULL ) {
printf( "str1: %s\n", str1);
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str1 = 0;
}

if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}

free( str1 );
free( str2 );

return 0;
}

/**
* Note: this function will return a newly allocated string. It
* is your responsibility to delete this memory to prevent a leak.
*
* param "string" - the string you want to extract a substring from.
* param "start" - the array index to begin your substring.

* param "start" - the array index to begin your substring.
* param "end" - the array index to terminate your substring.
*
* On Error: this function returns null;
*/
char * substr( char * string, size_t start, size_t end) {
// pointer to the substring on the heap
char *subString;

// calculate the total amount of memory needed
// to hold the substring.
// Algo: end - start + null terminator
size_t subStringSize = end - start + 1;

// request enough bytes to store the entire
// substring and null terminator.
subString = malloc( subStringSize );
Make that:

subString = malloc( subStringSize + 1 );
>
// test to make sure we got the memory
// from malloc
if( subString != NULL ) {
// Note this copies one extra byte (the
// null terminator's spot) which is garbage.
// We have to terminate this string.
strncpy( subString, string + start, subStringSize );

subString[subStringSize] = '\0';
Otherwise this indexes one past the end of malloc()ed memory, which is
undefined behavior.

Best regards
--
jay
Aug 31 '06 #7

P: n/a
Randall said:
Frederick's code is hard to read and harder to learn from. Here is
some fully checked code with lots of comments.
It didn't compile for me, so I just took a very quick look, and one thing
caught my eye:
if( str1 != NULL ) {
printf( "str1: %s\n", str1);
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str1 = 0;
}
This is exactly equivalent to:

if(str1 != NULL) {
printf("str1: %s\n", str1);
}

The else is utterly unnecessary because, if str1 is not a null pointer, it
is never entered, and if it /is/ a null pointer, setting it to a null
pointer value is a redundant operation.
if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
Likewise.

--
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)
Aug 31 '06 #8

P: n/a
Randall posted:
#include <stdlib.h // for malloc() and free()
#include <string.h // for strncpy()
#include <sys/types.h // for size_t


Non-standard header. "stddef.h" contains "size_t".
#include <stdio.h // for printf()

char * substr(char * string, size_t start, size_t end);


First parameter should be "pointer to const".
int main( void ) {

char *str1 = substr("abcdefghijklmnop",2,7);
char *str2 = substr("abcdefghijklmnop",4,15);


Both variables should be const. (You don't want the address to change
before you pass it to "free".)
if( str1 != NULL ) {
printf( "str1: %s\n", str1);
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str1 = 0;
}

if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}


As Richard Heathfield pointed out, both "else" clauses are redundant.
free( str1 );
free( str2 );

return 0;
}

/**
* Note: this function will return a newly allocated string. It
* is your responsibility to delete this memory to prevent a leak.
*
* param "string" - the string you want to extract a substring from.
* param "start" - the array index to begin your substring.

* param "start" - the array index to begin your substring.
* param "end" - the array index to terminate your substring.
*
* On Error: this function returns null;
*/
char * substr( char * string, size_t start, size_t end) {


First parameter should be "pointer to const".
// pointer to the substring on the heap
char *subString;

// calculate the total amount of memory needed
// to hold the substring.
// Algo: end - start + null terminator
size_t subStringSize = end - start + 1;


Perhaps you should have written:

size_t len = end - start;

And then added the +1 only when malloc'ing.
// request enough bytes to store the entire
// substring and null terminator.
subString = malloc( subStringSize );


subString = malloc(len+1);
// test to make sure we got the memory
// from malloc
if( subString != NULL ) {
// Note this copies one extra byte (the
// null terminator's spot) which is garbage.
// We have to terminate this string.
strncpy( subString, string + start, subStringSize );


"memcpy" would be more efficient if you were strict about the length of
the string, e.g.:

assert( strlen(string) - istart >= len );
subString[subStringSize] = '\0';


Here you invoke undefine behaviour by writing past the end of the buffer.

subString[len] = 0;

You should _always_ check array indexes.
}

// This will either be NULL if we didn't get the
// memory from malloc or it will have our substring.
return subString;

} // end function substr
--

Frederick Gotham
Aug 31 '06 #9

P: n/a
Frederick Gotham <fg*******@SPAM.comwrote:
Randall posted:
#include <stdlib.h // for malloc() and free()
#include <string.h // for strncpy()
#include <sys/types.h // for size_t

Non-standard header. "stddef.h" contains "size_t".
So so <stdlib.h>, <string.h>, and...
#include <stdio.h // for printf()
.... <stdio.h>.

It is not often necessary to #include <stddef.h>. It is very rarely
necessary to do so just for the declaration of size_t. All headers whose
functions need it also declare it themselves, and it's a rare program
that does not use one of those headers.
char * substr(char * string, size_t start, size_t end);

First parameter should be "pointer to const".
No, it shouldn't, because that's not how the function is defined. It may
be a wise idea to _define_ it as a pointer to const char, or even a
const pointer to const char, and then also declare it as such, but
"should" is too strong.
if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}

As Richard Heathfield pointed out, both "else" clauses are redundant.
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.
// calculate the total amount of memory needed
// to hold the substring.
// Algo: end - start + null terminator
size_t subStringSize = end - start + 1;

Perhaps you should have written:

size_t len = end - start;

And then added the +1 only when malloc'ing.
Why?

Richard
Aug 31 '06 #10

P: n/a
smnoff wrote:
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.
The C language makes this a bigger pain in the ass than it needs to be
as the discusion that has followed this shows. You can see how this is
done more easily in the Better String Library which you can get here:
http://bstring.sf.net/

If you just want to do it directly then:

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

char * substralloc (const char * src, size_t pos, size_t len) {
size_t i;
char * substr;
if (NULL == src || len < pos) return NULL; /* Bad parameters */
for (len += pos, i = 0; i < len; i++) {
if ('\0' == src) {
if (i < pos) i = pos;
break;
}
}
i -= pos;
if (NULL != (substr = (char *) malloc ((1 + i) * sizeof (char)))) {
if (i) memcpy (substr, src+pos, i);
substr[i] = '\0';
}
return substr;
}

So if there is an error in the meaning of the parameters or if there is
a memory allocation failure then NULL is returned. If you ask for a
substring which is beyond the end of the source string, or whose length
exceeds the end othe source string, then the result is truncated.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 31 '06 #11

P: n/a
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Frederick Gotham <fg*******@SPAM.comwrote:
>Randall posted:
if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}

As Richard Heathfield pointed out, both "else" clauses are redundant.

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.
--
"C has its problems, but a language designed from scratch would have some too,
and we know C's problems."
--Bjarne Stroustrup
Aug 31 '06 #12

P: n/a
Randall wrote:
Frederick's code is hard to read and harder to learn from. Here is
some fully checked code with lots of comments.

///////////////////////////////////////////////////////////////////////////////
// file: substr.c
// Note: C++ style comments are allowed for C99 compliant compilers.
///////////////////////////////////////////////////////////////////////////////
Note: C99 compliant compilers are in very short supply. (Though
compilers that *claim* to be C99 compilers is a little higher and those
that accept // comments are even higher.)
#include <stdlib.h // for malloc() and free()
#include <string.h // for strncpy()
#include <sys/types.h // for size_t
#include <stdio.h // for printf()

[...]

/**
* Note: this function will return a newly allocated string. It
* is your responsibility to delete this memory to prevent a leak.
*
* param "string" - the string you want to extract a substring from.
* param "start" - the array index to begin your substring.

* param "start" - the array index to begin your substring.
* param "end" - the array index to terminate your substring.
*
* On Error: this function returns null;
*/
char * substr( char * string, size_t start, size_t end) {
// pointer to the substring on the heap
char *subString;

// calculate the total amount of memory needed
// to hold the substring.
// Algo: end - start + null terminator
size_t subStringSize = end - start + 1;

// request enough bytes to store the entire
// substring and null terminator.
subString = malloc( subStringSize );

// test to make sure we got the memory
// from malloc
if( subString != NULL ) {
// Note this copies one extra byte (the
// null terminator's spot) which is garbage.
// We have to terminate this string.
strncpy( subString, string + start, subStringSize );
This leads to UB, since you have not established that string + start is
a valid thing to be pointing at.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 31 '06 #13

P: n/a
Frederick Gotham wrote:
smnoff posted:
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?

Unchecked code, may contain an error or two:
(At least ...)
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>

char *to_release;
Are you seriously making this global?
void ReleaseLastString(void)
{
free(to_release);
}

char const *CreateSubstring(char const *const p,
size_t const istart,size_t const iend)
{
int assert_dummy = (assert(!!p),assert(!!istart),assert(!!iend),0);

if(!p[iend+1]) return to_release = 0, p + istart;
Homiesaywhat? What the hell is that if() condition trying to do? And
what is p+istart trying to do? Are you trying to say p += istart?
to_release = malloc(iend - istart + 1);
Ok, so what if istart iend? And what if to_release contained some
unfreed contents before this call -- wouldn't that lead to a leak?
memcpy(to_release,p,iend - istart);
What if to_release was set to NULL (because of a memory allocation
failure)?
to_release[iend - istart] = 0;

return to_release;
}
--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 31 '06 #14

P: n/a
we******@gmail.com wrote:
#include <stdlib.h>
#include <string.h>

char * substralloc (const char * src, size_t pos, size_t len) {
size_t i;
char * substr;
if (NULL == src || len < pos) return NULL; /* Bad parameters */
Whoops! That should just be if (NULL == src) return NULL;

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 31 '06 #15

P: n/a

smnoff wrote:
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?
It would help if you could tell us a bit more about the strings:

(1) Are we allowed to mangle the source string?

(2) Can we assume the source string is going to exist for as long as
you need the substring?

(3) How many substrings do you need at any one instant? How long are
they on average?

-----
You see most malloc()'s have considerable overhead. If we can mangle
the source string, we can return the substring as a pointer into the
source string, with a zero byte at the end of the substring. Which is
economical, unless you need the original string or maybe another
substring might match at substring end + 1?

If the lifetime of the substrings can be determined, it might be
simpler faster and easier to just have a small array of substrings
rather than allocate each darn one on the heap.

Aug 31 '06 #16

P: n/a
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.

Issue 2: freeing or deleting given a NULL pointer more than once.
I should have written this code:
free( ptr_to_memory);
ptr_to_memory = NULL;

That way the ptr_to_memory no longer points to freed memory. If your
program is complicated and mission critical, it's nice to know that if
you (accidentally) free or delete it twice you wont introduce undefined
behavior into your system.

///////////////////////////////////////////////////////////////////////////////
// file: substr.c
// Note: C++ style comments are allowed for (partially)
// C99 compliant compilers -- the part that allows
// C++ style comments. ; )
///////////////////////////////////////////////////////////////////////////////
#include <stdlib.h // for malloc() and free()
#include <string.h // for strncpy()
#include <stdio.h // for printf()
#include <sys/types.h // for size_t - goes great with
// standard Unix headers like
// <unistd.h>; in fact it is required.

char * substr( const char * string, size_t start, size_t end);

int main( void ) {

char *str1 = substr("abcdefghijklmnop",2,7);
char *str2 = substr("abcdefghijklmnop",4,15);

if( str1 != NULL )
printf( "str1: %s\n", str1);

if( str2 != NULL )
printf( "str2: %s\n", str2 );

free( str1 );
str1 = NULL;

free( str2 );
str2 = NULL;

return 0;
}

/**
* Note: this function will return a newly allocated string. It
* is your responsibility to delete this memory to prevent a leak.
*
* param "string" - the string you want to extract a substring from.
* param "start" - the array index to begin your substring.
* param "end" - the array index to terminate your substring.
*
* On Error: this function returns null.
*/
char * substr( const char * string, size_t start, size_t end) {
// pointer to the substring on the heap
char *subString;

// calculate the total amount of memory needed to hold the substring
size_t subStringLen = end - start;

// request enough bytes to store the entire substring and null
// terminator.
subString = malloc( subStringLen + 1);

// test to make sure we got the memory from malloc
if( subString != NULL ) {
// Use pointer arithmetic to skip to the specified
// starting point of the substring. From that
// position, copy the desired number of characters.
strncpy( subString, string + start, subStringLen );

// We have to terminate this string with a NULL.
subString[ subStringLen ] = '\0';
}

// This will either be NULL if we didn't get the
// memory from malloc or it will have our substring.
return subString;

} // end function substr

Sep 1 '06 #17

P: n/a
Randall said:
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.
....and for pointing out that it didn't compile on his (GNU Linux/gcc)
system. Which it still doesn't.

--
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 #18

P: n/a
Ben Pfaff <bl*@cs.stanford.eduwrote:
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Frederick Gotham <fg*******@SPAM.comwrote:
Randall posted:
if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}

As Richard Heathfield pointed out, both "else" clauses are redundant.
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". That habit will then bite you when you encounter an
exception; e.g., when you make a copy of a pointer and only set one copy
to null, or when you have to work with other people's code which doesn't
nullify any pointers.
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. Don't just pass any which pointer to any which function,
relying on cheap hacks to keep you "safe".

Richard
Sep 1 '06 #19

P: n/a
Ben Pfaff wrote:
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:

>>Frederick Gotham <fg*******@SPAM.comwrote:

>>>Randall posted:

if( str2 != NULL ) {
printf( "str2: %s\n", str2 );
} else {
// Setting a null pointer to zero ensures you
// can delete it more than once (free) without
// undefined behavior. This is a good
// programming habit.
str2 = 0;
}

As Richard Heathfield pointed out, both "else" clauses are redundant.

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.
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

since setting a pointer to NULL tells the GC that
the associated memory is free to reuse.
It is interesting that none of the posters considers GC and how
it would enormously SIMPLIFY the writing of this code.

jacob
Sep 1 '06 #20

P: n/a
Richard Bos said:
Ben Pfaff <bl*@cs.stanford.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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a
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********@yahoo.com) (cb********@maineline.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.netUSE maineline address!
Sep 1 '06 #25

P: n/a
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

P: n/a
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.announce.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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a
Richard Heathfield wrote:
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);
Obvious.

The GC documentation makes usages like this explicitely off limits.
The GC will not look for pointers:

o in the windows extra bytes provided by Microsoft
o in the hard disk (!!!)
o in your grandmother's mail where she said:

Why did you send me that pointer 0xFF45AC son?

I give it back, I do not needed it.

Sep 1 '06 #31

P: n/a
jacob navia said:
Richard Heathfield wrote:
>>
<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);

Obvious.
Indeed. So much for automatic garbage collection.

--
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 #32

P: n/a
Richard Heathfield wrote:
jacob navia said:

>>Richard Heathfield wrote:
>>><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);

Obvious.


Indeed. So much for automatic garbage collection.
But what are you trying to prove with that nonsense Heathfield?

Imagine I say:

void foo(void)
{
char *p = malloc(1024);

for (int i=0; i<20; i++) {
free(p); // Crash here
}
}

Then I conclude:

"So much for malloc/free usage".
Wouldn't be stupid to conclude that because incorrect usage
the software crashes?

Is it possible to discuss here technical opinions without
trying just to prove at all costs that the other opinion is
just nonsense?

Note that I am not saying that malloc/free should not be used
neither that they are "bad software", but that the GC provides a very
useful alternative for people that do not like to mess with the
associated problems of manual garbage collection (malloc/free).

jacob
Sep 1 '06 #33

P: n/a
jacob navia <ja***@jacob.remcomp.frwrote:
Richard Heathfield wrote:
<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);

Obvious.

The GC documentation makes usages like this explicitely off limits.
Well, then it isn't C, is it?

Richard
Sep 1 '06 #34

P: n/a
Richard Bos wrote:
jacob navia <ja***@jacob.remcomp.frwrote:

>>Richard Heathfield wrote:
>>><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);

Obvious.

The GC documentation makes usages like this explicitely off limits.


Well, then it isn't C, is it?

Richard
Of course. Making a restriction in the usage of
a library makes it "not c".

Then, freeing twice an object (a restriction in the usage of free() )
makes free() "not c".

What kind of logic do you use?
Sep 1 '06 #35

P: n/a
Richard Heathfield wrote:
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.
What am I "selling"?

A product for zero dollars and zero cents?

Sep 1 '06 #36

P: n/a
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:8a********************@bt.com...
jacob navia said:
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.
....and elsethread...

Richard Heathfield wrote:
>jacob navia said:
>Richard Heathfield wrote:
>>>
<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);

Obvious.

Indeed. So much for automatic garbage collection.
Richard, while you have earned a lot of my respect and admiration through
your posting, I do feel that you are on a little bit of a crusade here. You
seem to be arguing that because garbage collection can't protect against all
memory leaks without care from the user, it is worthless. This is a somewhat
ridiculous argument - after all, manual memory management has precisely the
same property.

GCs don't give you a license not to think, but I didn't see anybody arguing
that they do.

Philip

Sep 1 '06 #37

P: n/a
jacob navia said:
Richard Heathfield wrote:
<snip>
>So much for automatic garbage collection.

But what are you trying to prove with that nonsense Heathfield?
If by "nonsense" you mean "correct C code", I am trying to prove, and
succeeding in proving, that automatic garbage collectors will struggle to
cope with correct C code.
Imagine I say:

void foo(void)
{
char *p = malloc(1024);

for (int i=0; i<20; i++) {
free(p); // Crash here
}
}

Then I conclude:

"So much for malloc/free usage".
It's not valid C. The example I gave /is/ valid C.
Wouldn't be stupid to conclude that because incorrect usage
the software crashes?
The example I gave is correct C. The example you gave is not.
Is it possible to discuss here technical opinions without
trying just to prove at all costs that the other opinion is
just nonsense?
Yes, and it happens all the time. Observe the technical discussions that
take place amongst those who actually know what they're talking about, and
you will see this very plainly.
Note that I am not saying that malloc/free should not be used
neither that they are "bad software", but that the GC provides a very
useful alternative for people that do not like to mess with the
associated problems of manual garbage collection (malloc/free).
Since this "very useful alternative" can't cope with correct C code, it
doesn't seem terribly useful to programmers who are using C. It may well be
useful to programmers who are using some other language, but that would be
a topic for some other newsgroup, not the comp.lang.c newsgroup.

--
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 #38

P: n/a
jacob navia said:
Richard Bos wrote:
>jacob navia <ja***@jacob.remcomp.frwrote:
<snip>
>>>
The GC documentation makes usages like this explicitely off limits.


Well, then it isn't C, is it?
Of course. Making a restriction in the usage of
a library makes it "not c".
What he means, I think, is that the kind of automatic garbage collection you
advocate cannot be used reliably in place of manual garbage collection in
arbitrary C programs, because it fails to deal with some C constructs that
are perfectly legal. It may be useful to those who are prepared to code
around its limitations, but unless you are able to persuade ISO to change
the language definition to forbid C constructs that confuse the collector,
that collector cannot reasonably be advanced as a generic replacement for
manual garbage collection.
>
Then, freeing twice an object (a restriction in the usage of free() )
makes free() "not c".
Not so. It means that freeing a block of memory /twice/ is "not C".
What kind of logic do you use?
He uses the normal kind. I'm not so sure what logic /you/ are using but,
whatever kind it is, it doesn't work very well in persuading other people
that you have a valid point.

--
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 #39

P: n/a
jacob navia said:
Richard Heathfield wrote:
>jacob navia said:
<snip>
>>>As you may know, I am not selling anything here,

No, I don't know that. There is considerable evidence to the contrary.
What am I "selling"?

A product for zero dollars and zero cents?
I didn't claim you were any good at it.

--
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 #40

P: n/a
Philip Potter said:
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:8a********************@bt.com...
>>
So much for automatic garbage collection.

Richard, while you have earned a lot of my respect and admiration through
your posting, I do feel that you are on a little bit of a crusade here.
Perhaps, but you may be mistaken as to the issues at stake.
You seem to be arguing that because garbage collection can't protect
against all memory leaks without care from the user, it is worthless.
No, I'm sure it has a place in other languages. I just don't think it sits
very well with C, for at least two reasons:

1) As we have already seen upthread, automatic garbage collection (AGC)
encounters serious difficulties when faced with C's heavy use of pointers
for keeping track not only of memory blocks but of particular positions
within them.

2) C is commonly used where not only performance but even timing (in
real-time stuff) is an important criterion for acceptance of the program,
and AGC implementations are notorious for introducing arbitrary delays at
various times through a program's run.

As I have already agreed, AGC is undoubtedly of value to some people in some
situations. I just don't think AGC is a good fit for C programmers, in the
general case. That's not to say that it might not be useful on occasion,
but I don't believe such occasions are sufficiently common to make the
subject a worthwhile diversion away from the topic of this newsgroup, which
is C programming, *not* "C programming + Jacob Navia's AGC extensions".

Were this discussion taking place in Jacob Navia's own newsgroup,
comp.compilers.lcc, then I would not have raised any objections at all.

--
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 #41

P: n/a
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:gb********************@bt.com...
Perhaps, but you may be mistaken as to the issues at stake.
Perhaps. I haven't said very much yet, so it's a bit early to be drawing
conclusions.
No, I'm sure it has a place in other languages. I just don't think it sits
very well with C, for at least two reasons:

1) As we have already seen upthread, automatic garbage collection (AGC)
encounters serious difficulties when faced with C's heavy use of pointers
for keeping track not only of memory blocks but of particular positions
within them.

2) C is commonly used where not only performance but even timing (in
real-time stuff) is an important criterion for acceptance of the program,
and AGC implementations are notorious for introducing arbitrary delays at
various times through a program's run.
You're right that AGC is not always suited to C. However, you said above:
I just don't think it sits
very well with C, for at least two reasons:
suggesting you think it is /never/ suited to C. You have yet to convince me
of this. In non-performance-critical, non-realtime situations, I see nothing
wrong with plugging in a garbage collector. And even in realtime situations,
there are ways to ensure the garbage collector will not activate in critical
sections of code.
As I have already agreed, AGC is undoubtedly of value to some people in
some
situations. I just don't think AGC is a good fit for C programmers, in the
general case. That's not to say that it might not be useful on occasion,
but I don't believe such occasions are sufficiently common to make the
subject a worthwhile diversion away from the topic of this newsgroup,
which
is C programming, *not* "C programming + Jacob Navia's AGC extensions".

Were this discussion taking place in Jacob Navia's own newsgroup,
comp.compilers.lcc, then I would not have raised any objections at all.
If all you were complaining about was topicality, then you should have said
so. But it looks to me more like you were complaining about garbage
collection itself, and you yourself were part of the "diversion" you are now
complaining about.

Anyhow, I agree with you that this is offtopic, so perhaps we should leave
this here.

Philip

Sep 1 '06 #42

P: n/a
Philip Potter said:
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:gb********************@bt.com...
>Perhaps, but you may be mistaken as to the issues at stake.

Perhaps. I haven't said very much yet, so it's a bit early to be drawing
conclusions.
But surely "you may be mistaken" is not a conclusion?

<snip>
You're right that AGC is not always suited to C. However, you said above:
>I just don't think it sits
very well with C, for at least two reasons:

suggesting you think it is /never/ suited to C.
I don't think I suggested that at all. I think I suggested that it doesn't
sit very well with C, which is not quite the same thing!

But I'm very much in favour of people being allowed to do what they want to
do as long as it doesn't hurt other people or frighten the horses. So if
people want to use AGC in some extended version of C, great, more power to
them - but I do very much hope that ISO continue to mandate the provision
of support for manual garbage collection via free(), so that those of us
who prefer to maintain manual control over our own programs' garbage
collection can continue to have that control.

<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 #43

P: n/a
On Fri, 1 Sep 2006, Richard Heathfield wrote:
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);
Your rebuttal is worse than the disease, because:

(1) If fwrite or fread fails, any further use of p will
invoke undefined behaviour.

(2) Even with error checking inserted, you would still be
leaking memory when fread fails.

(3) In general, writing pointers to files is always
nonportable. So, I am not sure why you are posting this in a
group that values portability.

Tak-Shing
Sep 1 '06 #44

P: n/a
Tak-Shing Chan <t.****@gold.ac.ukwrites:
(3) In general, writing pointers to files is always
nonportable. So, I am not sure why you are posting this in a
group that values portability.
Writing a pointer to a file is *not* always non-portable. It is
portable to write a pointer to a file, read it back within the
same run of the program, and then use the pointer (as long as the
lifetime of the associated memory has not been reached). This is
what Richard did.

Now, whether it's advisable to do so is another question. I
haven't encountered many (any?) situations where it is.
--
"Give me a couple of years and a large research grant,
and I'll give you a receipt." --Richard Heathfield
Sep 1 '06 #45

P: n/a
In article <87************@benpfaff.org>,
Ben Pfaff <bl*@cs.stanford.eduwrote:
>Writing a pointer to a file is *not* always non-portable. It is
portable to write a pointer to a file, read it back within the
same run of the program, and then use the pointer (as long as the
lifetime of the associated memory has not been reached).
Reference, please?

My recollection is that the relevant section says only that
when something is written out to a binary file, that the same
binary value will be read back in. When, though, it comes to a pointer,
that doesn't promise that the reconstituted pointer points to anything.

There is a section of the standard that talks about writing out
pointers and reading them back in, but that has to do with using
the %p printf() format, which Richard did not do.
--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)
Sep 1 '06 #46

P: n/a
On Fri, 1 Sep 2006, Ben Pfaff wrote:
Tak-Shing Chan <t.****@gold.ac.ukwrites:
> (3) In general, writing pointers to files is always
nonportable. So, I am not sure why you are posting this in a
group that values portability.

Writing a pointer to a file is *not* always non-portable. It is
portable to write a pointer to a file, read it back within the
same run of the program, and then use the pointer (as long as the
lifetime of the associated memory has not been reached).
An intervening realloc could mess it up.
This is
what Richard did.

Now, whether it's advisable to do so is another question. I
haven't encountered many (any?) situations where it is.

Tak-Shing
Sep 1 '06 #47

P: n/a
Tak-Shing Chan <t.****@gold.ac.ukwrites:
On Fri, 1 Sep 2006, Ben Pfaff wrote:
>Tak-Shing Chan <t.****@gold.ac.ukwrites:
>> (3) In general, writing pointers to files is always
nonportable. So, I am not sure why you are posting this in a
group that values portability.

Writing a pointer to a file is *not* always non-portable. It is
portable to write a pointer to a file, read it back within the
same run of the program, and then use the pointer (as long as the
lifetime of the associated memory has not been reached).

An intervening realloc could mess it up.
realloc terminates the memory's lifetime.
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Sep 1 '06 #48

P: n/a
ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) writes:
In article <87************@benpfaff.org>,
Ben Pfaff <bl*@cs.stanford.eduwrote:
>>Writing a pointer to a file is *not* always non-portable. It is
portable to write a pointer to a file, read it back within the
same run of the program, and then use the pointer (as long as the
lifetime of the associated memory has not been reached).

Reference, please?

My recollection is that the relevant section says only that
when something is written out to a binary file, that the same
binary value will be read back in. When, though, it comes to a pointer,
that doesn't promise that the reconstituted pointer points to anything.
Do you believe that you can portably copy pointers with memcpy?
Then why wouldn't you believe that you can portably read and
write pointers in a file, under the stated conditions? You need
not even use a binary file: you could encode the bits in the
pointers as plain text in hexadecimal or another notation, then
decode them when you read them back in.
--
"It wouldn't be a new C standard if it didn't give a
new meaning to the word `static'."
--Peter Seebach on C99
Sep 1 '06 #49

P: n/a
Tak-Shing Chan said:
On Fri, 1 Sep 2006, Richard Heathfield wrote:
<snip>
>>
<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);

Your rebuttal is worse than the disease, because:
No, it isn't. I agree that it's not a terribly bright idea, but it is legal
C. Yes, I omitted error-checking for brevity. This is not a student
discussion. It's a discussion amongst people who all know the importance of
error-checking, and we're all big enough and ugly enough to know where the
error-checking would go. This is just short-hand, that's all. If you want
full error-checking (as indeed I would, in a real program), you are
perfectly capable of adding it yourself.
(1) If fwrite or fread fails, any further use of p will
invoke undefined behaviour.
Sure, but error-checking would cope with that in a real program.
(2) Even with error checking inserted, you would still be
leaking memory when fread fails.
Yes, that's perfectly true. But when it succeeds, you would not be leaking
memory.
(3) In general, writing pointers to files is always
nonportable.
Why? If you mean that freestanding implementations don't need to have
filesystems, you're trivially but IMHO irrelevantly correct.

--
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 #50

94 Replies

This discussion thread is closed

Replies have been disabled for this discussion.