3

How can I modify the value of a string being passed as argument in a function?

For example I have this function foo (that is supposed to change the value of return_string from "old string" to "new string"):

int foo(char *return_string) {
    char *tmp = "new string";
    return_string = tmp;
    return 0;
}

But if I call it in the following way:

char *s = "old string";
foo(s);
printf("%s\n", s);

I still get old string as output. Why?

I admit I have a little of confusion with pointers and strings in C.

Robb1
  • 4,587
  • 6
  • 31
  • 60

3 Answers3

4

The problem

In the function foo():

int foo(char *return_string) {
    char *tmp = "new string";
    return_string = tmp;
    return 0;
}

You are just assigning the pointer tmp to the pointer return_string. The parameter return_string is passed by value to foo() (i.e.: it is a copy of what the caller passed). Neither what return_string is pointing to (which may be what you want) nor the pointer passed is being modified.


strcpy()

Consider using strcpy() instead:

int foo(char *return_string) {
    char *tmp = "new string";
    strcpy(return_string, tmp);
    return 0;
}

This will modify the contents of the string pointed by return_string.


Passing the pointer by reference

Passing the pointer by reference, will make possible the modification of the pointer pointing to the string:

int foo(char **return_string) {
    char *tmp = "new string";
    *return_string = tmp;
    return 0;
}
Isacc Barker
  • 507
  • 4
  • 15
JFMR
  • 23,265
  • 4
  • 52
  • 76
  • `return_string = &tmp;` should be `*return_string = tmp;` – mch Jan 17 '18 at 09:23
  • @mch `tmp` has automatic storage duration, so it does not exist after leaving the function. It didn't make sense at all. – JFMR Jan 17 '18 at 09:28
  • `*return_string = tmp;` is okay, if `tmp` points to a string literal. Using `&tmp` is dangerous. – mch Jan 17 '18 at 09:30
  • If I'm passing the pointer by reference should I call `foo` in such a way? `char *s = "old string"; foo(&s); printf("%s\n", s);` – Robb1 Jan 17 '18 at 09:47
  • Yes, in order to pass the pointer `s` by reference, use `foo(&s)` (i.e.: pass the address of the pointer). – JFMR Jan 17 '18 at 09:48
0

You are passing the pointer by value. You need to pass the pointer by reference.

Change the function interface to pass a char** return_string instead of a char* return_string. And then do *return_string = tmp;.

Morten Jensen
  • 5,818
  • 3
  • 43
  • 55
0

Provided that your strings are dynamically allocated, it might be implemented as follows

int foo(char **return_string) {
    if (*return string) free(*return_string)
    *return_string = strdup("new string");
    return 0;
}

char* s = strdup("original");
foo(&s);
....
AndreyS Scherbakov
  • 2,674
  • 2
  • 20
  • 27
  • nothing guarantees that the argument is dynamically allocated. – Jean-François Fabre Jan 17 '18 at 09:13
  • try `char *test="hello"; foo(&hello);` => BANG! the caller is responsible for the memory leak when passing a pointer on a pointer. – Jean-François Fabre Jan 17 '18 at 09:40
  • Yes of course. You will need some agreement on how do you allocate your strings. If you use dynamic allocation, it's the most universal solution (you will need to avoid storing constants, but it's not the worst restriction. Say, when you use strcpy - based approach, you'll need to worry about buffer size. All options have their drawbacks. The best solution might be your own string container with an explicit deallocator pointer.. but it's probably beyond the scope of the question in hand. – AndreyS Scherbakov Jan 17 '18 at 09:47