Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/forums/c/)
-   -   hi , i'm having a problem with pointers in C ... (http://www.go4expert.com/forums/hi-im-pointers-c-t14794/)

blackslither 26Oct2008 05:15

hi , i'm having a problem with pointers in C ...
 
I will give a simple example inspired from my problem :

void change(int *x, int *y){x=y;}

int main(){
int *xx,*yy;

yy = (int*)malloc(sizeof(int));
change(xx,yy);

if(xx == NULL)printf("is null\n");
else printf("---- %d ----\n",*xx);

.................................................. .........

xx doesn't point to the value of yy (*yy) , the program prints "is null" . Why ?

xx and yy must be declared int* , it's something that i must do in my program .

xpi0t0s 26Oct2008 16:15

Re: hi , i'm having a problem with pointers in C ...
 
A quick lesson on pointers. If a function has to change something that is passed in, then you need to pass in a pointer to that thing. For example,
Code:

void add1(int x)
{
  x=x+1;
}
int main()
{
  int var;
  add1(var);
}

won't increment var (although it will increment the local copy, which is held in x and discarded when the function returns), you need to do
Code:

void add1(int *x)
{
  *x=*x+1;
}
int main()
{
  int var;
  add1(&var);
}

instead. The & operator in this context takes the address of the variable it precedes; &var means "the address of var", and in add1() the * operator means the computer will treat the variable as a pointer and access memory at the location contained in the variable; suppose you have int foo; int *baz=&foo; then to access foo through the baz pointer you use *baz, and you can increment foo with *baz=*baz+1;. This is known a DEREFERENCING the pointer - a very important term.

The same is true for pointers, if you need to modify a pointer, then you have to pass in the address of that pointer. So:
Code:

void incr_ptr(int *x)
{
  x=x+1;
}
int main()
{
  int x[2];
  int *x_ptr=&x[0];
  incr_ptr(x_ptr);
}

won't increment x_ptr to point to x[1], although as before it WILL increase the local variable x, which is discarded when the function returns. If you want to increase x_ptr itself, then just as before you have to pass in a pointer and dereference it:
Code:

void incr_ptr(int **x)
{
  *x=*x+1;
}
int main()
{
  int x[2];
  int *x_ptr=&x[0];
  incr_ptr(&x_ptr);
}

So your function change() only changes the local variable x, then discards that change. It leaves xx untouched. To modify xx you need to pass in a pointer to xx. xx itself is a pointer to int, so the x parameter to change() needs to be a pointer to a pointer to int. So:
Code:

void change(int **x,int *y)
{
  *x = y;
};
int main()
{
  int *xx, *yy;
  yy=malloc(sizeof int);
  change (&xx,yy);
  //etc

should work. Note that y isn't declared as int** because you don't need to modify yy. This is a neat little example of using different levels of INDIRECTION (another important term - it's "indirect" because you don't go directly to the variable. int x would be direct. x is that number. int *ptr2x; is indirect; to get at x you have to go indirectly, via ptr2x, with *ptr2x).

Despite the simplicity of the program there are still two bugs worth a mention:

The value displayed by the program will be unpredictable, because *yy is uninitialised. Also, the program leaks memory, because the malloc() is not matched by a free(). Both these are major bugs; a memory leak in a long running program will mean that the program will eventually stop working because there's no memory left, and uninitialised variables will mean any behaviour dependent on the value of those variables will be unpredictable.

So some good habits for you to develop immediately are:

- ALWAYS initialise variables. Initialise them to zero if you can't think of a suitable value.
- ALWAYS ALWAYS ALWAYS initialise pointers. Initialise them to zero.
- ALWAYS write "free" somewhere, ideally in such a way as to cause a compiler error, when you write malloc(), because that will force you to deal with the free at the most important time (same is true for new/delete/new[]/delete[] in C++). Leaving it will mean that you forget it, which means (a) you'll get a leak and (b) you'll have to spend hours trying to find what is leaking. ALWAYS write resource allocation and resource deallocation simultaneously, or as simultaneously as possible.
- Remember that allocating memory simply gives you somewhere to stuff a value. It doesn't do any value stuffing for you. int **yy=malloc(sizeof int); initialises yy to point to an int, but the int it points to is NOT DEFINED.


All times are GMT +5.5. The time now is 14:06.