Pointer is "passed by value"? - c

After calling f() on ptr, I expect it to point to a single byte with value of A.
But instead ptr is copied by value and it is only available in the f function(?)
What am I doing wrong?
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
Thanks!

Yes, it's passed by value. If you want the changes you make to the pointer to be visible at the call site, you need to pass a pointer to the pointer.
Example:
#include <stdlib.h>
#include <stdio.h>
void f(char **ptr) { // pointer to the pointer
*ptr = malloc(1);
if(*ptr) // precaution if malloc should fail
**ptr = 'A';
}
int main(void) {
char *ptr;
f(&ptr); // take the address of `ptr`
if(ptr) // precaution again
printf("%c\n", *ptr); // now fine
free(ptr); // without this, you have a memory leak
}

Or, f() could simply return the pointer.
Form the habit of testing return values.
#include <stdio.h>
#include <stdlib.h>
char *f(void) {
char *ptr = malloc(1);
if( ptr != NULL )
*ptr = 'A';
return ptr;
}
int main() {
char *ptr = f();
if( ptr != NULL )
printf( "%c\n", *ptr );
free( ptr );
}
You might even be able to save some code if you write main() like this:
int main() {
char *ptr;
if( ( ptr = f() ) != NULL )
printf( "%c\n", *ptr ), free( ptr ), ptr = NULL;
/* more code that will see ptr as NULL */
}
And, that leads to this (being inefficient but valid):
int main() {
for( char *ptr = f(); ptr; free( ptr ), ptr = NULL )
printf( "%c\n", *ptr );
}

You are passing the pointer ptr to the function f() by value.
This essentially means that the pointer variable you passed to f() will be copied locally inside f().
Any changes made to the local copy will only affect the local copy and not the original variable you passed to f().
When a variable is passed by value, it's copy can be referenced by whatever the function argument is called.
In your case, the pointer you pass to f() has been copied inside f() and the local copy can be referenced by ptr, since that is the argument name in:
void f(char *ptr)
Now you know how pass by value works you may now understand why your code is erroneous.
In the code:
void f(char* ptr) {
ptr = (char*) malloc(1);
*ptr = 'A';
}
You modify a local copy of what you passed into f() called ptr. And since it is local, it has something called automatic storage duration.
Automatic storage duration essentially means that after the function ends, all local variables will cease to exist and the memory they occupy will be freed. This means your code actually causes a memory leak because the pointer to the memory you allocated is lost.
Solution:
In order to achieve what you want and to modify the pointer called ptr declared in main() you must pass the address of the pointer you want to modify.
This would look like this:
void f(char **ptr)
{
*ptr = malloc(sizeof(char));
if (*ptr == NULL)
{
fprintf(stderr, "malloc fail");
return;
}
**ptr = 'A';
}
int main()
{
char *ptr;
f(&ptr);
printf("%c\n", *ptr);
return 0;
}
Output:
A

Function parameters are its local variables. Changing a local variable has no effect on the argument expression.
You can imagine the function definition and its call the following way
int main() {
char* ptr;
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
// free(ptr);
}
void f( /*char* p */ ) {
char *p = ptr;
p = (char*) malloc(1);
*p = 'A';
}
That is the function parameter p (I renamed it to distinguish the parameter and argument in the function call) is initialized by the value of the argument expression and within the function the local variable p that occupies its own extent of memory is changed.
To change the original pointer you need to pass it to the function by reference. In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer you get a direct access to the original object.
So the function in your program should be defined the following way
void f(char **ptr) {
*ptr = (char*) malloc(1);
**ptr = 'A';
}
and called like
f( &ptr );

you are passing a address of ptr so this will be copied to the funktion f(),
a smiple solution can be: you make the f(...) return a char* and used in the main: ptr = f(ptr);

Alternatively, you can allocate the memory for ptr where you declare it:
void f(char* ptr) {
*ptr = 'A';
}
int main() {
char* ptr = malloc(1);
f(ptr);
printf("%c\n", *ptr); // Segmentation fault, But it should be 'A'
free(ptr);
}

Related

C char array pointers

I want to pass a char pointer to a function and have it set the value and pass it back. Here is my attempt but the printf prints garbage, where am I going wrong?
int a() {
char *p;
b(p);
printf("%s", p);
return 0;
}
int b(char * ptr) {
ptr = "test string";
return 0;
}
Pass a reference to the pointer.
int b(char **ptr)
{
*ptr = "Print statement";
//your code
}
//call
b(&p);
If you want to set the value of the pointer and pass it back, then b() needs to return a pointer:
int a(void) {
char *p = NULL;
p = b(p);
printf("%s", p);
return 0;
}
char * b(char * ptr) {
ptr = "test string";
return ptr;
}
Here p is initialized to NULL to avoid undefined behavior from passing an uninitialized value to a function. You could also initialize p to another string literal. Inside b, ptr is a copy of the pointer p that was passed to b. When you reassign the value stored in ptr to the address of the string literal "test string", the original pointer p is unchanged. By passing ptr back to the calling function, and reassigning p to the return value of b, the calling function can use the updated value.
As #M.M points out in the comments, this is somewhat redundant. The function b() could instead declare a pointer of its own, initialized to a string literal:
int a(void) {
char *p = b();
printf("%s", p);
return 0;
}
char * b(void) {
char *ptr = "test string";
return ptr;
}

Pointer manipulation inside function

Let's say I have a pointer pointing to memory
0x10000000
I want to add to it so it traverses down memory, for example:
0x10000000 + 5 = 0x10000005
How would I do this inside a function? How would I pass in the address that the pointer points to, and inside the function add 5 to it, then after the function's complete, I can use that value?
You have two options:
The function can return the updated pointer.
char *f(char *ptr) {
ptr += 5;
return ptr;
}
The caller then does:
char *p = some_initialization;
p = f(p);
The function argument can be a pointer to a pointer, which it indirects through:
void f(char **ptr_ptr) {
*ptr += 5;
}
The caller then does:
char *p = some_initialization;
f(&p);
Basically, like what everyone else as said you have to pass the pointer by reference(that is a pointer to a pointer aka double pointer) to the function.
#include<stdio.h>
void IncrementAddress(void **addr)
{
int offset=5;//give what ever value you want
*addr = *addr + offset;
printf("%d\n",*addr);
}
int main()
{
char x;// or any other data type like int x or float x etc.
void *ptr=NULL;
ptr = &x;
printf("%d\n",ptr);
IncrementAddress(&ptr);
printf("%d\n",ptr);
return 0;
}

C free(): invalid pointer allocated in other function

I'm new in StackOverflow. I'm learning C pointer now.
This is my code:
#include <stdio.h>
#include <stdlib.h>
int alloc(int* p){
p = (int*) malloc (sizeof(int));
if(!p){
puts("fail\n");
return 0;
}
*p = 4;
printf("%d\n",*p);
return 1;
}
int main(){
int* pointer;
if(!alloc(pointer)){
return -1;
}else{
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
I compile with: gcc -o main main.c
error: free(): invalid pointer: 0xb77ac000 ***
what's wrong with my code?
Arguments in C are always passed by value. So, when you call alloc(pointer), you just pass in whatever garbage value pointer contains. Inside the function, the assignment p = (int*)... only modifies the local variable/argument p. Instead, you need to pass the address of pointer into alloc, like so:
int alloc(int **p) {
*p = malloc(sizeof(int)); // side note - notice the lack of a cast
...
**p = 4; // <---- notice the double indirection here
printf("%d\n", **p); // <---- same here
return 1;
}
In main, you would call alloc like this:
if (!(alloc(&pointer))) {
....
Then, your code will work.
Everything in C is pass-by-value. This means that functions always operate on their own local copy of what you pass in to the function. Usually pointers are a good way to mimic a pass-by-reference scheme because a pointer and a copy of that pointer both contain the same memory address. In other words, a pointer and its copy both point to the same space.
In your code the issue is that the function alloc gets its own local copy of the pointer you're passing in. So when you do p = (int*) malloc (sizeof(int)); you're changing the value of p to be a new memory address, but the value of pointer in main remains unchanged.
You can get around this by passing a pointer-to-a-pointer, or by returning the new value of p.
You have two major problems in your code.
First, the alloc function creates a pointer via malloc, but never frees it, nor does it return the pointer to the calling function. This guarantees the memory the pointer addresses can never be freed up via the free command, and you now have memory leaks.
Second, the variable, int* pointer in main, is not being modified as you would think. In C, function arguments are "passed by value". You have two ways to address this problem:
Pass a pointer to the variable you want to modify (in your case, a pointer to a pointer to an int)
Have the function return the pointer to the function that called it.
Here are two implementations of my recommendations:
Approach 1
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p);
int alloc(int** p) {
if (!p) {
printf("Invalid argument\n");
return (-1);
}
if ((*p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (-1);
}
**p = 123;
printf("p:%p - *p:%p - **p:%d\n", p, *p, **p);
return 0;
}
int main(){
int* pointer;
if(alloc(&pointer) != 0){
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
return 0;
}
Sample Run for Approach 1
p:0xbfbea07c - *p:0x8656008 - **p:123
&pointer:0xbfbea07cointer - pointer:0x8656008ointer - *pointer:123
Approach 2
#include <stdio.h>
#include <stdlib.h>
int* alloc(void) {
int* p;
if ((p = (int*)malloc(sizeof(int))) == NULL) {
printf("Memory allocation error\n");
return (NULL);
}
*p = 123;
printf("p:%p - *p:%d\n", p, *p);
return p;
}
int main(){
int* pointer = alloc();
if(pointer == NULL) {
printf("Error calling function\n");
}else{
printf("&pointer:%p- pointer:%p- *pointer:%d\n", &pointer, pointer, *pointer);
}
free(pointer);
pointer = NULL;
return 0;
}
Sample Run for Approach 2
p:0x858e008 - *p:123
&pointer:0xbf9bb1ac- pointer:0x858e008- *pointer:123
You are passing the pointer by value into your alloc function. Although that function takes a pointer to an int, that pointer itself cannot be modified by the function. If you make alloc accept **p, set *p = ..., and pass in &pointer from main, it should work.
#include <stdio.h>
#include <stdlib.h>
int alloc(int** p){
*p = (int*) malloc (sizeof(int));
if(!*p){
puts("fail\n");
return 0;
}
**p = 4;
printf("%d\n",**p);
return 1;
}
int main() {
int* pointer;
if(!alloc(&pointer)){
return -1;
} else {
printf("%d\n",*pointer);
}
free(pointer);
return 0;
}
If you want a function to write to a non-array parameter of type T, you must pass a pointer to that parameter.
void func( T *ptr )
{
*ptr = new_value;
}
void foo ( void )
{
T var;
func( &var ); // writes new value to var
}
If T is a pointer type Q *, it would look like
void func( Q **ptr )
{
*ptr = new_pointer_value;
}
void foo ( void )
{
Q *var;
func( &var ); // writes new pointer value to var
}
If Q is a pointer type R *, you would get
void func( R ***ptr )
{
*ptr = new_pointer_to_pointer_value;
}
void foo ( void )
{
R **var;
func( &var ); // writes new pointer to pointer value to var
}
The pattern is the same in all three cases; you're passing the address of the variable var, so the formal parameter ptr has to have one more level of indirection than the actual parameter var.
One sylistic nit: instead of writing
p = (int *) malloc( sizeof (int) );
use
p = malloc( sizeof *p );
instead.
In C (as of the 1989 standard), you don't need to cast the result of malloc; void pointers can be assigned to other pointer types and vice versa without needing a cast (this is not true in C++, but if you're writing C++, you should be using the new operator instead of malloc anyway). Also, under the 1989 version of the language, using the cast would mask a bug if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope. That hasn't been a problem since the 1999 version, though, so now it's more a matter of readability than anything else.
The type of the expression *p is int, so the result of sizeof *p is the same as the result of sizeof (int). This way, if you ever change the type of p, you don't have to modify the malloc call.
To allocate an array of values, you'd use something like
T *p = malloc( sizeof *p * NUM_ELEMENTS );
or, if you want everything to be zeroed out initially, use
T *p = calloc( sizeof *p, NUM_ELEMENTS );

Why I've allocated a pointer memory in a function, but it's also NULL?

The code confused me.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void create_int(int *p)
{
p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
You are not passing the pointer value back from the function. Try:
void create_int(int **p) {
*p = (int *) malloc(sizeof(int));
}
int main() {
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
The variable p in the function create_int is a copy of the variable p in main. So any changes made to p in the called function does not get reflected in main.
To make the change get reflected in main you need to either:
Return the changed value:
int* create_int(int *p) {
p = malloc(sizeof(int));
// err checking
return p:
}
...
// in main:
p = create_int(p);
Or pass the address of p as:
void create_int(int **p) {
*p = malloc(sizeof(int));
// err checking
}
...
// in main:
create_int(&p);
You need a pointer to a pointer like this:
void create_int(int **p)
{
*p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
As folks have pointed out, it's failing since you're not actually changing the pointer that the caller has.
A different way to think about the code might be to notice that it's basically wrapping malloc(), i.e. it's doing a memory allocation but with intelligence added. In that case, why not make it have the same prototype (=call signature) as malloc()? That makes it clearer in the caller's context what's going on, and easier to use:
int * create_int(void)
{
return malloc(sizeof (int));
}
int main(void)
{
int *p = create_int();
assert(p != NULL);
return 0;
}
Also, in C you should never cast the return value of malloc() (see Do I cast the result of malloc?).
You need to send a pointer to a pointer to be able to assign a memory to it via a function
void create_int(int **p)
{
*p = (int*)malloc(sizeof_int));
}
int main()
{
int* p = NULL;
create_int(&p);
assert(p != NULL);
return 0;
}
Your code contains two pointers: one in the create_int function and another one in main. When you call create_int, a copy of the pointer in main is made and used, then eliminated when the create_int function returns.
So, any changes you did to the copy within create_int remain there and are not propagated back to main.
The only way to propagate changes between functions in C (aside from, obviously, returning new values) is to pass a pointer to the changed values. This way, while the pointer being passed will be copied, the value that it points to will be the same, so changes will apply.
Since you're trying to change a pointer, you need a pointer-to-pointer.
void create_int(int **pp)
{
// this changes the pointer that `p` points to.
*pp = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
// this sends a pointer to the pointer p in main
create_int(&p);
assert(p != NULL);
return 0;
}

dynamic memory created inside a function [duplicate]

This question already has answers here:
C Programming: malloc() inside another function
(9 answers)
Closed 5 years ago.
I would like to know the technical reason(in terms of memory) why this piece of code will not work:
#include <stdio.h>
#include <stdlib.h>
int* fun(int*);
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
fun(ptr);
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
void fun(int* ptr)
{
ptr = (int*)malloc(sizeof(int));
*ptr = 115;
}
Why will this not work? I thought that the heap(more importantly the addresses) is common to all the function's variables in the stack .
Also, why would this work.
If i comment the memory allocation inside the function fun and uncomment the one in main . It works fine.
In C, everything is passed by value.
What you are passing to fun() is a copy of the pointer you have in main().
That means the copy of ptr is aimed at the allocated memory, and that memory set to 115.
The ptr in main() still points at an undefined location because it has never been assigned.
Try passing a pointer to the pointer, so that within fun() you have access to the pointer itself:
#include <stdio.h>
#include <stdlib.h>
int* fun(int**); // <<-- CHANGE
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
fun(&ptr); // <<-- CHANGE
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
int* fun(int** another_ptr) // <<-- CHANGE
{
*another_ptr = (int*)malloc(sizeof(int)); // <<-- CHANGE
**another_ptr = 115; // <<-- CHANGE
return *another_ptr;
}
The other option would be to make fun() actually return the updated pointer (as advertised), and assign this to ptr:
#include <stdio.h>
#include <stdlib.h>
int* fun(int*);
int main()
{
int a=5;
int* ptr;
// ptr=(int*)malloc(sizeof(int));
ptr = fun(ptr); // <<-- CHANGE
a=*ptr;
printf("\n the val of a is:%d",a);
return 0;
}
int* fun(int* another_ptr)
{
another_ptr = (int*)malloc(sizeof(int));
*another_ptr = 115;
return another_ptr; // <<-- CHANGE
}
Edit: I renamed the variable in fun() to make it clear that it is different from the one you use in main(). Same name doesn't mean anything here.
The fun() function parameter is a copy of the variable you passed into fun(). So when you do:
ptr = (int*)malloc(sizeof(int));
*ptr = 115;
you only change that copy. You should change the function signature:
int* fun(int** ptr)
{
*ptr = (int*)malloc(sizeof(int));
**ptr = 115;
}
and change how you call it accordingly.
You are confused about several things here, but one easy way of writing the function is:
int * fun()
{
int * ptr = (int*)malloc(sizeof(int));
* ptr = 115;
return ptr;
}
You are now responsible for freeing the memory, so in main():
int * ip = fun();
printf( "%d", * ip );
free( ip );
The alternative is to pass the address of apointer (a pointer to a pointer) to the function:
void fun( int ** pp )
{
* pp = (int*)malloc(sizeof(int));
** pp = 115;
}
then your code in main() looks like:
int * ip;
fun( & ip );
printf( "%d", * ip );
free( ip );
I think you can see that the first function is simpler to use.
You need to pass the address of the pointer in main if you want to change it:
fun(&ptr);
(and change fun appropriately, of course)
At the moment, it's changing the local variable ptr inside the function, and of course that change doesn't magically appear anywhere else.
You're passing the ptr by value to fun. fun will recieve a copy of ptr which will be modified. You need to pass ptr as int**.
void fun(int** ptr)
{
*ptr = (int*)malloc(sizeof(int));
**ptr = 115;
}
and call it with:
fun(&ptr);
(I also removed the return value from fun since it wasn't used)
The variable int* ptr is passed by value to the function fun. So the value assigned to ptr inside the function using ptr = (int*)malloc(sizeof(int)); will not be reflected outside the function. So when you do a = *ptr; in main() you are trying to use an un-initialized pointer. If you want to to reflect the changes done to ptr outside the function then you need to change the signature of fun to fun(int** ptr) and do *ptr = (int*)malloc(sizeof(int));
Remember that if you want a function to modify the value of an argument, you must pass a pointer to that argument. This applies to pointer values; if you want a function to modify a pointer value (not what the pointer points to), you must pass a pointer to that pointer:
void fun (int **ptr)
{
/**
* Do not cast the result of malloc() unless you are
* working with a *very* old compiler (pre-C89).
* Doing so will supress a valuable warning if you
* forget to include stdlib.h or otherwise don't have
* a prototype for malloc in scope.
*
* Also, use the sizeof operator on the item you're
* allocating, rather than a type expression; if you
* change the base type of ptr (say from int to long),
* then you don't have to change all the corresponding
* malloc() calls as well.
*
* type of ptr = int **
* type of *ptr = int *
* type of **ptr = int
*/
*ptr = malloc(sizeof **ptr);
*ptr = 115;
}
int main(void)
{
int *p;
fun(&p);
printf("Integer value stored at %p is %d\n", (void *) p, *p);
return 0;
}
BTW, you have a type mismatch in your example; your initial declaration of fun returns an int *, but the definition returns void.

Resources