(Assigning values to pointers)
(Problems with pointers)
 
(3 intermediate revisions by the same user not shown)
Line 54: Line 54:
 
  #include <stdio.h>
 
  #include <stdio.h>
 
  int main()  
 
  int main()  
{
+
{
  int a;  
+
  int a;  
  int* p;
+
  int* p;
  p = &a;
+
  p = &a;
  int** q; //q is a pointer to a pointer to int
+
  int** q; //q is a pointer to a pointer to int
  q = &p;
+
  q = &p;
  printf("a = %d, *p =%d, **q = %d\n", a, *p, **q);
+
  printf("a = %d, *p =%d, **q = %d\n", a, *p, **q);
}
+
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 74: Line 74:
 
  #include <stdlib.h> //contains the declaration for malloc
 
  #include <stdlib.h> //contains the declaration for malloc
 
  int main()  
 
  int main()  
{
+
{
  int a;  
+
  int a;  
  int* p = &a;
+
  int* p = &a;
  *p = 6;
+
  *p = 6;
p = malloc(10 * sizeof(int));
+
  p = malloc(10 * sizeof(int));
*(p+5) = 7;
+
  *(p+5) = 7;
printf("a = %d, *(p+5) = %d, p[5] = %d\n", a, *(p+5), p[5]);
+
  printf("a = %d, *(p+5) = %d, p[5] = %d\n", a, *(p+5), p[5]);
}
+
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
==Problems with pointers==
 
==Problems with pointers==
Pointers are very powerful but with power comes problems. Since, pointer allows direct access to memory address, if programmer is not careful, pointer usage can cause segmentation faults. Then pointer dereferencing is difficult to debug especially when there are more than two levels of indirection (pointer to pointers).
+
Pointers are very powerful but with power comes problems. Since, pointer allows direct access to memory address, if programmer is not careful, pointer usage can cause segmentation faults. The other problem with pointer is that pointer dereferencing is difficult to debug especially when there are more than two levels of indirection (pointer to pointers).
  
 
==Exercise Questions==
 
==Exercise Questions==

Latest revision as of 19:58, 16 June 2014

Pointer as the word implies just points. It is a datatype in C which is used to hold memory address. Pointers may point to any datatype in C and based on the data type pointer arithmetic is done.

* Operator

A pointer is declared using * as follows: <syntaxhighlight lang="C">

int* p; //p is a pointer to int. int *p is also syntactically correct but * here is always taken with int as int* and p is the name for the variable. Many take this as *p which is not correct
char* y; //y is a pointer to char

</syntaxhighlight>


Actually pointer operation is very simple as there are just one operator for using pointer which is the dereferencing operator *.

*p -> gives the content of the location in p. 

What the content is, depends on the type of p. If p is an integer pointer, *p will return 4 bytes from the location contained in p. If p is a char pointer *p will return 1 byte from the location in p.

Example

<syntaxhighlight lang="C">

int *p, a;
scanf("%d",&a); //memory address of a is passed to scanf and it stores the keyboard entered value in that location
p = &a; //Memory address of a is stored in p
printf("*p = %d", *p); //Content of p is printed by printf. Since %d is used, 4 bytes (assuming sizeof int is 4) from the memory location given by p is converted to integer and printed.

</syntaxhighlight>


The below code also does the same job but in a slightly different manner.

<syntaxhighlight lang="C">

int *p, a;
p = &a;
scanf("%d",p);
printf("a = %d *p = %d", a, *p);

</syntaxhighlight>

Pointer Arithmetic

Why do we do pointer arithmetic? It is to access the next or previous elements in an array of elements. For that reason pointer arithmetic is restricted to just addition and subtraction. And though pointers can be represented using integer values, as they hold memory addresses, pointer arithmetic is different from integer arithmetic. Pointer arithmetic works as follows: <syntaxhighlight lang="C">

//Assume p and q are pointers
p+1 //p is incremented to the next address for holding the data type for p. i.e; if p is an int pointer p+2 will add 8 to the content of p (assuming sizeof (int) is 4)
p-1 //p is decremented to the previous address for holding the data type of p
p-q //If p and q are pointers p-q will work as above and thus will return the no. of objects of type of p (p and q must be of same data type or else it is compilation error)
p+q //Not allowed and throws compilation error

</syntaxhighlight>


There is no multiplication or division operations in pointer arithmetic as they have no meaning.

Does a pointer have memory?

Yes, pointer is a data type and so has a memory for it. On a 32 bit system, pointer requires 4 bytes (32 bits) of memory while on a 64 bit system it requires 8 bytes. And it is the same for pointer to any data type. Since pointer has a memory, we can have a pointer to pointer as well and this can be extended to any level.

Example

<syntaxhighlight lang="c">

#include <stdio.h>
int main() 
{
  int a; 
  int* p;
  p = &a;
  int** q; //q is a pointer to a pointer to int
  q = &p;
  printf("a = %d, *p =%d, **q = %d\n", a, *p, **q);
}

</syntaxhighlight>

Assigning values to pointers

Since pointers should hold valid memory address (OS allocates certain memory region for a process and it should use only that region and should not try to access other memory region), we should not assign random values to a pointer variable. Assigning some values to a pointer is allowed, but if that value is not in the memory address for the process, dereferencing that pointer using * operator will cause segmentation fault.

One way of assigning value to a pointer variable is by using & operator on an already defined variable. Thus, the pointer variable will now be holding the address of that variable. The other way is to use malloc function which returns an array of dynamic memory created on the heap. This method is usually used to create dynamic arrays.

Example

<syntaxhighlight lang="c">

#include <stdio.h>
#include <stdlib.h> //contains the declaration for malloc
int main() 
{
  int a; 
  int* p = &a;
  *p = 6;
  p = malloc(10 * sizeof(int));
  *(p+5) = 7;
  printf("a = %d, *(p+5) = %d, p[5] = %d\n", a, *(p+5), p[5]);
}

</syntaxhighlight>

Problems with pointers

Pointers are very powerful but with power comes problems. Since, pointer allows direct access to memory address, if programmer is not careful, pointer usage can cause segmentation faults. The other problem with pointer is that pointer dereferencing is difficult to debug especially when there are more than two levels of indirection (pointer to pointers).

Exercise Questions

<quiz display="simple"> {What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 5;
 int* p = &a;
 printf("%d", ++*p);

} </syntaxhighlight> |type="{}" /} { 6 } ||p is pointing to the address of a. *p will return the content of a which is 5 and ++ will increment it to 6.


{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 char a[] = "Hello World";
 char* p = &a;
 printf("%s", p+2 );

} </syntaxhighlight> |type="()" /} -Compiler Error -World +llo World -Runtime Error

||Since p is a char pointer p+2 will add 2 to p (since sizeof(char) is 1). So, p+2 will be pointing to the string "llo World".

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a;
 int* p = &a;
 printf("%zu", sizeof( *(char*)p  ));

} </syntaxhighlight> |type="()" /}

+1 -2 -4 -Compile Error

||p is typecasted to char pointer and then dereferenced. So, returned type will be char and sizeof(char) is 1.

{Is the following code legal? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 1;
 if((char*)  &a)
 {
   printf("My machine is little endian");
 }
 else
 {
    printf("My machine is big endian\n");
 }

} </syntaxhighlight> |type="()" /} +Yes -No ||On a little endian machine the lower address will contain the least significant byte. Suppose a is stored at address 1000 and contains 1, then character at 1000 will be 1, if the machine is little endian.

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int *a = (int*) 1;
 printf("%d", a);

} </syntaxhighlight> |type="()" /} -Garbage value +1 -0 -Compile error -Segmentation fault ||Assigning int values to pointer variable is possible. Only when we dereference the variable using *, we get a segmentation fault.

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 1, *p, **pp;
 p = &a;
 pp = p;
 printf("%d", **pp);

} </syntaxhighlight> |type="()" /} -Garbage value -1 -Compile error +Segmentation fault ||Here, p is having address of a and the same is copied to pp. So, *pp will give 1 which is contained in a, but **p will use 1 as an address and tries to access the memory location 1, giving segmentation fault.

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 1, *p, **pp;
 p = &a;
 pp = p;
 printf("%d", *pp);

} </syntaxhighlight> |type="()" /} +1 -Garbage value -Compile error -Segmentation fault ||Here, p is having address of a and the same is copied to pp. So, *pp will give 1 which is contained in a.


{Assuming a little endian machine, what will be the output of the following program? <syntaxhighlight lang="c">

  1. include<stdio.h>

fun(int a) {

 char *arr[] = {"0000", "0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};
 unsigned char* p = (unsigned char*) &a ;
 p+=3;
 int i;
 for(i = 0; i < sizeof a; i++)
 {
   int d = (*p)>>4; 
   printf("%s", arr[d]);
   d = (*p) & 0xf;
   printf("%s ", arr[d]);
   p--;
 }

}

int main() {

int a;
scanf("%d", &a);
fun(a);

} </syntaxhighlight> |type="()" /} +Print the binary of the input number -Compile error -Runtime error -Compiler dependent output ||The code is printing the binary equivalent of the input number. Suppose a is stored starting from address 1000. Since, we assume a little endian machine, the LSB of a will be stored at address 1000 and MSB will be stored at address 1003. So, we make a char pointer to 1003 and take out the MSB. Then using shift operator we get the most significant 4 bits from it and then the lest significant 4 bits. We repeat the same for the other three bytes of a. </quiz>



blog comments powered by Disqus

Pointer as the word implies just points. It is a datatype in C which is used to hold memory address. Pointers may point to any datatype in C and based on the data type pointer arithmetic is done.

* Operator[edit]

A pointer is declared using * as follows: <syntaxhighlight lang="C">

int* p; //p is a pointer to int. int *p is also syntactically correct but * here is always taken with int as int* and p is the name for the variable. Many take this as *p which is not correct
char* y; //y is a pointer to char

</syntaxhighlight>


Actually pointer operation is very simple as there are just one operator for using pointer which is the dereferencing operator *.

*p -> gives the content of the location in p. 

What the content is, depends on the type of p. If p is an integer pointer, *p will return 4 bytes from the location contained in p. If p is a char pointer *p will return 1 byte from the location in p.

Example[edit]

<syntaxhighlight lang="C">

int *p, a;
scanf("%d",&a); //memory address of a is passed to scanf and it stores the keyboard entered value in that location
p = &a; //Memory address of a is stored in p
printf("*p = %d", *p); //Content of p is printed by printf. Since %d is used, 4 bytes (assuming sizeof int is 4) from the memory location given by p is converted to integer and printed.

</syntaxhighlight>


The below code also does the same job but in a slightly different manner.

<syntaxhighlight lang="C">

int *p, a;
p = &a;
scanf("%d",p);
printf("a = %d *p = %d", a, *p);

</syntaxhighlight>

Pointer Arithmetic[edit]

Why do we do pointer arithmetic? It is to access the next or previous elements in an array of elements. For that reason pointer arithmetic is restricted to just addition and subtraction. And though pointers can be represented using integer values, as they hold memory addresses, pointer arithmetic is different from integer arithmetic. Pointer arithmetic works as follows: <syntaxhighlight lang="C">

//Assume p and q are pointers
p+1 //p is incremented to the next address for holding the data type for p. i.e; if p is an int pointer p+2 will add 8 to the content of p (assuming sizeof (int) is 4)
p-1 //p is decremented to the previous address for holding the data type of p
p-q //If p and q are pointers p-q will work as above and thus will return the no. of objects of type of p (p and q must be of same data type or else it is compilation error)
p+q //Not allowed and throws compilation error

</syntaxhighlight>


There is no multiplication or division operations in pointer arithmetic as they have no meaning.

Does a pointer have memory?[edit]

Yes, pointer is a data type and so has a memory for it. On a 32 bit system, pointer requires 4 bytes (32 bits) of memory while on a 64 bit system it requires 8 bytes. And it is the same for pointer to any data type. Since pointer has a memory, we can have a pointer to pointer as well and this can be extended to any level.

Example[edit]

<syntaxhighlight lang="c">

#include <stdio.h>
int main() 

{

 int a; 
 int* p;
 p = &a;
 int** q; //q is a pointer to a pointer to int
 q = &p;
 printf("a = %d, *p =%d, **q = %d\n", a, *p, **q);

} </syntaxhighlight>

Assigning values to pointers[edit]

Since pointers should hold valid memory address (OS allocates certain memory region for a process and it should use only that region and should not try to access other memory region), we should not assign random values to a pointer variable. Assigning some values to a pointer is allowed, but if that value is not in the memory address for the process, dereferencing that pointer using * operator will cause segmentation fault.

One way of assigning value to a pointer variable is by using & operator on an already defined variable. Thus, the pointer variable will now be holding the address of that variable. The other way is to use malloc function which returns an array of dynamic memory created on the heap. This method is usually used to create dynamic arrays.

Example[edit]

<syntaxhighlight lang="c">

#include <stdio.h>
#include <stdlib.h> //contains the declaration for malloc
int main() 

{

 int a; 
 int* p = &a;
 *p = 6;
p = malloc(10 * sizeof(int));
*(p+5) = 7;
printf("a = %d, *(p+5) = %d, p[5] = %d\n", a, *(p+5), p[5]);

} </syntaxhighlight>

Problems with pointers[edit]

Pointers are very powerful but with power comes problems. Since, pointer allows direct access to memory address, if programmer is not careful, pointer usage can cause segmentation faults. Then pointer dereferencing is difficult to debug especially when there are more than two levels of indirection (pointer to pointers).

Exercise Questions[edit]

<quiz display="simple"> {What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 5;
 int* p = &a;
 printf("%d", ++*p);

} </syntaxhighlight> |type="{}" /} { 6 } ||p is pointing to the address of a. *p will return the content of a which is 5 and ++ will increment it to 6.


{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 char a[] = "Hello World";
 char* p = &a;
 printf("%s", p+2 );

} </syntaxhighlight> |type="()" /} -Compiler Error -World +llo World -Runtime Error

||Since p is a char pointer p+2 will add 2 to p (since sizeof(char) is 1). So, p+2 will be pointing to the string "llo World".

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a;
 int* p = &a;
 printf("%zu", sizeof( *(char*)p  ));

} </syntaxhighlight> |type="()" /}

+1 -2 -4 -Compile Error

||p is typecasted to char pointer and then dereferenced. So, returned type will be char and sizeof(char) is 1.

{Is the following code legal? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 1;
 if((char*)  &a)
 {
   printf("My machine is little endian");
 }
 else
 {
    printf("My machine is big endian\n");
 }

} </syntaxhighlight> |type="()" /} +Yes -No ||On a little endian machine the lower address will contain the least significant byte. Suppose a is stored at address 1000 and contains 1, then character at 1000 will be 1, if the machine is little endian.

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int *a = (int*) 1;
 printf("%d", a);

} </syntaxhighlight> |type="()" /} -Garbage value +1 -0 -Compile error -Segmentation fault ||Assigning int values to pointer variable is possible. Only when we dereference the variable using *, we get a segmentation fault.

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 1, *p, **pp;
 p = &a;
 pp = p;
 printf("%d", **pp);

} </syntaxhighlight> |type="()" /} -Garbage value -1 -Compile error +Segmentation fault ||Here, p is having address of a and the same is copied to pp. So, *pp will give 1 which is contained in a, but **p will use 1 as an address and tries to access the memory location 1, giving segmentation fault.

{What will be the output of the following code? <syntaxhighlight lang="c">

  1. include<stdio.h>

int main() {

 int a = 1, *p, **pp;
 p = &a;
 pp = p;
 printf("%d", *pp);

} </syntaxhighlight> |type="()" /} +1 -Garbage value -Compile error -Segmentation fault ||Here, p is having address of a and the same is copied to pp. So, *pp will give 1 which is contained in a.


{Assuming a little endian machine, what will be the output of the following program? <syntaxhighlight lang="c">

  1. include<stdio.h>

fun(int a) {

 char *arr[] = {"0000", "0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};
 unsigned char* p = (unsigned char*) &a ;
 p+=3;
 int i;
 for(i = 0; i < sizeof a; i++)
 {
   int d = (*p)>>4; 
   printf("%s", arr[d]);
   d = (*p) & 0xf;
   printf("%s ", arr[d]);
   p--;
 }

}

int main() {

int a;
scanf("%d", &a);
fun(a);

} </syntaxhighlight> |type="()" /} +Print the binary of the input number -Compile error -Runtime error -Compiler dependent output ||The code is printing the binary equivalent of the input number. Suppose a is stored starting from address 1000. Since, we assume a little endian machine, the LSB of a will be stored at address 1000 and MSB will be stored at address 1003. So, we make a char pointer to 1003 and take out the MSB. Then using shift operator we get the most significant 4 bits from it and then the lest significant 4 bits. We repeat the same for the other three bytes of a. </quiz>



blog comments powered by Disqus