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(...);
...
}
Related
This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 6 months ago.
I have char* that I have defined in the main function. To my understanding, when passing around a pointer and assigning it a value anywhere, the value that the pointer points to is changed universally. But how come it doesn't behave like this here:
#include <stdio.h>
void idk(char *str) {
printf("1.idk: %s\n", str);
str = "hello world";
printf("2.idk: %s\n", str);
}
int main() {
char *str = "init value";
printf("1.main: %s\n", str);
idk(str);
printf("2.main: %s\n", str);
return 0;
}
Output:
1.main: init value
1.idk: init value
2.idk: hello world
2.main: init value // why is this not "hello world"?
Because you changed the pointer, not the value it points to.
Consider this code.
void idk(int num) {
num = 42;
}
You wouldn't expect this to change the value outside the function. num is a copy of the value. Same thing with a pointer. A pointer is just a number. You changed the number, not the value it points at.
If you want to change the number, you pass in a pointer to it and dereference it to access its value.
void idk(int *num) {
*num = 42;
}
Same thing, we need a pointer to the char *. A char **, a pointer to a pointer, a "double pointer".
First, make sure str is initialized, using an uninitialized value is undefined behavior. We'll use strdup to make sure the value is not constant (not strictly necessary, but it avoids having to deal with constant pointers vs pointers to constants).
Then we pass in a pointer to the char *, a char **.
Inside the function, we dereference the char ** to change what it points at.
#include <stdio.h>
#include <string.h>
void idk(char **str) {
printf("1.idk: %s\n", *str);
*str = "hello world";
printf("2.idk: %s\n", *str);
}
int main() {
// Make sure str is initialized and not constant.
char *str = strdup("testing 123");
printf("1.main: %s\n", str);
// Pass in a pointer to the char *
idk(&str);
printf("2.main: %s\n", str);
return 0;
}
In your function idk, your are not changing the pointed value but the pointer itself. That's mean your are changing a local copy of your pointer.
For this to work you need to pass a pointer of pointer
void idk(char **str) {
printf("1.idk: %s\n", *str);
*str = "hello world";
printf("2.idk: %s\n", *str);
}
int main() {
char *str;
printf("1.main: %s\n", *str);
idk(&str);
printf("2.main: %s\n", *str);
return 0;
}
In this code your are changing the pointed value of your pointer of pointer so, your changing the value of your pointer. And then str will point to Hello World.
As mention in comments, your pointer are not initialized, accessing it's pointed value like you do in printf is undefined behavior. To avoid that you should always initialized all your variables. For a pointer you can initialize with NULL.
Be cautious when you do things like
char* str = "hello world";
because the "hello world" is a string literal and so it is a const string and thus can not be modified. Prefer to do this
char const* str = "hello world";
This will prevent you to modified your string content but you can still modified the pointer it self.
Perhaps this helps make clear what's happening...
int main() {
char *str = "init value";
printf( "1.main: %s\n", str );
/* idk( str ) */ /* Function call pushes copy of ptr onto stack */
{
char *strInFunc = str; // function takes local copy off stack
printf( "1.idk: %s\n", strInFunc );
strInFunc = "hello world";
printf( "2.idk: %s\n", strInFunc );
}
/* At this point, 'strInFunc' no longer exists */
printf("2.main: %s\n", str);
return 0;
}
Look at parameters as local variables, which are initialized with the arguments of the call. Actually, compilers generate such code, so this "think model" is realistic.
Therefore, the parameter str of your function idk() uses a separate space, not the space of the variable str in main(). Their scopes are even separate, the names do not "collide" or "shadow" or "connect" each other. Both functions do not even know the names after compiling.
Where you call idk(), the value of main's variable str is copied into idk()'s parameter str.
When you changed this value inside idk(), the variable in main() is not touched.
This is called "passing by value", and is true even for pointers. In this sense, C only uses passing by value. I think this is a very clear concept.
"Passing by reference" is achieved, if you access the value pointed to by such a pointer. For example, you can change the string in main(), if you dereference the pointer:
void idk(char *str) {
printf("1.idk: %s\n", str);
str[0] = 'e'; /* str[0] is the same as *(str + 0) */
str[1] = 'x'; /* str[1] is the same as *(str + 1) */
printf("2.idk: %s\n", str);
}
Just be aware of the size of objects pointed to, and do not access memory outside the object.
Yes it is true that passing pointers is a way to have functions edit the variables passed to them, but not in the way that you're trying to do it.
When you pass an argument to a function in C (pointer or otherwise), a new variable is created for your function to do what it pleases with, and the value of the argument is put in this new variable. This new "local" variable will be discarded when your function returns.
Where pointers get around this is you can dereference them inside of your functions to edit the value(s) they point to, so the changes will be reflected outside of the function.
Consider the following:
#include <stdio.h>
void bar(int local_foo) {
local_foo = 21;
}
void baz(int *local_foo_ptr) {
*local_foo_ptr = 21;
}
int main() {
int foo = 19;
printf("First: %d\n", foo);
bar(foo);
printf("Second: %d\n", foo);
baz(&foo);
printf("Third: %d\n", foo);
}
A small clarification: you may not have encountered the & operator before. What it does is gets a pointer the the variable it is applied to. So in
baz(&foo);
what is happening is baz() is being called, and a pointer to foo is being passed to it.
Anyways, bar() fails to make any change to foo because all it does is store 21 into local_foo. This does nothing to change foo in main().
However, baz() is passed a pointer to foo (which is stored in local_foo_ptr), and it dereferences this pointer to change the value it points to, which in this case is foo in main(). Thus the output of this program is:
First: 19
Second: 19
Third: 21
Now consider your program again, but with the variable names changed to make things easier to understand:
#include <stdio.h>
void idk(char *local_str) {
printf("1.idk: %s\n", local_str);
local_str = "hello world";
printf("2.idk: %s\n", local_str);
}
int main() {
char *str = "init value";
printf("1.main: %s\n", str);
idk(str);
printf("2.main: %s\n", str);
return 0;
}
In idk(), only local_str is changed, and str in main() is unaffected. Thus after the call to idk(), str still points to the string "init value", and this is reflected in the output.
One way to get around this is to pass a pointer to str to idk(), and dereference that to change str in main(). This is usually called using a "double pointer". Here's one way this could be done:
void idk(char **local_str_ptr) {
...
*local_str_ptr = "hello world";
...
}
int main() {
...
idk(&str);
...
}
In this, we generate a pointer to str and pass that as an argument, thus the function can dereference this pointer and change the value of str in main().
That said, there's more than one way to skin a cat, and this is by no means how it "has to" or "should" be done.
'''
void calling (char *str)
{
str = NULL;
}
int main()
{
char str2[20];
calling(str2);
if(str2 == NULL)
{
printf("null");
}
return 0;
}
'''
Just wondering why did the printf not run.Can I not change the char-array pointer to NULL once its declared.
Why does the char pointer not get updated to NULL
Incorrect conclusion. Inside calling(char *str), the pointer str did get updated to NULL.
Just wondering why did the printf not run.
Because &str2[0] is not NULL.
str2 is an array, not a pointer. With str2 == NULL, str2 is converted to the type and value of the address of the first array element. The address of the first array element (&str2[0]) is not NULL.
char str2[20];
...
if(str2 == NULL)
{
printf("null");
}
Can I not change the char-array pointer to NULL once its declared.
"char-array pointer" is unclear.
Array str2 in char str2[20]; cannot change to NULL. An array's address never changes.
Pointer str in char *str ... str = NULL; can get assigned to NULL.
calling(str2); converts array str2 to the type and value of the address of the first array element, just as if is was calling(&str2[0]); and passes that pointer to calling().
void calling(char *str) receives a copy of that pointer. As calling() changes that pointer copy str within itself, it does not affect the address of the calling code's str2.
Remember: an array is not a pointer. A pointer is not an array.
For starters you have an array
char str2[20];
that is str2 is not a pointer it is an array. Arrays are non-modifiable lvalues. You can not assign one array to another array like for example
char str1[20];
char str2[20];
str1 = str2;
In this function call
calling(str2);
the array designator str2 is implicitly converted to pointer to the first element of the array and represents an rvalue. You can imagine the function definition and its call the following way
calling(str2);
//...
void calling ( /*char *str*/)
{
char *str = str2;
str = NULL;
}
As you can see the function deals with a copy of the value of an expression that yields the value of the address of the first element of the array str2.
Within the function it is the local variable (pointer) str that is changed. The original array str2 declared in main stays unchanged.
Even if you will pass the array by reference you will be unable to change it. For example this program will not compile
#include <stdio.h>
void calling (char ( *str )[20] )
{
*str = NULL;
}
int main()
{
char str2[20];
calling( &str2 );
if(str2 == NULL)
{
printf("null");
}
return 0;
}
because in this statement
*str = NULL;
you are trying to assign a pointer to an array.
There are many issues in the code:
char* calling (char *str)
{
str = NULL;
return str;
}
You change the local copy of str which is not visible to the caller.
You could just have a plain return NULL; have the same effect.
int main()
{
char str2[20];
calling(str2);
As mentioned above, the parameter to the function is not affected outside of the function.
You also do not do anything with the return value. The NULL value is just discarded.
Also there is no pointer existing in main at all that could be updaed.
You have an array. Arrays are not pointers, pointers are not arrays.
You can never assign a value to the array variable as it represents the location in memory where the array members are stored.
As mentioned in comments you should get hands on y good book to learn C.
Especially chapters about arrays, pointers and passing data into and out of functions should be relevant for you.
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 ..
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".