1

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?

4
  • 1
    It's unfortunately very hard to answer this question in a good manner. The reason is that you don't seem to have sufficient basic knowledge about pointers and string literals. I could write code that kind of works for you, but that would be confusing. I recommend reading about strings, pointers and string literals. Commented Sep 23, 2019 at 14:42
  • 1
    @klutt. I dunno, I kinda like my answer Commented Sep 23, 2019 at 14:44
  • @MadPhysicist I'm not sure. I get the feeling that while it is technically correct, I doubt that it teaches OP what he really needs to know. Commented Sep 23, 2019 at 14:46
  • @klutt. Barring the fact that we can never truly know what is in someone's mind, I've made an update. Commented Sep 23, 2019 at 14:51

3 Answers 3

4

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
Sign up to request clarification or add additional context in comments.

Comments

3

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.

Comments

2

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".
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.