473,890 Members | 1,397 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 4831
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
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
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
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 ReleaseLastStri ng(void)
{
free(to_release );
}

char const *CreateSubstrin g(char const *const p,
size_t const istart,size_t const iend)
{
int assert_dummy = (assert(!!p),as sert(!!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_relea se,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
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

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
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("abcdefg hijklmnop",2,7) ;
char *str2 = substr("abcdefg hijklmnop",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
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
Ben Pfaff <bl*@cs.stanfor d.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
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

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.