16

In C, I am trying to set a pointer's value by sending it to a function, but the value wont change outside of the function. Here is my code:

#include <stdio.h>
void foo(char* str) {

    char* new_str = malloc(100);
    memset(new_str, 0, 100);
    strcpy(new_str, (char*)"new test");

    str = new_str;
}


int main (int argc, char *argv[]) {

    char* str = malloc(100);
    memset(str, 0, 100);

    strcpy(str, (char*)"test");

    foo(str);

    printf("str = %s\n", str);
}  

I want to print out:

str = new test 

but this code prints out:

str = test

Any help will be appreciated. Thanks in advance.

Thomas
  • 1,103
  • 3
  • 13
  • 25

4 Answers4

29

There is no pass-by-reference in C. If you provide str as the argument to a function in C, you are always passing the current value of str, never str itself.

You could pass a pointer to str into the function:

void foo(char** pstr) {
    // ...
    *pstr = new_str;
}

int main() {
    // ...
    foo(&str);
}

As Eiko says, your example code leaks the first memory allocation. You're no longer using it, and you no longer have a pointer to it, so you can't free it. This is bad.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • "There is no pass-by-reference in C" - Isn't arrays passed by reference? – naivnomore Aug 19 '10 at 21:51
  • @naivnomore Basically you pass a pointer which is (at least syntactically) different to passing references in C++. – Eiko Aug 19 '10 at 21:56
  • 1
    No, they're not. Arrays decay to pointers when passed as parameters, but that's still not a pass-by-reference because changing the value of the pointer argument itself will not affect the array. – Tyler McHenry Aug 19 '10 at 21:56
  • 1
    @naivnomore: Well, they're passed as a pointer to the first element. Pass-by-pointer serves pretty much all the practical purposes of pass-by-reference, but it's not the same thing. C has the syntactic quirk that you can declare a function parameter `char[]`. That's synonymous with `char*`, but combined with array-to-pointer decay it looks like a pass-by-reference in inadequate light. The way to tell the difference is to use `sizeof` on the parameter inside the function, or assign to it. True pass-by-reference would maintain the type, as when you pass an array reference in C++. – Steve Jessop Aug 19 '10 at 21:57
  • It is true, though, that arrays aren't passed by value in C either, perhaps leading to the thought that by a process of elimination, they must be passed by reference. In fact they can't be passed as parameters at all, just pointers to them. It's technically incorrect (although commonly done, and normally understood) to refer to "passing an array" in C, or for that matter "passing a string". – Steve Jessop Aug 19 '10 at 22:00
  • @Steve Yep, there's a similar pass-by-reference misconception about Java. But it's simple: everything is passed by value. Sometimes you pass references (Java) or pointers (C) but the references/pointers themselves are still being passed by value. – Tyler McHenry Aug 19 '10 at 22:07
  • I think it's misleading to say there is no pass by reference in C. There is a difference between `foo(i)` and `foo(&i)`, and I think 'pass by reference' is a reasonable way to talk about it. Compared to C++, there are syntactic differences (you have to refer to the argument as `*i`) and safety differences (you can modify whatever you damn well please, but that's what we like about C), but otherwise it works the same way. – ladenedge Aug 19 '10 at 22:17
  • @ladenedge: well, maybe, but I think it would be more misleading to say that there is pass-by-reference in C. As I said: pass-by-pointer fulfils the practical needs, but it's not the language feature which exists in other languages under the name "pass-by-reference". It's passing *a* reference, sure. But the reference is a pointer, and it's passing the pointer by value. – Steve Jessop Aug 19 '10 at 22:22
  • @ladenedge It's not a matter of opinion. "pass by reference" and "pass by value" (and the much more rarely-used things like "pass by name") are well-defined technical terms in the domain of programming languages. Passing a pointer passes a *value* to the function. The fact that that value represents a memory address at which something else is stored is immaterial. Passing a reference in C++ is truly pass-by-reference because there is no value being passed; the parameter is in all senses a true alias name for the argument, which a pointer is not. – Tyler McHenry Aug 19 '10 at 22:23
4

You need to use pointer to the pointer, untested:

#include <stdio.h>

void foo(char** str)
{
    char* new_str = malloc(100);
    memset(new_str, 0, 100);
    strcpy(new_str, (char*)"new test");
    if (str) { /* if pointer to pointer is valid then */
        if (*str)   /* if there is a previous string, free it */
            free(*str);
        *str = new_str;  /* return the string */
    }
}


int main (int argc, char *argv[])
{
    char* str = malloc(100);
    memset(str, 0, 100);

    strcpy(str, (char*)"test");

    foo(&str);

    printf("str = %s\n", str);
}
Dummy00001
  • 16,630
  • 5
  • 41
  • 63
2

You are just reassigning a pointer, which is a local variable in foo.

If you want to copy the string, use strcpy(str, new_str);

You could pass a reference to the pointer instead and reassign, but this can easily lead to memory leaks and is hard to maintain.

Edit: For the pseudo pass by reference see the answer by Steve.

Eiko
  • 25,601
  • 15
  • 56
  • 71
0

I did it this way by returning the pointer from the function. There is no reason to use malloc in this case, so you don't have to worry about freeing.

gcc 4.4.3 c89

char* print_test(char *str)
{
    char *new_str =  "new_test";
    printf("new_str [ %s ]\n", new_str);
    str = new_str;
    return str;
}

int main(void)
{
    char *str = "test";

    printf("str [ %s ]\n", str);

    str = print_test(str);

    printf("str [ %s ]\n", str);

    return 0;
}
ant2009
  • 27,094
  • 154
  • 411
  • 609
  • 1
    This only partially works because you are assigning the pointer to a string in a const memory area in print_test(), but you return a non-const pointer. The signature needs to be const char* print_test(const char *str); so that in main, the memory pointed to by str can't be written to. Add str[0] = 'X'; printf("str [ %s ]\n", str); before return 0; to see the error. – Erik Nov 02 '21 at 15:25