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

Dynamic C String Question

P: n/a
I'm writing a program in C, and thus have to use C strings. The
problem that I am having is I don't know how to reallocate the space
for a C string outside the scope of that string. For example:
int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(string1);

}

void foo(char *string)
{
string = realloc(string, 12);
strcat(string, " World");
}
In this example, I reallocate the space for a string declacred in
another function in the function foo. But, after it returns to main
from the function foo, the C string will only contain "Hello". The
changes from the function foo have disappered. I suspect this is
because the reallocation has gone out of scope - and I have no idea how
to keep the changes after the function returns.
Any help would greatly be appreciated.

--Sachin

Nov 14 '05 #1
Share this Question
Share on Google+
18 Replies


P: n/a
intercom5 wrote:
I'm writing a program in C, and thus have to use C strings. The
problem that I am having is I don't know how to reallocate the space
for a C string outside the scope of that string. For example:
int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(string1);

}

void foo(char *string)
{
string = realloc(string, 12);
strcat(string, " World");
}
In this example, I reallocate the space for a string declacred in
another function in the function foo. But, after it returns to main
from the function foo, the C string will only contain "Hello". The
changes from the function foo have disappered. I suspect this is
because the reallocation has gone out of scope - and I have no idea how
to keep the changes after the function returns.


pointer to pointer could be the answer.

int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(&string1);

}

void foo(char **string)
{
*string = realloc(string, 12);
strcat(*string, " World");
}
Nov 14 '05 #2

P: n/a
intercom5 wrote:
I'm writing a program in C, and thus have to use C strings. The
problem that I am having is I don't know how to reallocate the space
for a C string outside the scope of that string. For example:
int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(string1);

}

void foo(char *string)
{
string = realloc(string, 12);
strcat(string, " World");
}
In this example, I reallocate the space for a string declacred in
another function in the function foo. But, after it returns to main
from the function foo, the C string will only contain "Hello". The
changes from the function foo have disappered. I suspect this is
because the reallocation has gone out of scope - and I have no idea how
to keep the changes after the function returns.


Actually the subtle change is because , realloc has moved everything
to a new address. (it is allowed to do that, of course ) because
the requested new size is > the prev. size.

OTOH, if you had requested less than the original size,
then it may not move it and just reallocate memory.
In that case, the original pointer might be still valid
after the function returns.

realloc is a multi-edged sword, indeed :) . Use it with care.
Nov 14 '05 #3

P: n/a


intercom5 wrote:
I'm writing a program in C, and thus have to use C strings. The
problem that I am having is I don't know how to reallocate the space
for a C string outside the scope of that string. For example:
int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(string1);

}

void foo(char *string)
{
string = realloc(string, 12); /* Where did u get this magic 12 ? not a good practise. */
strcat(string, " World");
} Always check for return values of *alloc functions.
Return the string from foo !
Modified version is:

char *foo (char *string)
{
string = realloc(string, 12);
if (string)
strcat(string, " World");

return string;
}
int main(void)
{
char *string1;
string1 = malloc(6);
if (!string1)
return 0; /* Handle failures before returning. */

sprintf(string1, "Hello"); /* Just strcpy would do here -
strcpy(string1, "Hello"); */
string1 = foo(string1);
puts (string1);
return 0;
}


In this example, I reallocate the space for a string declacred in
another function in the function foo. But, after it returns to main
from the function foo, the C string will only contain "Hello". The
changes from the function foo have disappered. I suspect this is
because the reallocation has gone out of scope - and I have no idea how
to keep the changes after the function returns.
Any help would greatly be appreciated.

--Sachin


Nov 14 '05 #4

P: n/a
Karthik Kumar wrote:
pointer to pointer could be the answer.

int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(&string1);

}

void foo(char **string)
{
*string = realloc(string, 12); ^
missing '*', innit? strcat(*string, " World");
}

Nov 14 '05 #5

P: n/a
"Karthik Kumar" <ka*******************@yahoo.com> wrote in message
news:41c90b47$1@darkstar...
Actually the subtle change is because , realloc has moved everything
to a new address. (it is allowed to do that, of course ) because
the requested new size is > the prev. size.
It is allowed to do that in all cases !
OTOH, if you had requested less than the original size,
then it may not move it and just reallocate memory.
In that case, the original pointer might be still valid
after the function returns.
don't rely in this : C99 just hints that the new and old pointers may be the
same, but they may also be different, even if the size doesn't change or if it
is reduced.
realloc is a multi-edged sword, indeed :) . Use it with care.


Or even better : realloc() is too complex to use for newbies, it has an error
prone API, it is *strongly* recommended to not use it at all !

--
Chqrlie.
Nov 14 '05 #6

P: n/a
thanks guys. using a pointer to a pointer worked.

Nov 14 '05 #7

P: n/a
intercom5 wrote:
I'm writing a program in C, and thus have to use C strings. The
problem that I am having is I don't know how to reallocate the space
for a C string outside the scope of that string. For example:
int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(string1);

}

void foo(char *string)
{
string = realloc(string, 12);
Quite apart from the problem you know you have, you also have a couple
of problems you don't know you have.
strcat(string, " World");
}
In this example, I reallocate the space for a string declacred in
another function in the function foo. But, after it returns to main
from the function foo, the C string will only contain "Hello". The
changes from the function foo have disappered. I suspect this is
because the reallocation has gone out of scope - and I have no idea how
to keep the changes after the function returns.
Any help would greatly be appreciated.


If you want a function to update a value in an object available to
the calling function, you pass that object's address to the
function. Now, in this case your object is called string1. It
happens to be a pointer, but that doesn't make it special. If you
want foo() to alter the value of string1, you must pass string1's
address to foo().

The following code is based heavily on your own code; I have changed
the indentation to make it more readable to others, and added error
checking, but I haven't "fixed" the code to my own style and preference,
tempting though the idea was.

#include <stdio.h> /* 1 */
#include <stdlib.h> /* 2 */

int foo(char **); /* 3 */

int main(void)
{
char *string1;
string1 = malloc(6);
if(string1 != NULL) /* 4 */
{
sprintf(string1, "%s", "Hello"); /* 5 */
if(foo(&string1) == 0) /* 6 */
{
printf("%s\n", string1);
}
free(string1); /* 7 */
}

return 0; /* 8 */
}

int foo(char **string) /* 9 */
{
char *p = realloc(*string, 12); /* 10 */
if(p != NULL) /* 11 */
{
*string = p; /* 12 */
strcat(*string, " World"); /* 13 */
}
return p == NULL; /* 14 */
}

Notes

1. Prototype for sprintf (and a printf I added myself).
2. Prototype for malloc and free.
3. Prototype for foo. Note the change in return type,
as well as the change in arg type.
4. After a resource request, check that the request
succeeded instead of just assuming it did.
5. When sprintfing, bear in mind that your data may
contain formatting characters relevant to sprintf
(e.g. %). To avoid this from causing alarming
problems, always specify a format string.
6. Pass the ADDRESS of string1 to foo, and CHECK
the return value.
7. When you've finished with a resource, give it back.
8. main() returns int, so return an int from main().
9. We need to update a pointer and have that change
"stick", so we accept a pointer to the pointer.
10. Note the use of the temporary object p. This
temporary object can catch the return value from
realloc. If realloc fails, p will be NULL, but
*string will remain unchanged, so we at least
can still use the memory we started with.
Also note the use of *string rather than string.
11. See note 4.
12. If the request succeeded, we can (and indeed
MUST) update *string with the new value; the
old value may no longer valid and should not
be used. (If it /is/ still valid, then p == *string
anyway, but there's no way to test for this
without using *string's value, which - as I said -
may not be valid!)
13. Note again the use of *string.
14. This function needs some way of communicating to
its caller whether the allocation request succeeded
or not. An easy way to do this is via an int
return value (here, I chose 0 == success, non-0
== failure).

Sorry for the long reply. HTH. HAND.
Nov 14 '05 #8

P: n/a
Karthik Kumar wrote:

<snip>

pointer to pointer could be the answer.

int main(void)
{
char *string1;
string1 = malloc(6);
sprintf(string1, "Hello");
foo(&string1);

}

void foo(char **string)
{
*string = realloc(string, 12);


This won't work. You meant:

*string = realloc(*string, 12);

Had you tested your code before posting, you'd have discovered this.

Nov 14 '05 #9

P: n/a
Karthik Kumar wrote on 22/12/04 :
void foo(char **string)
{
*string = realloc(string, 12);


*string = realloc(*string, 12);

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++

Nov 14 '05 #10

P: n/a
Charlie Gordon wrote:
"Karthik Kumar" <ka*******************@yahoo.com> wrote in message
news:41c90b47$1@darkstar...
realloc is a multi-edged sword, indeed :) . Use it with care.

Or even better : realloc() is too complex to use for newbies, it has an error
prone API, it is *strongly* recommended to not use it at all !


I used to think the same thing, but the reality is that realloc is
just too useful to discard.

It does take a modicum of care to use realloc correctly but, once
you have learned how to do it, it's actually not at all complex. Anyone
who cannot master realloc is going to struggle in their programming
career, for the simple reason that they are required to master lots
of stuff that is much, much more complex than realloc.
Nov 14 '05 #11

P: n/a
On Wed, 22 Dec 2004 06:50:35 +0000 (UTC)
infobahn <in******@btinternet.com> wrote:
Karthik Kumar wrote:

<snip>

pointer to pointer could be the answer.

int main(void)
{
char *string1;
string1 = malloc(6);
You need to test to see if malloc has failed.
sprintf(string1, "Hello");
foo(&string1);

}

void foo(char **string)
{
*string = realloc(string, 12);


This won't work. You meant:

*string = realloc(*string, 12);

Had you tested your code before posting, you'd have discovered this.


Also, if the realloc fails you have lost your pointer to the memory you
still have allocated.

void foo(char **my_string)
{
char *tmp = realloc(*my_string, 12);
if (tmp == NULL) {
/* handle error */
}
else {
*my_string = tmp
}
}

I've also changed the name because identifiers starting with str
followed by another letter, such as string, are reserved.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #12

P: n/a


infobahn wrote:


The following code is based heavily on your own code; I have changed
the indentation to make it more readable to others, and added error
checking, but I haven't "fixed" the code to my own style and preference,
tempting though the idea was.

I realize that you are using the routines provided by the op, but
without too much trouble you can provide protection should the function
be called with no previous allocations, i.e. should *string == NULL.
If you do this then you need not worry with doing the initial allocation
in function main. Instead, use the function for the initial string and
subsequent appends.

int foo(char **string) /* 9 */
{
char *p = realloc(*string, 12); /* 10 */
if(p != NULL) /* 11 */
{
*string = p; /* 12 */
strcat(*string, " World"); /* 13 */
}
return p == NULL; /* 14 */
}


Should *string be NULL and the allocation succeed, you would
need to assign string[0] the value of '\0' for the strcat
function to work.

Example:

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

int dCatStr(char **s, const char *catstr)
{
char *tmp;
size_t curlen = *s?strlen(*s):0;

if((tmp = realloc(*s,curlen+strlen(catstr)+1)) != NULL)
{
if(curlen == 0) *tmp = '\0';
*s = tmp;
strcat(*s,catstr);
}
return tmp?1:0;
}

int main(void)
{
char *string1 = NULL;

if(dCatStr(&string1,"Hello"))
if(dCatStr(&string1," World!"))
printf("string1 = \"%s\"\n",string1);
else puts("FAILURE: to append");
else puts("FAILURE: to append");
free(string1);
return 0;
}

--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #13

P: n/a
Flash Gordon wrote:
On Wed, 22 Dec 2004 06:50:35 +0000 (UTC)
infobahn <in******@btinternet.com> wrote:

Karthik Kumar wrote:

<snip>
pointer to pointer could be the answer.

int main(void)
{
char *string1;
string1 = malloc(6);


You need to test to see if malloc has failed.


Well, Earthik Kumar does. If you glance over my
reply to the OP, you'll find that I addressed
this issue, and all the others you mentioned, except ...

<snip>
void foo(char **my_string)
{
char *tmp = realloc(*my_string, 12);
if (tmp == NULL) {
/* handle error */
}
else {
*my_string = tmp
}
}

I've also changed the name because identifiers starting with str
followed by another letter, such as string, are reserved.


Not local identifiers.
Nov 14 '05 #14

P: n/a
Al Bowers wrote:


infobahn wrote:


The following code is based heavily on your own code; I have changed
the indentation to make it more readable to others, and added error
checking, but I haven't "fixed" the code to my own style and preference,
tempting though the idea was.

I realize that you are using the routines provided by the op,


Right.
but
without too much trouble you can provide protection should the function
be called with no previous allocations, i.e. should *string == NULL.
If you do this then you need not worry with doing the initial allocation
in function main. Instead, use the function for the initial string and
subsequent appends.
I thought I'd squeezed all the juice out of it, but you're right - I
should have suggested this myself. Apologies for my omission.

<snip>
Example:

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

int dCatStr(char **s, const char *catstr)
{
char *tmp;


It would be profitable to add an assertion here:

assert(s != NULL);

before dereferencing s. This would of course involve including
<assert.h> and, in C90, enclosing the remainder of the code in
a block { }, or separating the definition of curlen from the
test on *s (for the obvious reason).

<snip>
Nov 14 '05 #15

P: n/a
infobahn wrote on 22/12/04 :
I've also changed the name because identifiers starting with str
followed by another letter, such as string, are reserved.


Not local identifiers.


Saiz who ?

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"

Nov 14 '05 #16

P: n/a
Emmanuel Delahaye wrote:
infobahn wrote on 22/12/04 :
I've also changed the name because identifiers starting with str
followed by another letter, such as string, are reserved.

Not local identifiers.

Saiz who ?


ANSI, if I'm reading the Standard correctly.

****
4.13 FUTURE LIBRARY DIRECTIONS

The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.
****

The possibility remains that I am not reading the Standard correctly.
Nov 14 '05 #17

P: n/a
infobahn wrote on 23/12/04 :
Emmanuel Delahaye wrote:
infobahn wrote on 22/12/04 :
I've also changed the name because identifiers starting with str
followed by another letter, such as string, are reserved.

Not local identifiers.


Saiz who ?


ANSI, if I'm reading the Standard correctly.

****
4.13 FUTURE LIBRARY DIRECTIONS

The following names are grouped under individual headers for
convenience. All external names described below are reserved no
matter what headers are included by the program.
****

The possibility remains that I am not reading the Standard correctly.


A static (hence 'not external') function with str* (say strcmp()) will
shadow the external strcmp() from the standard library. According to
the standard, technically correct, but bad practice IMO.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"

Nov 14 '05 #18

P: n/a
Emmanuel Delahaye wrote:

<snip>

A static (hence 'not external') function with str* (say strcmp()) will
shadow the external strcmp() from the standard library. According to the
standard, technically correct, but bad practice IMO.


Shadowing names that are already known to exist in the standard library
is, of course, not just bad practice but terrible practice.

In this case, however, no such shadowing was done. In my own code, I
avoid starting names with str*, but I saw no reason to amend the OP's
code in my own article, since I figured I'd already given him enough
to think about. :-)

Nov 14 '05 #19

This discussion thread is closed

Replies have been disabled for this discussion.