this doesn't work:
void function(char* var)
{
var = (char*) malloc (100);
}
int main()
{
char* str;
function(str);
strcpy(str, "some random string");
printf("%s\n", str);
return 0;
}
this does:
void function(char* var)
{
//var = (char*) malloc (100);
}
int main()
{
char* str;
//function(str);
str = (char*) malloc (100);
strcpy(str, "some random string");
printf("%s\n", str);
return 0;
}
Why?
You have to pass the address of the pointer to assign the address you want inside the function, otherwise you are just passing a copy of it:
void function(char** var)
{
*var = malloc (100);
}
int main()
{
char* str;
function(&str);
strcpy(str, "some random string");
printf("%s\n", str);
return 0;
}
You need to use a pointer to pointer as a parameter for that, char **.
When you pass a pointer as a parameter, it gets copied, so what you get inside the function is just another pointer pointing to the same place.
You need to receive a char ** and do:
my_alloc_fun(void **ptr){
*ptr= malloc(size);
}
void *myptr;
my_alloc_fun(&myptr);
This way, you get the address of the pointer inside the function, so that you can make the original pointer to point to the newly allocated memory.
When you call function(str), you are passing the value of str to function. This value is some uninitialized garbage value because you haven't set it to anything in main, but that's not the problem.
The problem is that function has its own pointer, var, into which it puts that garbage value so that one could say var points to the same thing (garbage) that str points to. However, they are not the same variable. They are two distinct variables, and changing var has no effect on str.
When you say var = (char*) malloc (100);, you are allocating memory somewhere and then telling var to point to it. Now var points to a different location than str. Immediately you return from that function, losing var and the location of that memory. This by the way is a memory leak.
When you return back to main, str is as it ever was - pointing to garbage.
A numerical example:
char *str; // str -> 0xfeedface (garbage)
function(str);
// inside 'function', an initialization like this occurs
char *var = str; // var -> 0xfeedface (same garbage)
var = (char*) malloc (100); // var -> 0x12341234 (alloc'd memory)
return;
// back in 'main'
strcpy(str, "some random string"); // str still points to 0xfeedface!
To do this properly, you need to change strs value. This means function needs a pointer to str, or a pointer to a pointer.
void function(char **var)
{
*var = (char*)malloc(sizeof(char) * 100);
}
int main()
{
char *str;
function(&str);
strncpy(str, "some random string", 99);
...
free(str); // important in general
}
Pointers are just like any other variable; the difference is only in what their value represents. Whereas a double has a value that represents a double-precision floating point number, and an int has a value that represents a signed integer, a pointer has a value that represents the location of another variable.
Pointers themselves are still passed by-value to other functions; so your example doesn't work for exactly the same reason that this analagous function doesn't work:
void function(int var)
{
var = 100;
}
int main()
{
int num;
function(num);
printf("%d\n", num);
return 0;
}
The answer in both cases is the same: When function() changes the value of the parameter var, it is changing only its local copy of that - it isn't changing the variable within main().
See my answer to C Programming: malloc() inside another function for an explanation about how to think about this.
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.
I am struggling to write a char* passed as an argument. I want to write some string to char* from the function write_char(). With the below code, I am getting a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
int main(){
char* test_char;
write_char(test_char);
printf("%s", test_char);
return 0;
}
You have two problems (related to what you try to do, there are other problems as well):
Arguments in C are passed by value, which means that the argument variable (c in your write_char function) is a copy of the value from test_char in the main function. Modifying this copy (like assigning to it) will only change the local variables value and not the original variables value.
Assigning to a variable a second time overwrites the current value in the variable. If you do e.g.
int a;
a = 5;
a = 10;
you would (hopefully) not wonder why the value of a was changed to 10 in the second assignment. That a variable is a pointer doesn't change that semantic.
Now how to solve your problem... The first problem could be easily solved by making the function return a pointer instead. And the second problem could be solved by copying the string into the memory instead of reassigning the pointer.
So my suggestion is that you write the function something like
char *get_string(void)
{
char *ptr = malloc(strlen("some string") + 1); // Allocate memory, +1 for terminator
strcpy(ptr, "some string"); // Copy some data into the allocated memory
return ptr; // Return the pointer
}
This could then be used as
char *test_string = get_string();
printf("My string is %s\n", test_string);
free(test_string); // Remember to free the memory we have allocated
Within the function
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
the parameter c is a local variable of the function. Changing it within the function does not influence on the original argument because it is passed by value. That is the function deals with a copy of the original argument.
You have to pass the argument by reference through pointer to it.
Also the function has a memory leak because at first the pointer was assigned with the address of the allocated memory and then reassigned with the address of the first character of the string literal "some string".
If you want to create a copy of a string literal then what you need is the following
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char( char **s )
{
const char *literal = "some string";
*s = malloc( strlen( literal ) + 1 );
if ( *s ) strcpy( *s, literal );
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
if ( test_char ) puts( test_char );
free( test_char );
}
The program output is
some string
Do not forget to allocate dynamically a character array that is large enough to store also the terminating zero of the string literal.
And you should free the allocated memory when the allocated array is not needed any more.
If you want just to initialize a pointer with the address of a string literal then there is no need to allocate dynamically memory.
You can write
#include <stdio.h>
void write_char( char **s )
{
*s = "some string";
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
puts( test_char );
}
In C, you'll need to pass a pointer to a pointer. Your malloc call is trying to change the value of the variable that's being passed in, but it's actually only a copy. The real variable you pass in will not be changed.
Also, the way that you copy a string into a char* is not using assignment... Here's some revised code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void write_char(char** c){
size_t len = strlen("some string");
*c = (char*)malloc(len + 1); // + 1 for null termination
strncpy(*c, "some string", len);
}
int main(){
char* test_char;
write_char(&test_char);
printf("%s", test_char);
return 0;
}
String assignment in C is very different from most modern languages. If you declare a char * and assign a string in the same statement, e.g.,
char *c = "some string";
that works fine, as the compiler can decide how much memory to allocate for that string. After that, though, you mostly shouldn't change the value of the string with =, as this use is mostly for a constant string. If you want to make that especially clear, declare it with const. You'll need to use strcpy. Even then, you'll want to stay away from declaring most strings with a set string, like I have above, if you're planning on changing it. Here is an example of this:
char *c;
c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
If you're passing a pointer to a function that will reallocate it, or even malloc in the first place, you'll need a pointer to a pointer, otherwise the string in main will not get changed.
void myfunc(char **c) {
char *tmp = realloc(*c, 32 * sizeof(char));
if(tmp != NULL) {
*c = tmp;
}
}
char *c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
myfunc(&c);
char* test_char="string"; // initialize string at the time of declaration
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
}
int main(){
char* test_char="strin";
write_char(test_char);
printf("%s", test_char);
return 0;
}
I am trying to pass address of char pointer to a function by using call by reference. When I try to check the address of char pointer in main and function they both are different, why?. One more surprising thing what I cant understand is when using call by reference the string updated in function should actually reflect in main also.
void fun(char *str){
str = "hello";
printf(" str address in fun is = %p\n",str);
printf("In fun str is = %s\n",str);
}
int main(){
char *str = (char*) malloc(sizeof(10));
fun(str);
printf(" str address is = %p\n",str);
printf("In main str is = %s\n",str);
}
Output of the program is as follows:
str address in fun is = 0x804859b
In fun str is = hello
str address is = 0x839e008
In main str is =
I am not able to understand why this is happening. Can any one explain what actually is happening in this code. Why I am not able to get the string updated in main from function.
[Note: When I try the same code using int pointer this works fine. I am trying to understand the heap memory role in char pointer scenarios.]
I am not able to understand why this is happening.
Since pointers are also passed by value, this line
str = "hello";
overwrites the value passed from main to another value, namely, that of the location of "hello" string literal, for the duration of fun function call. That is why you see correct printouts inside fun. However, this re-assignment is not visible in main.
Replacing this line with
strcpy(str, "hello");
will fix the problem. Now both addresses and both string values will be the same.
Note: The allocation char *str = (char*) malloc(sizeof(10)); is incorrect: you don't need sizeof in there. It should be char *str = malloc(10);
Assuming the working program with int looks something like this (simplified):
void fun(int *ptr)
{
*ptr = 10;
}
int main(void)
{
int var;
fun(&var);
}
This is emulating pass by reference by passing a pointer to the variable and using the dereference operator in the function to access what the pointer ptr is pointing to.
In fun you have something like this
+-----+ +--------------------------+
| ptr | ---> | var in the main function |
+-----+ +--------------------------+
That is, ptr is pointing to the var variable in the main function. By using the dereference on ptr we can modify what ptr is pointing to, which as said is the var variable.
Now lets take a simplified version of the program you have problems with:
void fun(char *ptr)
{
// 1
ptr = "hello"
// 2
}
void main(void)
{
char str[10];
fun(str);
}
At point 1 in the function above, ptr is pointing to the first element in the array str from the main function.
At point 2 (after the assignment) then ptr is pointing to the string literal "hello" instead. And as ptr is a local variable who will go out of scope once the function returns, the assignment is lost.
To fix this either you strcpy as answered by dasblinkenlight. Or you can emulate pass by reference by passing a pointer to the variable:
void fun(char **ptr_to_ptr)
{
// Note the use of the dereference operator here
*ptr_to_ptr = "hello";
}
void main(void)
{
char str[10] = "foobar";
char *ptr = str; // Make ptr point to the first element of str
// Note the use of the address-of operator
fun(&ptr);
printf("%s\n", ptr); // Will print "hello"
printf("%s\n", str); // Will print "foobar"
}
What the above program is doing is to change what ptr in the main function is pointing at.
Important note: If you use dynamic allocation for ptr (like you do in your program) then fun as shown above will lead to a memory leak, because you no longer have the original pointer returned by malloc.
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 ..
Whenever the environment variable's value is larger than its key in this method, I get a buffer overflow. Target is part of a dynamically allocated two dimensional array for tokens. Whenever I replace the token that's an environment variable with a value longer than it, it flows into the next token. I've tried adding a realloc to try and fix it, but it doesn't work or leads to a segfault.
If anyone has any suggestions or can point me at something I"m overlooking, I'd greatly appreciate it, because I have a feeling I'll be kicking myself when I find it out anyway.
The method is:
void envReplace(ENV *evlist, char *Target)
{
if (Target[0] == '#')
{
memmove(Target, Target+1, strlen(Target));
for(q = 0; q<16; q++)
{
if(evlist[q].envVariable!=NULL)
{
if(strcmp(Target, evlist[q].envVariable)==0)
{
//this is where I'd add the realloc as realloc(Target, strlen(evlist[q].Value))
strcpy(Target, evlist[q].Value);
return;
}
}
}
printf("Variable not found\n");
}
else
{
printf("A value that didn't start with # was an argument\n");
return;
}
}
The data structure ENV is:
typedef struct envStorage
{
char *envVariable;
char *Value;
}ENV;
You can pass a pointer to a pointer, like this, and then you can call realloc() inside the function, modifying the original pointer.
void func (char **to_change) {
// Changes the char *target in main()
*to_change = (char *) realloc(*to_change, 20);
sprintf (*to_change, "Blablablablabla\n");
}
int main (int argc, char **argv) {
char *target = (char *) malloc (10);
func(&target);
printf(target);
free(target);
}
In this example, func() writes to the original pointer char *target in the main() function.
What happens in your code, is that you realloc() and assign to a copy of the pointer. The pointer is copied when you call envReplace(). When this function returns, the original pointer contains the old memory address, which is no longer valid allocated memory (it was freed by realloc()).