Reputation: 364
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
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 char
s 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 char
s including the null terminator:
char s[100] = "hello"; // s[100] has space for 99 characters plus a null terminator.
Upvotes: 3
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
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