intercom5 said:
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.