Thursday, October 1, 2015

C language : Pointers -1


Everyone knows about pointer. So we are basically going straight into examples are cross checking our knowledge.



int *p;   or int* p;



Which one is better ? The first one for me, as it makes it easy for getting to know whether its int or function pointer.




Now see below

int *func();  int* func(); int (*func)();



here 1 and 2 are same , since C precedence for * is from left to right. hence we have to use brackets when defining function pointer.



So its better to associate * with either data type or function depending on what you are creating, it will help readability of code.




Now see the below code and see if it has any error and try to correct it.




int main()
{

chat **t=func();

printf("%c",*t[3]);
}

char **func()
{

char **p = (char **) malloc(sizeof(char *));
char *t = "icecream";

p = &t;

}





Now see the below code and see if it has any error and try to correct it.

int **func();

int main()
{

int **t=func();

printf("%d",**t);
}

int **func()
{

int **p = (int **) malloc(sizeof(int *));
int *t;
*t = 3;

*p = t;


}





Now see the below code and see if it has any error and try to correct it.

1)

typedef struct point_T{
int **a;
int b;
}point;



int main()
{

point *var;

var = (point *) malloc(sizeof(point));

(*var).b =2;
*var.b=2;        // WHY IS THIS WRONG
var->b=2;

printf("%d",var->b);

}






2)

typedef struct point_T{
int **a;
int b;
}point;



int main()
{

point *var;

var = (point *) malloc(sizeof(point));
       
  // WHICH ONE IS CORRECT : COMPILE WISE   , and WHY THIS PROGRAM GIVE RUNTIME ERROR

**(var->a)=3;
var->**a=3;
(var)->**a=3;
var->(**a)=3;

printf("%d",var->b);
}






3)

typedef struct point_T{
int **a;
int b;
}point;



int main()
{

point *var;
int b=9;
var = (point *) malloc(sizeof(point));
(*var).b =2;
(var->a)=(int **) malloc(sizeof(int *));
**(var->a)=b;     // IS THIS CORRECT  ???

printf("%d",var->b);
printf("%d",**(var->a));
}





4)  The below program is CORRECT

typedef struct point_T{
int **a;
int b;
}point;



int main()
{

point *var;
int b=9;
var = (point *) malloc(sizeof(point));
(*var).b =2;
(var->a)=(int **) malloc(sizeof(int *));
*(var->a)=&b;

printf("%d",var->b);
printf("%d",**(var->a));
}





If you run the above programs, you will see that  when dealing with pointers.

1) If they are not string literals, then  each  pointer has to be malloced, if you want to store some value in it , else segmentation fault.

2) if it is string literal, then by default malloc gets done.

3) if you are just using pointer to point to some address, no need to malloc, BUT IF IT IS DOUBLE POINTER, then INSIDE POINTER has to be malloced.






One last program for struct and pointers.




typedef struct point_T{
int **a;
int b;
}point;



int main()
{

point var;
int b=9;

var.b =2;
**(var.a)=b;  // Will this work, if not how will u correct it

printf("%d",var.b);
printf("%d",**(var.a));
}





Now coming on the  VOID POINTERS.


Lets see why we need them


Scenario 1 )


There are two processes, each one having their own structure or enum. Now when we want to pass some enum or struct to other process, how we will pass it.


Ex:


in process 1  we have  enum  week1  and in process we have enum week2. now process1 calls func()  to pass value to process2.


What will be the function definition


if we use


void func(week2 var1)  // then we get compile error , since week2 enum if not visible to process1.


if we use  func(week var1)  and then in process2 we get a compile error since week is not visible in process 2.


Hence we have to use void pointer, and take care of assigning correct values in each process.


Some things to take care


1) VOID POINTER can't be deference


Ex  :


int main()
{


int *t = (int *)malloc(sizeof(int));
*t=10;


void *y;


*y =10;  // This will give error
y= t;  // This is correct way.


printf("%d",*y) // again will give error


printf("%d",*((int *)y));  // This is correct way
}


As we can see everytime we have to dereference a void pointer, we have to cast it to some DATA TYPE pointer.




Scenario 2)


Function pointer and Void pointer.


Void pointer , you can think as something which provides a limited level of abstraction to C language.


Its a bucket, in which we can put any type of pointer, Only when we are emptying the bucket we should know what was in it actually.


So when we use function pointer and void pointer.  Again most of them are used when we have more than one process.  In that case


1) Sometimes we don't know what type of function needs to be called.


Example : Suppose there are two friends, One writing code for processing details of employee salary depending on it post.


the other friend is writing code of storing employee details and passing it to other friend.


Now if Friend1 has not told or due  to visibility the function name is not known, then we can't call any function.  So in that case we just call a function pointer, and also pass some data to friend2 so in know emp type.


And will call respective function in his code.




Some points to take care when defining Function Pointers are


1) The correct declaration is


return type (*func_pointer_name) (parameters);


2) Also its best practice to typedef this so that it will become easier


typedef   return_type (*typedef_name)(parameters) ;


Yes syntax is almost same, only we have to add typedef in starting.


3) Unlike data types, function name is itself a pointer or address.


for int we have to do like below


int r=8;
int *t;
t=&r;  // Here we are assigning the address


but with function pointers


void func1(int,int);
void (*func_pointer)(int,int);
func_pointer = func1;          //  No & sign was used.


which seems like below declaration


void func_pointer(int,int);


Only thing is here func_pointer is static and can't be used to change function call.


Now when u have typedef


void func1(int,int);
typedef void (*func_pointer)(int,int);


func_pointer f1;


f1=func;


4)  How to dereference a func pointer.


It can become a little tricky when dereferencing a function pointer, since like int,char pointer our tendency can be to use * while dereferencing, but we have to remember that * only means that it is function pointer, apart from that we have to treat it like normal function name.




int func1(int,int);
int (*func_pointer)(int,int);
func_pointer = func1;          //  No & sign was used.




Now here if we want to print return value of  func1, we would have done like below


printf("%d",func1(2,3));


Now if func_pointer is used, even then we will do the same


printf("%d",func_pointer(7,8));


No need to use * while deferencing.




5) How to pass function pointer.


Now with data type we can use pointer in two ways, while passing pointer from function1 to function2  we assign value in function1  or  we can assign value in function2.


First Way)


int main()
{


int *t= (int *) malloc(sizeof(int));
*t=2;
func(t);
}


void func(int *t)
{
int h=*t;
}


With function


typedef  int (*fp)(int,int);


int add(int a ,int b)
{
 printf("%d",a+b);
}


int main()
{
fp f1 = add;
func( f1)
}


void func(fp t)
{
  t(2,3);
}


Now can we use   typedef int (fp) (int,int).
Yes we can , but it is not used much, since whenever u will pass a function, you have to pass function pointer.


typedef int(fp)(int,int);


int add(int,int);


int main()
{
fp t;
t=add;  This will result in compile error, we have to use  


fp *t;  then only it will work, so its better to have * in typedef only.
}




Second Way)




int main()
{
int *t;
*t=2;
func(t);
printf("%d",*t);
}


void func(int *t)
{
t = (int *) malloc(sizeof(int));
*t=4;
}




With function




typedef  int (*fp)(int,int);


int add(int a ,int b)
{
 printf("%d",a+b);
}


int main()
{
fp f1;
func( f1)
f1(2,3);
}


void func(fp t)
{
t=add;
}


We will carry the discussion of 2nd approach in second post.















No comments:

Post a Comment