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?
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
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.
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".
}
Related
i want to ask a question about pointer:
void fun(const char** a) {...}
1.
const char* b = nullptr;
fun(&b);
2.
const char** b = nullptr;
fun(b);
why use 1 but not 2?
1 is good, 2 donnot work
C uses pass by value for function call arguments. That means a function receives a copy of the passed value, and there's no way for the function to directly change a variable in the caller.
For example, if you write
void set_to_5(int x)
{
x = 5;
}
and then write
int i = 3;
set_to_5(i);
printf("%d\n", i);
it prints 3, not 5. Or, if you write
void set_string(char *str)
{
str = "world";
}
and then write
char *p = "hello";
set_string(p);
printf("%s\n", p);
it prints hello, not world.
In both cases, the function successfully changes its copy of the passed value — x or str — but that doesn't have any effect on the variable in the caller (i or p).
When you want to have a function that does change a variable in its caller, one way to do that is to have the function accept a pointer. That looks like this:
void set_to_5_via_pointer(int *x)
{
*x = 5;
}
void set_string_via_pointer(char **str)
{
*str = "world";
}
Then you can write:
int i = 3;
set_to_5_via_pointer(&i);
printf("%d\n", i);
char *p = "hello";
set_string_via_pointer(&p);
printf("%s\n", p);
Now it does print 5 and world, as desired.
Notice that in each case I made three changes:
I added a * to the parameter type expected by the function (int x to int *x, char *str to char **str)
I added a * before each use of the parameter in the function, that is, where I actually set the new value (5 and "world")
I added a & before the variables where I passed them to the function (set_to_5_via_pointer(&i) and set_string_via_pointer(&p)).
One more thing. When you see a function declaration like
void set_string_via_pointer(char **str);
this does not necessarily mean that the right way to call the function is
char **x;
set_string_via_pointer(x);
Yes, here x is of type char **, and function set_string_via_pointer expects an argument of type char **, so it's a match. But if you declare and call
char *y;
set_string_via_pointer(&y);
that's also a perfectly good way to pass an argument of type char **, and in this case, it's certainly they way that was expected.
const char* b = nullptr;
fun(&b);
This passes the pointer b by reference — or emulates pass by reference semantics — i.e. the memory address of where the variable is stored is passed instead of its value. This allows you to access the pointer originally declared in the calling function, and any changes made to that pointer in the called function would be visible in the calling function.
const char** b = nullptr;
fun(b);
Au contraire, this passes b by value. If you change the pointer to point to some other memory location in the called function, that change will not be reflected back in the calling function. Any attempt to dereference it while it is pointing to NULL would result in undefined behaviour as per the following clauses of C11:
If an invalid value has been assigned to the pointer, the behavior of
the unary * operator is undefined.
[...]
Among the invalid values for dereferencing a pointer by the unary *
operator are a null pointer, [...]
[6.5.3.2 Address and indirection operators, C11]
why use 1 but not 2?
Why use either of them?
1 is good, 2 donnot work
“There is nothing either good or bad, but thinking makes it so.” — They both serve different purposes. Though, the purpose of the second snippet is rather ambiguous here.
This code snippet
void fun(const char** a) {...}
1.
const char* b = nullptr;
fun(&b);
means passing the pointer b to the function fun by reference in the C meaning. So dereferencing the pointer to pointer a within the function you can change the original pointer b passed to the function indirectly through a pointer to it.
Here is a demonstration program.
#include <stdio.h>
void fun( const char **a )
{
*a = "Hello World!";
}
int main( void )
{
const char *b = NULL;
fun( &b );
puts( b );
}
The program output is
Hello World!
As you can see the pointer b is passed to the function indirectly through a pointer to it (by reference in the C meaning). Thus dereferencing the pointer to pointer a
*a = "Hello World!";
you can change the original pointer b defined in main.
In the second case
2.
const char** b = nullptr;
fun(b);
the pointer b is passed by value and if the function fun will dereference the null pointer then undefined behavior will be invoked.
When I was introduced to pointers, I was told that they are useful because they let us modify certain variables fed into functions that wouldn't normally be modifiable. For example:
void copy(int *p, int *s);
int main(){
int a = 4, b = 10, *p = &a, *s = &b;
copy(p, s);
}
void copy(int *p, int *s){
*s = *p;
*p = 0;
}
So at the end of this, "b" is equal to "a", and "a" is equal to 0, even though "a" and "b" wouldn't normally be modifiable.
When talking about lists and, specifically, adding an element to a list, I can use a function like this:
struct list{
int n;
struct list *next;
}
struct list *first = NULL;
int main(){
int n = 3;
first = add_to_list(first, n);
}
struct list *add_to_list(struct list *first, int n){
struct list *new_node;
new_node = malloc(sizeof(struct list));
if(new_node == NULL) exit(EXIT_FAILURE);
new_node->value = n;
new_node->next = first;
return new_node;
}
What concerns me specifically is why the function can't simply return a type void, and instead of writing "return new_node", I can't simply write "first = new_node". Because first is a pointer, if I modify it anywhere in my program the original pointer should be modified too, just like it happened in the first example I made, right?
Also, bit of an unrelated question, but if I've got a function like this:
void first_to_n(int a[], int n){
a[0] = n;
}
The first element of the original vector a, which lets say is declared in main, gets also modified, right? Because vectors can be considered as pointers
Lets say we have something like the following code
void funcA(int x)
{
x = 0;
}
void funcB(int *y)
{
y = NULL;
}
int main(void)
{
int a = 10;
int *b = &a;
funcA(a);
funcB(b);
}
What happens when funcA is called is that the value of a is copied into the separate variable x inside the function. When the call is being made there are two copies of the value 10 stored in to different places. When the assignment x = 0 is done inside the function, only the local variable x is modified.
For funcB just the same happens. The value of the variable b is copied into the separate variable y in the function. That means there are two separate and distinct variable pointing to the same location. But once the assignment y = NULL is done, that's no longer true. The variable y is no longer pointing to the same location, but in the main function b is unmodifed since only a copy of the value was passed to the function.
If we now take a slightly different example
void func(int *x, int **y)
{
*y = x;
}
int main(void)
{
int a = 10;
int b = 20;
int *c = &a; // Make c point to the variable a
func(&b, &c);
}
After the function is called, then c does no longer point to a, it points to b. That's because for the second argument the value we pass is &c which is a pointer to the variable c. Inside the function we can then use the dereference operator to access what y is pointing to (which will be the variable c in the main function).
When I was introduced to pointers, I was told that they are useful because they let us modify certain variables fed into functions that wouldn't normally be modifiable.
Among other things, like creating non-trivial data structures and to avoid copies.
Because first is a pointer, if I modify it anywhere in my program the original pointer should be modified too, just like it happened in the first example I made, right?
first (the parameter) is a copy of first (the global). Therefore, first = new_node would only modify your pointer, not the global one.
This is more clear in your first example:
void copy(int *p, int *s){
*s = *p;
*p = 0;
}
If you were doing p = 0;, for instance, you would only modify the pointer, not the value pointed to.
The first element of the original vector a, which lets say is declared in main, gets also modified, right? Because vectors can be considered as pointers
That is not a "vector" (array), it is a pointer even if it looks like an array. It is a big gotcha of C.
But, indeed, a[0] = 0; is modifying the first value (in main) pointed by the parameter.
What concerns me specifically is why the function can't simply return
a type void, and instead of writing "return new_node", I can't simply
write "first = new_node".
As the other answers explain, you can't due to first being a 'copy' of the pointer outside the function. If however you were to instead change the function such that you passed a 'pointer to the pointer' rather that just the 'pointer', then you could change the external value, which is what's going on the in the 'copy' function.
This uses a pointer to a literal string.
The pointer is pass to modifypointer() where it is modified to point to another literal string. The new literal string is printed in the function, but main() still prints the original.
The pointer is passed as a pointer to itself in modifypointertopointer() where it is dereferenced to point to another literal string. Now the function prints the new literal string and main() also prints the new literal string.
In your last example, first = new_node; could be used except the function declares a shadow variable first and the global first is no longer in the scope of the function.
#include <stdio.h>
void modifypointer( char *mod) {
mod = "modify pointer";
printf ( "%s\n", mod);
}
void modifypointertopointer( char **ptrmod) {
*ptrmod = "modify pointer to pointer";
printf ( "%s\n", *ptrmod);
}
int main( void) {
char *text = "original";
printf ( "%s\n", text);
modifypointer ( text);
printf ( "%s\n", text);
modifypointertopointer ( &text);
printf ( "%s\n", text);
return 0;
}
I try to convert a decimal number to its its hexadecimal representation (and want to get only the fourth LSB digits).
It is seems that my function do works, but when i try to get the value of the number from the main function, i get all the digits and x1!=x2.
Where do I wrong?
here is my code:
char* dec_to_hex_converter(int num, char x[])
{
int i = 1;
int size = 0;
sprintf(x, "%04X\n", num);
size = strlen(x);
if (size > 4)
{
while (size > 4)
{
x++;
size--;
}
x--;
}
*(x + 4) = '\0';
printf("x1=%s\n", x);
return x;
}
int main()
{
char x[10];
dec_to_hex_converter(-16,x);
printf("x2=%s\n", x);
}
I want to get FFF0
but when I print the result I get FFFFFFF0 (ONLY OUTSIDE THE FUNCTION)
thanks in advance
The x pointer that is being printed out inside dex_to_hex_converter() has been moved to the middle of the character array. So only half of the string is printed.
char [] = "FFFFFFF0\0"
^
|
x
When you return to main(), the pointer x, which was passed by value, returns to its original value pointing to the beginning of the character array, and so, the whole string is once again printed out.
char [] = "FFFFFFF0\0"
^
|
x
To access only the portion of the string you want...use the pointer returned, not the one passed in :
printf("ret=%s\n", dec_to_hex_converter(-16, x));
When you change x in the function, you only change a local pointer that was initialized with the x array from main.
In fact the function declaration is seen by the compiler as:
char* dec_to_hex_converter(int num, char *x)
To really understand it, you could control the return value:
int main()
{
char x[10];
char *cur = dec_to_hex_converter(-16,x);
printf("x2=%s (returned:%s\n", x, cur);
printf("delta %d\n", cur - x);
return 0;
}
Output would be:
x1=FFF0
x2=FFFFFFF0 (returned:FFF0)
delta 4
You seem to mix some concepts.
In your title you mention a string returned by a function.
If you want to return a string you can use it as follows:
int main()
{
char x[10];
char *result = dec_to_hex_converter(-16,x);
printf("x2=%s\n", result);
}
In your code you try to change the passed pointer. This would require to pass a "reference" to it instead of the pointer itself. (In C there are no real references. You need to pass a pointer to the pointer instead)
And most important you need to pass a modifyable lvalue to the function.
The address of an array is not modifyable.
I'm trying to build a program that modifies the element of an array through a pointer to a pointer. I loaded it into the debugger and I see that the value of my pointer changes, but for some reason that doesn't affect the element in the array. Is my pointer syntax wrong? Am I reassigning my pointer somewhere else?
#include <stdio.h>
#include <stdlib.h>
#define SIZE 6
/*
*
*/
void change (char **x);
int main() {
char arra[] = "Back";
char *c = arra;
change(&c);
int i;
printf("%c", arra[0]);
}
void change (char **x) {
*x = "H";
}
*x = "H";
should be
**x = 'H';
You are trying to modify the first character and character has to be within single quotes.
There is no need of pointer to pointer here. You can just pass the array which decays to a pointer when passed in the function parameterks as shown by #haccks
No need to use pointer to pointer in this case. Just use pointer to char.
void change (char *x);
and call it as
change(c);
with the function body
void change (char *x) {
*x = 'H';
}
int main()
{
char *x = "HelloWorld";
char y[] = "HelloWorld";
x[0] = 'Z';
//y[0] = 'M';
return 0;
}
In the above program, HelloWorld will be in read-only section(i.e string table). x will be pointing to that read-only section, so trying to modify that values will be undefined behavior.
But y will be allocated in stack and HelloWorld will be copied to that memory. so modifying y will works fine. String literals: pointer vs. char array
Here is my Question:
In the following program, both char *arr and char arr[] causes segmentation fault if the content is modified.
void function(char arr[])
//void function(char *arr)
{
arr[0] = 'X';
}
int main()
{
function("MyString");
return 0;
}
How it differs in the function parameter context?
No memory will be allocated for function parameters??
Please share your knowledge.
Inside the function parameter list, char arr[] is absolutely equivalent to char *arr, so the pair of definitions and the pair of declarations are equivalent.
void function(char arr[]) { ... }
void function(char *arr) { ... }
void function(char arr[]);
void function(char *arr);
The issue is the calling context. You provided a string literal to the function; string literals may not be modified; your function attempted to modify the string literal it was given; your program invoked undefined behaviour and crashed. All completely kosher.
Treat string literals as if they were static const char literal[] = "string literal"; and do not attempt to modify them.
function("MyString");
is similar to
char *s = "MyString";
function(s);
"MyString" is in both cases a string literal and in both cases the string is unmodifiable.
function("MyString");
passes the address of a string literal to function as an argument.
char *arr;
above statement implies that arr is a character pointer and it can point to either one character or strings of character
& char arr[];
above statement implies that arr is strings of character and can store as many characters as possible or even one but will always count on '\0' character hence making it a string
( e.g. char arr[]= "a" is similar to char arr[]={'a','\0'} )
But when used as parameters in called function, the string passed is stored character by character in formal arguments making no difference.