Sep 10, 2014

C Programming #45: Pointer - as function parameter and return value

We already have covered functions C Programming #32: Function and pointers C Programming #41: Pointer - introduction.

This article deals with how pointers can be used along with functions. Two main usage are covered

  1. Pointers passed as parameter to function.
  2. Pointers returned from function.

Pointers passed as parameter to function

Best way to explain this is by taking example of most popular example. Write a function that would swap values in two integer variables.

Strategy:

  • Our function that swaps two variables be named swap.
  • Since it would swap(exchange) two integer variables lets it prototype be as follows
    • void swap(int, int); 
  • Swapping would be done by taking temporary variable

#include <stdio.h>
void swap(int, int); 
int main()
{
   int a = 10, b = 30;
   printf("Before Swap: a is %d and b is %d\n", a, b);
   swap(a, b);
   printf("After Swap: a is %d and b is %d\n", a, b);
}
void swap(int x, int y)
{
   int temp;
   temp = x;
   x = y;
   y = temp;
   return;
}
Output of above program is

Before Swap: a is 10 and b is 30
After Swap: a is 10 and b is 30
Oh, what just happened ?! Program as though looked very simple is not working. This is most important thing when program doesn't work as expected, go to the basics. See what is going wrong. Lets draw the stack of above program.
Hence the above program is swapping the local variables of function swap. Now how do we swap a and b ?  Answer is using pointers. Instead of passing the value of a and b to swap. We need to pass the address of a and b. So that using the address of a and b swap function could swap the values in variable.

New Strategy
  • Let the function name be still swap.
  • Since it would swap(exchange) two integer variables lets it prototype be as follows
    • void swap(int *, int*); 
  • Swapping would be done by taking temporary variable

#include <stdio.h>
void swap(int *, int *); 
int main()
{
   int a = 10, b = 30;
   printf("Before Swap: a is %d and b is %d\n", a, b);
   swap(&a, &b);
   printf("After Swap: a is %d and b is %d\n", a, b);
}
void swap(int *px, int *py)
{
   int temp;
   temp = *px;
   *px = *py;
   *py = temp;
   return;
}
Output of above program is

Before Swap: a is 10 and b is 30
After Swap: a is 30 and b is 10
Let me draw the stack diagram of above program
  1. Hence using pointers functions can access the variables of calling function.
  2. Note how in function call address was passed using the address operator &.
  3. Pointers are named generally with p prefixed to them, Just so that programmer is aware that it is a pointer.

Pointers returned from function

Returning pointer from the function is very tricky part. Let me give a negative example here, example which should not be followed

#include <stdio.h>

int *fun();

int main()
{
   int *pa;
   pa = fun();
   printf("Value of a inside main is %d\n", a);
   *pa = 200;
   printf("Value of a inside main, after assigment is %d\n", *pa);
   return 0;
}
int *fun()
{
   int a;
   a = 100;
   printf("Value of a inside fun is %d\n", a);
   return &a;
}
Output of above program is

$ gcc a.c
a.c: In function 'fun':
a.c:18:2: warning: function returns address of local variable [enabled by default]
$ ./a.out 
Value of a inside fun is 100
Value of a inside main is 100
Value of a inside main, after assigment is 200
You might think that it is working as expected. But we need to understand very important thing here. main function is using memory space allocated to fun even after the function call. Local variable 'a' in fun needs to be used only inside the function fun. This variable is created when fun is called inside the stack. When fun is returned it would return it back to stack. But remember it wont be initialized to zero. Hence if you use this memory even after fun call is done it would still have same value 100. (Not always, but in this case yes). Even you can use it to assign new value (in our case 200). But once the stack is given back we should not use that memory. Let me demonstrate by below example which is slight deviation of above example

#include <stdio.h>                                                              

int *fun();
void funx();

int main()
{
   int *pa;
   pa = fun();
   printf("Value of a inside main is %d\n", *pa);
   *pa = 200;
   printf("Value of a inside main, after assigment is %d\n", *pa);
   funx();
   printf("Value of a inside main, after funx call is %d\n", *pa);
   return 0;
}
int *fun()
{
   int a;
   a = 100;
   printf("Value of a inside fun is %d\n", a);
   return &a;
}
void funx()
{
   int g = 1000;
   printf("Inside funx, value of g is %d\n", g);
   return ;
}
Output of above program is as follows
Value of a inside fun is 100
Value of a inside main is 100
Value of a inside main, after assigment is 200
Inside funx, value of g is 1000
Value of a inside main, after funx call is 1000
Now you see that value of variable a has got changed as the same memory was used by funx for allocating its local variable g. Hence it is not a good idea for function to return pointer to its local address. You might want to revisit that C Compiler already complained about the same by issuing the warning.
a.c:18:2: warning: function returns address of local variable [enabled by default]

Most of others (programmers of non C/C++ language) would give above example in proving C is unsafe. My take on this is
  1. C allows programmer to do mistake. Some times mistake would result in catastrophic result.
  2. But if you know how C works, you would not do the mistake in first place.
  3. And there was warning already issued by compiler, hence don't complain.

As much as knowing what works is important, also knowing what doesn't work and why it doesn't work is more important.

Links

Next Article - C Programming #46: Pointer to function
Previous Article - C Programming #44: Pointer - other operators

All Article - C Programming

No comments :

Post a Comment