Sign in to follow this  
bnew

[c] pointer as function argument

Recommended Posts

bnew    122
I'm rather stuck at the following and a quick search reveals no solution: I have a pointer to a (typedef) structure. I want to initialize this (foo) and use it in another function (e.g. main). So basically, passing through. However, when a function call returns, the value remains unchanged? Why? I mean, in my understanding, I declare a pointer to a value_t structure and initialize with NULL. Then I invoke bar with the value_t structure passed by reference. Next, foo is invoked with again the value_t structure passed by ref. Foo initializes the structure by allocating memory and setting some values. On return in bar, I want to change some value of value_t, but an assertion is fired. Debugging shows that the value_t is still NULL. Why?
#include <stdio.h>
#include <malloc.h>
#include <assert.h>

typedef struct _val
{
	int a;
	int b;
} value_t;

int foo(value_t *val)
{
	val = (value_t*)malloc(sizeof(value_t));
	val->a = 0x65;
	val->b = 0x66;
	assert(val != NULL);
	return 0;
}

int bar(value_t *val)
{
	if (val == NULL)
		foo(val);
	assert(val != NULL);
	val->b++;
	return 0;
}

int main()
{
	value_t *val = NULL;
	bar(val);
	assert(val != NULL);
	free(val);
	return 0;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Pass a pointer to a pointer, ie the address of the pointer.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Hmm where did my explanation go?
You start with a null pointer and inside the function you allocate memory and assign it to the pointer. The problem is the pointer inside the function points to the memory but the main pointer is still null. It's simple really when you think of it, by passing the address of the null pointer you can then assigning the address to the dereferenced pointer to the null pointer and it will be valid upon returning to main.
hmm it sounded much better the last time I wrote it lol

Share this post


Link to post
Share on other sites
Palidine    1315
think of it as passing an int to a function. if you change the value of the int internal to the function, does the value change outside? no. why? because it's pass by value. To change the int you'd pass a reference to the int or a pointer to the int and _then_ you could change it externally. it's no different for a pointer. if you want the value of the pointer to change external to the funciton you need to either pass a reference or a pointer to the pointer.


int foo = 0;
int *poo = NULL;

void changeFoo( int &fooVar )
{
fooVar = 2;
}

void changePoo( int &*poo )
{
poo = new int;
*poo = 2;
}

void main()
{
changeFoo(foo);
changePoo(poo);

//foo and poo are now changed

delete poo;
}



-me

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Small typo there Palidine void changePoo( int &*poo ) should read void changePoo( int *& poo ) (anyway thats C++)
I just wanted to add that casting the return of malloc is not required(in C) and can cause problems an implicit cast is preformed.

Share this post


Link to post
Share on other sites
ToohrVyk    1596
The C version of what Palidine said:

int foo(value_t **val)
{
*val = (value_t*)malloc(sizeof(value_t));
(*val)->a = 0x65;
(*val)->b = 0x66;
assert(val != NULL);
return 0;
}



int bar(value_t **val)
{
if (*val == NULL)
foo(val);
assert(*val != NULL);
(*val)->b++;
return 0;
}

Share this post


Link to post
Share on other sites
Zahlman    1682
I think you better assert the result of your malloc call *before* trying to use the allocation :) Also, a function that always returns the same thing should usually not return anything at all. Oh, and when you have this extra level of indirection, it's usually easier to work with a temporary and then assign it at the end. Oh, and you're supposed to be #including <stdlib.h> and not casting your malloc() results, in "modern C" (heh).


void foo(value_t **out) {
value_t* val = malloc(sizeof(value_t));
assert(val); // I find this way more readable.
val->a = 0x65;
val->b = 0x66;
*out = val;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this