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'm acquainting myself with c-strings and pointers by using a very simple program.
This version, which passes in a string by reference, works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char **string) {
*string = (char *)malloc(5);
char *temp = "hell";
strcpy(*string, temp);
}
int main(int argc, char *argv[]) {
char *string = NULL;
test(&string);
printf("%s\n", string);
return 0;
}
It prints "hell".
This version, which simply passes the string by value, does not work, and results in a SEGFAULT:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char *string) {
string = (char *)malloc(5);
char *temp = "hell";
strcpy(string, temp);
}
int main(int argc, char *argv[]) {
char *string = NULL;
test(string);
printf("%s\n", string);
return 0;
}
From what I know, the first version makes sense because I pass in the address of the address of the string. Thus, when I dereference this double pointer, I get the real address of the string and can reassign it with malloc.
The second version, however, I'm kind of unclear why it doesn't work. In this version I pass the address of string into the test function. I read that everything in C is passed by value but that array names are actually addresses. Doesn't this mean that I'm passing in the actual address of string into test? Shouldn't things work out the same? I'm confused, please help me out.
Remember This : In C programming to use a value,you pass "by value". To change a value you must pass "by address". So,if what you want to change is an address,then you need to pass its address to change it.otherwise you may only use it.
When you pass an argument "by value", the value of the argument is copied into the formal argument in the function. Changing a copy (in your case string inside the test function) will of course not change the original (string in the main function).
On a side-note, C doesn't actually have "pass by reference", it only have pass by value. You emulate pass by reference by using pointers.
In your second version, string itself is being passed by value, so you simply cannot change string itself. This is for the similar reason you cannot change the value of an int or float when it is passed by value. While an argument is being passed by value, there is a local copy created in the called function's stack.
You can always change the content of string, however.
In C, array type is represented as a pointer to its first element. * in type means "pointer to", but outside of type means "dereference pointer". When you pass argument to function, in the body of function, you have copy of the thing, that you passed. Lets analyse your code with that in mind:
void test(char **string) { //expect pointer to string
*string = (char *)malloc(5); //dereference pointer to string and allocate memory (*string is of type char*, it is a string)
char *temp = "hell"; //create new string
strcpy(*string, temp); //copy new string to the old one
}
int main(int argc, char *argv[]) {
char *string = NULL; //create empty pointer (string is array, which is pointer to char), but NULL is not a valid string
test(&string); //pass pointer to string
printf("%s\n", string); //print string
return 0;
}
**sting did not change, but its contents *string did.
And in the second one:
void test(char *string) { //with this type, you could modify, what is actual string content (for example first letter), but you pass here NULL, so there is nothing you can do
string = (char *)malloc(5); //here, you are changing only COPY of the pointer, that you passed in main
char *temp = "hell"; //create another string
strcpy(string, temp); //copy new string to the one created, after this operation pointer to the string is lost
}
int main(int argc, char *argv[]) {
char *string = NULL; //the same
test(string); //pass the string, you are screwed here, values in C are passed by copying, so even if you modify the string correctly, you will not see the result
printf("%s\n", string); //the string variable never changed from NULL, so you get the error
return 0;
}
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.
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".
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 ..