POINTERS
Type Casting of pointers
Yes it is true that in C one type of pointer can be converted into another. There are 2 categories of pointer conversions in C.
(1) those that involve void* pointers and (2) those that don't!
The void* pointer, which is a "generic pointer" is permissible to assign any other type of pointer. And it is also permissible to assign any other pointer type to void* pointer. The void* pointer is used to refer to raw memory(the results of malloc() function) when the semantics of the memory are unknown. No explicit cast is required to convert to or from a void* pointer.
Except for void* all other pointer conversion must be performed with an accompanying explicit type cast. However there are some difficulties.
Example E1
_________________________________________________________________________________
#include<stdio.h>
main()
{
double x=101.31754833673,y;
int *p;
/* now we set the integer pointer to point the double x*/
p=(int*)&x;
/*then we try to assign y the value of x via the pointer p*/
y=*p;
/*however the above statement doesn't work as expected*/
printf("value of y is : %f",y);
}
_________________________________________________________________________________
try this one and see the result.
What really happened was, when we explicitly type casted the double x into integer pointer p, the pointer p points only to 2 bytes of data as it is an integer pointer, so in the background p points only to 2 bytes of data of the 8 byte long x-- which means the remaining 6 bytes of x were chipped off!
Work W1
OK now here is a work for the reader, in our previous example E1 we used a type cast of double value to an integer pointer- try out what happens if the reverse is done, that is try type casting of an integer value to a double value.
Here p=x is wrong. The statement assigns the value 10 to the pointer p. However, p is supposed to contain an address, not a value. To correct the program, write p=&x.
Making any comparison between pointers that do no point to the same object may yield unexpected results. For example:
E5
_________________________________________________________________________________
main()
{
char s[100], y[100];
char *p1,*p2;
p1=s;
p2=y;
if(p1<p2)
{
- - - - -
}
---------
}
_________________________________________________________________________________
The above given program quite an invalid concept, think why ?
A related error results when you assume that two adjacent arrays may be indexed as one by simply incrementing a pointer across the array boundaries. For example:
E6
_________________________________________________________________________________
main()
{
int first[10],second[10];
int *p,t;
p=first;
for(t=0;t<20;++t)
*p++ = t;
}
_________________________________________________________________________________
This is not a good way to initialize the arrays first and second with the numbers 0 through 19. Even though it may work on some compilers under certain circumstances, it assumes that both arrays will be placed back to back in memory with first first. This may not always be the case.
This is your turn, try to find the bug in this program!
E7
_________________________________________________________________________________
/* this program has a bug*/
#include<stdio.h>
#include<string.h>
main()
{
char *p1;
char s[100];
p1=s;
do
{
gets(s);
/* print the decimal equivalent of each character in s */
while(*p1)
printf("%d", *p1++);
}
while(strcmp(s,"done"));
}
_________________________________________________________________________________
The problem is that p1 is assigned the address of s only once, outside the loop. The first time through the loop, p1 points to the first character in s. However, the second time through, it continues where it left off because it is not reset to the start of s. This next character may be part of the second string, another variable, or a piece of the program! The proper way to write this program is by placing the assignment operation p1=s as the first statement of the do-while loop.
Pointers to functions
Dear friend this a confusing yet powerful feature of our C. Every function has a physical location in memory, like we directly assign a variable an address which stores the value we can manipulate. We can use pointers to use functions.Function pointers also allow functions to be passed as arguments to other functions- now wait functions as arguments? that's weird! isn't it?
We can obtain the address of a function directly from its name without any arguments or parentheses. This is similar to getting the address of an array from its name without its size or square brackets.
Example E2
_________________________________________________________________________________
#include<stdio.h>
#include<string.h>
void check(char a*,char b*,int(cmp*)(const char*,const char*))
{
printf("Testing for equality.\n");
if(!(cmp*)(a,b))
printf("Equals");
else
printf("Not equals");
}
main()
{
char s1[100],s2[100];
int (*p)(const char*,const char*); /*function pointer*/
p=strcmp; /*assign address of function strcmp to p*/
printf("enter the strings");
gets(s1);
gets(s2);
check(s1,s2,p); /*pass address of strcmp via p*/
}
_________________________________________________________________________________
remember to put the parentheses around *p and *cmp, it is necessary inorder for the compiler to interpret their corresponding declarations.
Inside the check(), the expression
(*cmp)(a,b);
calls strcmp, which is pointed to by cmp, with a & b as arguments. Another simpler syntax for the above stt is :
cmp(a,b);
but it is wise to use the first one, because the reader can easily understand that cmp is a function pointer $ not a function.
You can also call check() using strcmp directlylike
check(s1,s2,strcmp);
which eliminates the nerded for an additional pointer variable.
You may wonder why anyone would use such a style of programming which introduces lots and lots of confusion. However, at times it is advantageous to pass functions as parameter s or to create an array of functions. For example, when an interpreter is written, the parser(the part which processes the expression) often calls various supporting functions, such as those that compute mathematical operations(sine, cosine, tangent, etc), perform I/O, or access system resources. Instead of having a large switch statement with all of these function listed in it, an array of function pointers can be created. Here the proper function is selected by its index
The Restrict Qualifier for Pointers!
The C99 standard has added a new type qualifier that applies only to pointers: restrict.
A pointer qualified by restrict is initially the only means by which the object it points to is accessed. Access to the object by another pointer can occur only if the second pointer is based on the first. Thus, access to the object is restricted to expressions based on the restrict - qualified pointer. Pointers qualified by restrict are primarily used as function parameters or to point to memory allocated via malloc(). By qualifying a pointer with restrict, the compiler is better able to optimize certain types of routines. For example, if a function specifies two restrict - qualifier pointer parameters, then the compiler can assume that the pointers point to different(that is non-overlapping) object. The restrict qualifier doesn't change the semantics of the program.
Common Mistakes that we make with pointers.
Pointers are a mixed blessing. They give you tremendous power, but when a pointer is used incorrectly, or contains the wrong value, it can be a very difficult bug to find(such pointers are usually known as wild pointers).
BELIEVE ME NOTHING WILL GET YOU INTO MORE TROUBLE THAN A WILD POINTER!
The classic example of a pointer error is the uninitialized pointer.
E3
_________________________________________________________________________________
/*Believe it or not this junk of program is absolutely wrong */
main()
{
int x,*p;
x=10;
*p=x; /*ERROR p is not initialized!*/
}
_________________________________________________________________________________
This program assigns the value 10 to some unknown memory location. Here is the reason. Since the pointer p has never been given a value it contains an unknown(garbage) value when the assignment *p=x takes place. This causes the value of x to be written to some unknown memory location. This type of problem often goes unnoticed when the program is small. because the odds are in favor of containing a "safe" address - one that is not in your code, data area, or Operating system. However as your program grows the probability increases of p pointing to something vital. Eventually, your program stops working.
A second common error is caused by a simple misunderstanding of how to use a pointer. Consider the following:
E4
_________________________________________________________________________________
main()
{
int x,*p;
x=10;
p=x;
printf("%d",*p);
}
_________________________________________________________________________________
E4
_________________________________________________________________________________
main()
{
int x,*p;
x=10;
p=x;
printf("%d",*p);
}
_________________________________________________________________________________
Here p=x is wrong. The statement assigns the value 10 to the pointer p. However, p is supposed to contain an address, not a value. To correct the program, write p=&x.
Making any comparison between pointers that do no point to the same object may yield unexpected results. For example:
E5
_________________________________________________________________________________
main()
{
char s[100], y[100];
char *p1,*p2;
p1=s;
p2=y;
if(p1<p2)
{
- - - - -
}
---------
}
_________________________________________________________________________________
The above given program quite an invalid concept, think why ?
A related error results when you assume that two adjacent arrays may be indexed as one by simply incrementing a pointer across the array boundaries. For example:
E6
_________________________________________________________________________________
main()
{
int first[10],second[10];
int *p,t;
p=first;
for(t=0;t<20;++t)
*p++ = t;
}
_________________________________________________________________________________
This is not a good way to initialize the arrays first and second with the numbers 0 through 19. Even though it may work on some compilers under certain circumstances, it assumes that both arrays will be placed back to back in memory with first first. This may not always be the case.
This is your turn, try to find the bug in this program!
E7
_________________________________________________________________________________
/* this program has a bug*/
#include<stdio.h>
#include<string.h>
main()
{
char *p1;
char s[100];
p1=s;
do
{
gets(s);
/* print the decimal equivalent of each character in s */
while(*p1)
printf("%d", *p1++);
}
while(strcmp(s,"done"));
}
_________________________________________________________________________________
The problem is that p1 is assigned the address of s only once, outside the loop. The first time through the loop, p1 points to the first character in s. However, the second time through, it continues where it left off because it is not reset to the start of s. This next character may be part of the second string, another variable, or a piece of the program! The proper way to write this program is by placing the assignment operation p1=s as the first statement of the do-while loop.