Pointer is a data type that holds an address of another variable (other than register type)or to point to a memory location in the system and to access their content indirectly. Pointer is not a new data type like char, int etc but it is a type to hold the address of these existing types. We add * before variable name to indicate a pointer type.

Syntax of defining a pointer variable:

<data type> * <variable name>;
example:
int * num_ptr;
Pointer usage with examples:
int * num_ptr = NULL;
int i = 10;
int j = 0;
int k = 2;

/* Now point to the address of i */
num_ptr  = &i;

/*reading the value content at the location of i*/
/* Same as reading I and assigning to k */
k = *num_ptr;

/* assigning j value to the content of location of i*/
/* Same as reading j and assigning to i */
*num_ptr = j;

Pointer is nothing but an unsigned long number (32bit/64bit) which is to hold the address of a memory location. For 32 bit system this has a size of 32 bit or 4 byte and for 64 bit it is 64bit i.e. 8 bytes. Pointer variables are generally assigned to NULL when it was not initialized to a proper address or already been used and now it is free. Assigning an address to a pointer-

int * num_ptr = NULL;
int * num_ptr = (int *) 0xA00000;
int * num_ptr = &i;
int * num_ptr = (int *) malloc (sizeof (int));
Understanding integer pointer

Operator '&' is used to get the address of a variable and Pointers are also used to hold dynamically allocated memory chunks. APIs like malloc() or calloc() are used for allocation and free() is used for this cases.

Declaration of malloc():
void * malloc (size_t size);
size: size of memory block in bytes
Returns: Memory address from heap or returns NULL when failed.

Declaration of calloc():
void * calloc (<block count>, <size of memory one block in bytes>);

Declaration of free():
void free (<memory address>);

Example :
Int * num_ptr = NULL;
num_ptr = (int *) malloc (sizeof (int) * 10);
if (num_ptr) {
  free (num_ptr);
}
num_ptr = (int *) calloc (10, sizeof (int));
if (num_ptr) {
  free (num_ptr);
}

How to use pointers- We generally not concerned with the pointer address but with the value of the variable where it is pointing. This operation is called pointer dereferencing. We use operator * to dereference a pointer value. Pointers are basically 32bit/64bit unsigned integers and thus the value Dereferencing

int i;
num_ptr = &i;

<some variable> = *num_ptr; /* Dereferencing for reading */
*num_ptr = <some variable> /* Dereferencing for writing */
Pointer increments or decrements by the size of the type. Now to understand this we need to understand how a variable is packed in memory. A char type takes only one byte in memory. Thus a char pointer or char * increments or decrements by one. Same way int takes 4 bytes thus pointer increments or decrements by 4.
Say num_ptr is in 0xA00000
num_ptr = (int *)0xA00000;
One step increment using num_ptr++ or num_ptr += 1;
After derement, num_ptr will become 0xA00004;

One step decrement using num_ptr-- or num_ptr -= 1; from original position.
After decrement num_ptr will become 0x9FFFFC;

integer pointer increment or decrement

Void pointer does not have any size thus these operators like sizeof, ++, --, etc are not allowed on void.

void * void_ptr = malloc (sizeof(void)); /*sizeof on void is not allowed by compiler */
void_ptr ++; /* Size is not defined thus not allowed */
void_ptr --; /* Size is not defined thus not allowed */
void_ptr += 1; /* Size is not defined thus not allowed */
void_ptr -= 1; /* Size is not defined thus not allowed */

Pointer is indirect access of a variable/memory element. This creates many confusions and can lead to many unpredictable situations. These situations are not because of pointers but because of our incompitency in programming or carelessness, we face these. We need to be very careful when we are dealing with this. In the next sections we are discussing some of these situations and also finding the proper way to handle these.

Value anomaly of a variable: Pointers can access any variables indirectly. We need to remember that after writing the value to the variable by pointer, the value of the variable going to change. In the source flow we may not see that we have not accessed the variable but still the value has changed. We need to be careful for this and we have one example here

int i = 0;
int * num_ptr = &i;
*num_ptr = 1;
printf ("Value of i is %d\n, i);

Here output will come "Value of i is 1" not 0.

Accessing out of bound memory: Static or Dynamic array has a range of 0 to (ARRAY_SIZE - 1). Point to note here is index is zero based and ends before ARRAY_SIZE not at ARRAY_SIZE. If we access beyond this range then we are supposes to corrupt memory for other variables. We have to be very careful for this.

#define ARRAY_SIZE 10
num_ptr = (int *) malloc (sizeof (int) * ARRAY_SIZE);
/* This loop is proper */
for( i = 0; i < ARRAY_SIZE, i++)
{
  num_ptr[i] = i;
}
/* This loop is improper. last iteration can corrupt an
  element beyond array range */
for( i = 0; i <= ARRAY_SIZE, i++)
{
  num_ptr[i] = i;
}
/* This loop is also improper. first element has not been initialized */
for( i = 1; i < ARRAY_SIZE, i++)
{
  num_ptr[i] = i;
}

free (num_ptr);

Use/access after free: Dynamically allocated memory elements can be deallocated by free() call. We need to ensure that we are all done with this element and at last we de-allocate it. But sometimes it can happen because of improper coding we may access element after freeing.

struct node {
  int value;
  struct node * next;
};

struct node * node;
struct node * tmp_ptr;

node = <head>;
while (node)
{
  tmp_ptr = node;
  free (tmp_ptr); /* Free has no be after next statement */
  node = node->next;
}
/* Proper way to code this */
node = <head>;
while (node)
{
  tmp_ptr = node;
  node = node->next;
  free (tmp_ptr); 
}

Double free: Double free is a case of a allocated memory chunk which is already been freed and again comes to a path where it is going to call a second free.

#define ARRAY_SIZE 10

num_ptr = (int *) malloc (sizeof (int) * ARRAY_SIZE);
pmp_ptr = num_ptr;
for( I = 0; i < ARRAY_SIZE, i++)
{
  num_ptr[i] = I;
}

free (num_ptr);
free (tmp_ptr); /* This free is not needed */

Improper free: We allocate memory with malloc()/calloc() and are supposed to free the memory chunk by providing the same address to free() call. Sometimes we allocate some elements and during iterating through these elements, pointer may shift to some forward or backward location. Now this pointer contains a location which is not obtained via previous malloc/calloc call. Passing this pointer value for argument of free() is not a proper programming.

#define ARRAY_SIZE 10
num_ptr = (int *) malloc (sizeof (int) * ARRAY_SIZE);
tmp_ptr = num_ptr;
while(i < ARRAY_SIZE)
{
  *num_ptr++ = i++;
}

free (num_ptr); /* Should be replaced with free(tmp_ptr) */

Memory leak: Memory leak is a situation where we are not freeing one or more memory chunk when we are finished using it. Main program block often have small logical blocks or threads. Staring a block or thread we allocate some memory and at the end we should free all these. But because of improper design or some error paths may not have free calls. Control may take these paths and allocated memory never gets de-allocated. Now these block or threads are the part of main process thus virtual memory working set will increase as time passes by. This results heavy memory usage of entire system and at last may lead to thrashing.

struct student_t 
{
  char *name;
  int roll;
  int age;
  int class;

};

void copy_student_name(struct student_t *s, char *name)
{
  int len;
  if (s == NULL)
  {
    return;
  }
  len = strlen (name);
  if (len > 0)
  {
    s->name = (char *) malloc(len + 1);
	if (s->name)
	{
	  strcpy (s->name, name);
	}
  }
}
add_student_info(char *name, int class, int roll, int age)
{
  struct student_t s;
  s.roll = roll;
  s.age =age;
  s.class = class;
  copy_student_name(&s, name);
  ret = add_record (&s);
  /* s is going out of scope but 
     s.name pointer is not freed
  */
  return ret;
}

/* This is proper */
add_student_info(char *name, int class, int roll, int age)
{
  struct student_t s;
  s.roll = roll;
  s.age =age;
  s.class = class;
  copy_student_name(&s, name);
  ret = add_record (&s);
  if (s.name)
  {
    free (s.name);
  }
  return ret;
}
int main ()
{
  do {
    ....
    add_student_info("Student1", 1, 1, 5);
	.....
  } while (c != ESC_KEY);

}

You have viewed 1 page out of 248. Your C learning is 0.00% complete. Login to check your learning progress.

 Vote 0

Similar topics related to this section

scanf with printf, print using fprintf, take input using fscanf, floating point formatting, pointers, string vs integer pointer, long pointer increment, short pointer increment, short pointer increment,

# C Programming Language (Prentice Hall Software)
# Let Us C Paperback - 2006 by Yashavant Kanetkar
# Understanding and Using C Pointers Core techniques for memory management
# Data Structures Using C and C++ Paperback - 1998
# Data Structures In C Paperback - August 11, 2008 by Noel Kalicharan