I want to change the actual argument passed to a function and not a copy of it. For example:
char str[] = "This is a string";
I want to create a function after a call to which the value of str is different. I tried to create a function accepting char** as the argument but I just couldn't get what I want.
I think you mean something like this:
void update_string(char ** ptr)
{
*ptr = strdup("This is a test");
return;
}
Then call the function like this:
char * str = strdup("hello world\n");
printf("%s\n", str);
update_string(&str);
printf("%s\n", str);
You may pass char*. The pointer will be copied, but it will still point to the same string
If you need the pointer itself to be passed (not its copy) you should pass a char**
To change a string passed to a function in-place, use a regular pointer. For example:
void lower_first_char(char *str)
{
*str = tolower(*str);
}
After this function executes, the first character of the passed string will be changed to lowercase.
Pass a char* if you want to modify the actual string:
foo(str);
...
void foo(char *some_string) {
some_string[0] = 'A';
}
str will now hold "Ahis is a string"
If instead of str being an array, you had: char *str = "Hello";, and wanted to modify where str pointed, then you would pass a char**:
bar(&str);
...
void bar(char **ptr_string) {
*ptr_string = "Bye";
}
str will now point to "Bye".
Related
This question already has answers here:
How to change value of variable passed as argument?
(4 answers)
Closed 5 years ago.
How can I modify the value of a string being passed as argument in a function?
For example I have this function foo (that is supposed to change the value of return_string from "old string" to "new string"):
int foo(char *return_string) {
char *tmp = "new string";
return_string = tmp;
return 0;
}
But if I call it in the following way:
char *s = "old string";
foo(s);
printf("%s\n", s);
I still get old string as output. Why?
I admit I have a little of confusion with pointers and strings in C.
The problem
In the function foo():
int foo(char *return_string) {
char *tmp = "new string";
return_string = tmp;
return 0;
}
You are just assigning the pointer tmp to the pointer return_string. The parameter retrun_string is passed by value to foo() (i.e.: it is a copy of what the caller passed). Neither what return_string is pointing to is being modified (which may be what you want) nor the pointer passed is keeps the modification at the caller's side.
strcpy()
Consider using strcpy() instead:
int foo(char *return_string) {
char *tmp = "new string";
strcpy(return_string, tmp);
return 0;
}
This will modify the contents of the string pointed by return_string.
Passing the pointer by reference
Passing the pointer by reference, will make possible the modification of the pointer pointing to the string:
int foo(char **return_string) {
char *tmp = "new string";
*return_string = tmp;
return 0;
}
You are passing the pointer by value. You need to pass the pointer by reference.
Change the function interface to pass a char** return_string instead of a char* return_string.
And then do *return_string = tmp;.
Provided that your strings are dynamically allocated, it might be implemented as follows
int foo(char **return_string) {
if (*return string) free(*return_string)
*return_string = strdup("new string");
return 0;
}
char* s = strdup("original");
foo(&s);
....
I fell over this little thing while coding:
char* strinit(char* str) {
str = (char*) malloc(100);
strcpy(str, "hello SO");
return str;
}
int main()
{
char* str = strinit(str);
return 0;
}
As you can see, I am using the same variable that I am declaring to initialize it. This is no problem. I tried the same thing in Java. That causes errors.
So my question is: Is there any problems doing this? Can I use it in my code in good conscience?
C & C++ consider that char* str = strinit(str); is legal; because it is evaluated to:
char* str;
str = strinit(str);
see Why is 'int i = i;' legal?
Not everything you can do should be done. The code
char* strinit(char* str) {
str = (char*) malloc(100);
strcpy(str, "hello SO");
return str;
}
uses a parameter only as a local variable. You should change it to
char* strinit(void) {
char* str = malloc(100);
strcpy(str, "hello SO");
return str;
}
and call the function without parameters.
Edit:
There is only a little problem with the actual call of your function. The value of the variable str in the main function is passed to the strinit function. This is cheap in your case. But this can be expensive if the parameter type is a more complex type. The compiler will create a copy of the parameter what can call the objects constructor. Of course, the copy of a pointer is cheap.
this is a sample program demonstrating getting a string value from a func
can allocate memory inside called function itself and return
can allocate memory inside calling function and called function just updates it.
i am facing problem with the 2nd way.
is there any workaround?
/*
* main.c
*
* Created on: Sep 6, 2014
* Author: Murtaza
*/
#include<stdio.h>
#include<stdlib.h>
char* someFunc1();
void someFunc2(char* str);
void firstApproach();
void secondApproach();
int main()
{
firstApproach();
printf("\n");
secondApproach();
return 0;
}
char* someFunc1()
{
char *str = (char*)malloc(sizeof(char)*10);
str = "HELLO";
return str;
}
void someFunc2(char* str)
{
str = "Hello";
}
void secondApproach()
{
char *str = (char*)malloc(sizeof(char)*10);
someFunc2(str);
printf(str);
printf("heythere");
}
void firstApproach()
{
char *str;
str=someFunc1();
printf(str);
printf("wassup");
}
Please tell me why the second approach isn't working.
thanks!
my output is:
HELLOwassup
h>heythere
and my expected output should be
HELLOwassup
Helloheythere
void someFunc2(char* str)
{
str="Hello"; //-----the variable str is local to this function, thus it goes out of scope as
// soon as the function returns
}
void secondApproach()
{
char *str=(char*)malloc(sizeof(char)*10);
someFunc2(str);
printf(str); // -------------- here the value inside str is some garbage value.
printf("heythere");
}
CORRECTION :
void someFunc2(char **str )
{
*str = "hello";
}
void secondApproach()
{
char *str=(char*)malloc(sizeof(char)*10);
someFunc2(&str); // pass the address of the string
printf("%s", str);
printf("heythere");
}
Let's take a closer look at someFunc2:
void someFunc2(char* str)
{
/* str is a copy of the pointer that was passed in from secondApproach(). */
str = "Hello";
}
Here, you are passing a pointer by value. Thus, str in someFunc2 is a copy of the original pointer str that was passed in from secondApproach(). someFunc2 tells the copy pointer to point somewhere else, but it leaves the original str pointer alone. The solution is to pass in the address of the str pointer then tell someFunc2 to modify the pointer at that address to point to "hello".
void secondApproach()
{
char* str = (char*) malloc(sizeof(char) * 10);
someFunc2(&str); // Pass in the address of str.
printf("%s", str);
printf("heythere");
}
void someFunc2(char** str)
{
*str = "hello";
}
When you write a string between quotes and use it directly as:
a char* -> it gets created in a mutable place in memory, and gives its address to the pointer variable its assigned to. It is still in memory as long as that variable referencing it is not NULL.
an argument -> it gets created as char* and passed to the function (and treated there as a char*), then automatically disposed from memory (i.e. you can't access it or reference it anymore) ..
So, the only situation when a string is actually mutable is when you assign it to a char[], then it gets created in readonly memory and copied into to the stack .. ( the copy on the stack is what the char[] variable will point to )
If you think about it for some time, you realize that this is one of the benefits of dynamic memory: you can create a char* that is mutable, and since it is just a pointer, you don't need to specify the size of the string it is going to point at. So you can see how useful this would be ..
Also, it's worth to note that in functions:
if you pass a string, the variable in the function itself is treated as a char pointer and most likely would try to modify it, and if it's readonly that would raise a Segmentation Fault. So functions are assuming you know what you're doing ..
if you want a function to be able to modify a string directly (i.e string = "somestring") then pass it a pointer to the actual string, else the modification will only be local to the function. That's because the string is a "pointer to char", so the function can't modify the string as a whole. But that also means that a function can modify the string's characters individually ( obviously, because it has a pointer for characters: the string ). If you pass it, however, a string pointer (char**), the function can modify the string directly (*string = "whatever") and can also modify the characters individually (*string[1] = 'C'). Which choice you need depends entirely on the purpose of the function ..
Now, for your specific example, you can do one of two ..
Using a pointer to a pointer to a char (string pointer)
void someFunc2(char** str)
{
*str = "Hello";
}
Using a pointer to char (string)
void someFunc2(char* str)
{
char *k = "Hello";
for(int i = 0; i < 5; ++i)
str[i] = k[i];
}
This is one of the most controversial and advanced topics in C. No matter what type of C programming you're doing, you have to understand these core concepts ..
if I have this kind of function: str1= NULL in the begining
Result dosomething(char* str1, char* str){
str1=malloc(strlen(str2)+1); //followed by NULL check
strcpy(str1, str2);
.
.
return something
then I use this function in some other function:
char* output="hello";
char* input=NULL;
result=dosomething(input,output);
for some reason input remains NULL after using "dosomething" function, although if I use printf right after the strcpy, I can see that str1 did change to "hello". am I doing something wrong with the char* here when passing them to other function?
You need to pass a pointer to the string you want to change
Result dosomething(char** str1, char* str){
*str1=malloc(strlen(str2)+1); //followed by NULL check
strcpy(*str1, str2);
calling as
result=dosomething(&input,output);
or change the function to return the newly allocated string, returning NULL to indicate an error
char* dosomething(char* str){
char* str1=malloc(strlen(str2)+1); //followed by NULL check
strcpy(str1, str2);
...
return str1;
calling as
input=dosomething(output);
if (input==NULL) {
// error
Pass string by pointer to pointer
Result dosomething(char** str1, char* str){
*str1=malloc(strlen(str2)+1); //followed by NULL check
strcpy(*str1, str2);
and use as
result=dosomething(&input,output);
Since you need to modify the pointer's value so pass its address.
You're getting tripped up because you're changing the value of the pointer you're passing inside the function. For the sake of illustration replace your char* here with int to see what's going wrong:
Result dosomething_int(int a, int b) {
a = 29;
...
}
Here 29 takes the place of your malloc call, which replaces the value of the str1 pointer you passed with a new value. Now use this function:
int output = 17;
int intput = 0;
result = dosomething_int(input,output);
Would you expect the value of input to to be 0 or 29 after this? Probably you can answer this question easily -- the same thing is happening in the char * case. You'll need to pass a pointer to your char * to solve it:
Result dosomething(char** str1, char * str2) {
*str1 = malloc(...);
...
}
I want to change the actual argument passed to a function and not a copy of it. For example:
char str[] = "This is a string";
I want to create a function after a call to which the value of str is different. I tried to create a function accepting char** as the argument but I just couldn't get what I want.
I think you mean something like this:
void update_string(char ** ptr)
{
*ptr = strdup("This is a test");
return;
}
Then call the function like this:
char * str = strdup("hello world\n");
printf("%s\n", str);
update_string(&str);
printf("%s\n", str);
You may pass char*. The pointer will be copied, but it will still point to the same string
If you need the pointer itself to be passed (not its copy) you should pass a char**
To change a string passed to a function in-place, use a regular pointer. For example:
void lower_first_char(char *str)
{
*str = tolower(*str);
}
After this function executes, the first character of the passed string will be changed to lowercase.
Pass a char* if you want to modify the actual string:
foo(str);
...
void foo(char *some_string) {
some_string[0] = 'A';
}
str will now hold "Ahis is a string"
If instead of str being an array, you had: char *str = "Hello";, and wanted to modify where str pointed, then you would pass a char**:
bar(&str);
...
void bar(char **ptr_string) {
*ptr_string = "Bye";
}
str will now point to "Bye".