Devin Ersoy
Devin Ersoy

Reputation: 364

How to change a pointer value between functions

I am new to C, and am confused on how to change the value of a char * between functions.

For example:

#include <stdio.h>
void testing(char *s) {
        s = "hi";
} // testing

int main() {
        char *s = "hello";
        testing(s);
        printf("%s\n", s);
} // main

In this case, the value of s is not changed, and "hello" is printed.

How can I change s, without having to change the return type or parameters of either function?

Upvotes: 1

Views: 1603

Answers (3)

Ian Abbott
Ian Abbott

Reputation: 17438

In main, char *s is initialized to the string literal "hello". This means s will be pointing to an anonymous array of 6 char containing the values { 'h', 'e', 'l', 'l', o', '\0' }. However, the contents of this array are not modifiable as far as the standard is concerned, so any code that writes to this array exhibits undefined behavior.

In the call to testing, the parameter char *s is treated as a local variable within the function. Any change to the pointer value will not affect the char *s variable in main. In C function calls, all parameters are passed by value.

Within testing, you change s to point to another string literal "hi". Similar to the initialization in main, testing's s will now point to an anonymous array of 3 char containing the values { 'h', 'i', '\0' }. The contents of this anonymous array are not modifiable. As mentioned above, this has no effect on main's s pointer.

You stated that you do not wish to modify the parameters or return type of either function. In order to do that, testing will need to overwrite the contents of the array pointed to by its parameter s. Since the current code in main has s pointing to a non-modifiable array, you will need to change it to point to a modifiable array. This can be done by changing main's s into an array instead of a pointer:

int main() {
        char s[] = "hello"; // N.B. s[] is 6 chars long including the null terminator
        testing(s);
        printf("%s\n", s);
} // main

Then you can change testing to overwrite the contents of the array pointed to by its parameter s:

#include <string.h>

void testing(char *s) {
        strcpy(s, "hi");
} // testing

I have made use of the strcpy standard library function in the above version of testing.

It is up to you to ensure that you do not write too many chars to the array pointed to by s.

The length of array s in main has been automatically set to 6 by the initializer "hello" (5 characters plus a null terminator character). You can set the length of the array explicitly if you need to overwrite more than 6 chars including the null terminator:

    char s[100] = "hello";  // s[100] has space for 99 characters plus a null terminator.

Upvotes: 3

Eric Postpischil
Eric Postpischil

Reputation: 223389

Functions receive only copies of argument values:

void f(int x)          // x is a new variable that is initialized to the argument value.
{
    x = x + 3;         // Adds 3 to the local x.
    printf("%d\n", x); // Prints 8.
}

int main(void)
{
    int x = 5;
    f(x);              // Passes 5, not x, to f.
    printf("%d\n", x); // Prints 5, not 8.
}

You can get a value back from a function by returning it:

int f(int x)           // Function is changed to return int.
{
    x = x + 3;         // Adds 3 to the local x.
    printf("%d\n", x); // Prints 8.
    return x;          // Returns new value.
}

int main(void)
{
    int x = 5;
    x = f(x);          // Set x from the value returned by the function.
    printf("%d\n", x); // Prints 8.
}

You can also get a value back from a function by having the function change the value of an object. To do this, you must provide the address of the object to the function:

void f(int *p)          // p is a pointer to an int.
{
    *p = *p + 3;        // Adds 3 to the pointed-to int.
    printf("%d\n", *p); // Prints 8.
}

int main(void)
{
    int x = 5;
    f(&x);             // Passes address of x to f.
    printf("%d\n", x); // Prints 8.
}

If you want a function to change a pointer, you can pass the address of a pointer:

void f(char **p)       // p is a pointer to a pointer to a char.
{
    *p = "hi"          // Sets *p to point to (first character of) "hi".
    printf("%s\n", x); // Prints "hi".
}

int main(void)
{
    char *s = "hello"; // Sets s to point to (first character of) "hello".
    f(&s);             // Passes address of s to f.
    printf("%s\n", x); // Prints "hi".
}

Upvotes: 2

Mad Physicist
Mad Physicist

Reputation: 114440

C function calls are strictly pass-by-value. This means that when you pass s to testing, a local copy is made. Assigning a new value to s in the function will therefore not affect the value in main.

Since the value of the pointer is copied, however, you can access the memory it points to. If s points to memory that isn't read-only, you could copy the contents of one buffer to another. For example, instead of s = "hi";,

strcpy(s, "hi");

In main, the statement char *s = "hello"; is likely to have s point to a read-only buffer. To make it a writable buffer, declare s as an array instead:

 char s[] = "hello";

If you want to change the value of the pointer, rather than what it points to, you need to pass in the address of the memory containing main's version of s: a pointer to a pointer. That would look like this:

#include <stdio.h>
void testing(char **s) {
        *s = "hi";
} // testing

int main() {
        char *s = "hello";
        testing(&s);
        printf("%s\n", s);
} // main

Another (perhaps better in this context) way is to use return values instead of parameters for both input and output:

#include <stdio.h>
char *testing(char *s) {
        s = "hi";
        return s;
} // testing

int main() {
        char *s = "hello";
        s = testing(s);
        printf("%s\n", s);
} // main

Upvotes: 4

Related Questions