Working of WEP

                                                   WORKING OF WEP



The Wired Equivalent Privacy protocol is used in 802.11 networks
to protect link-level data during wireless transmission.
It is described in detail in the 802.11 standard [15];
we reproduce a brief description to enable the following discussion of its properties.

WEP relies on a secret key shared between the communicating
parties to protect the body of a transmitted frame of data.
Encryption of a frame proceeds as follows:

                                                       CHECKSUMMING:
 


First, we compute an integrity checksum c(M)
on the message . We concatenate the two to obtain a plaintext
P=(M,c(M)), which will be used as input to the second stage.
Note that  c(M), and thus , does not depend on
the key .

c(M)=Total no. of message bits to be sent;






                                                      ENCRYPTION:





In the second stage, we encrypt the plaintext
derived above using RC4. We choose an initialization vector
(IV) . The RC4 algorithm generates a keystream—i.e., a
long sequence of pseudorandom bytes—as a function of the
IV and the key . This keystream is denoted by RC4(v,k).
Then, we exclusive-or (XOR, denoted by ) the plaintext
with the keystream to obtain the ciphertext:
          C=P(+)RC4(v,k).
                                                                                                        



                                                    TRANSMISSION:
 



Finally, we transmit the IV and the ciphertext over
the radio link.
Symbolically, this may be represented as follows:
         A-->B:v,(P(+)RC4(v,k)) where P=(M,c(M))





We will consistently use the term message (symbolically,M) to

refer to the initial frame of data to be protected, the term plaintext
(P) to refer to the concatenation of message and checksum as it is
presented to the RC4 encryption algorithm, and the term ciphertext
(C) to refer to the encryption of the plaintext as it is transmitted
over the radio link.









To decrypt a frame protected by WEP, the recipient simply re-
verses the encryption process.
First, he regenerates the keystream RC4(v,k)
and XORs it against the ciphertext to recover the initial
plaintext:

  P'=C(+)RC4(v,k)
    =(P(+)RC4(v,k))(+)RC4(v,k)
    =P
Next, the recipient verifies the checksum on the decrypted plaintext
P' by splitting it into the form (M',c')re-computing the checksum c(M')
and checking that it matches the received checksum c'.
This ensures that only frames with a valid checksum will be
accepted by the receiver.

Thoughts are Things








You imagine many things that are not so,
 but if you continue to imagine these things, they eventually come to pass;
WHY IS THIS?

It is because the imagination is the process of imaging these things in or on your mind, and this process is nature's method of creation.

Perhaps you may think that your imagination can create nothing.
Well, you can easily prove whether this is so or not yourself.


 Take a piece of white paper about twenty-four inches square.
 Draw a circle as large as this paper will permit and then draw a horizontal line through the center of the circle.
 Call the left end of the line "A" and the right end "B".
 Now, draw a vertical line through the circle and call the north end of this line "C" and the south end "D".
 Take a lead pencil and attach a string about eight inches long and upon the end of the string tie a small weight about the size of a quarter
 . Now, then, for the proof.
                                                      
Place the paper on a table, stand upright, and hold the rod above the paper
so that the pendulum will be just above the center of the paper where the lines intersect.
Now think of the line A-B, but do not move;
 in a few minutes the pendulum will swing back and forth along the line A-B.
 Now think of the line C-D;
 the pendulum will stop swinging back and forth and will begin to swing up and down along the line C-D.

Now take your thought off from the lines entirely and fix it upon the circle.
 The pendulum will begin a circular motion.
Now then, think that the pendulum is swinging faster and faster, that you can hardly stop it.
 The motion will become so fast, that you can hardly see it go.

Now then, think that it will not move at all, that something is the matter with it.
It will stop!

This experiment is one that Mr. Charles Baudouin of The Jean Jacques Institute in France uses to illustrate the power of thought to his students.
You may think that this is will power.
 It is nothing of the kind. In fact, if you will the pendulum to move, it will not budge;
 you must think of the result, not upon how it is accomplished.

In his experiments, Mr. Baudouin found that the higher the type of intelligence that the student possessed
the more rapidly did he secure results.
Those students who were more or less deficient in mentality were very slow and in some cases results were almost negligible.

When you become familiar with the operation of this law,
 you will have found the secret of success, of health, of prosperity, of happiness, and of popularity.

You will have discovered a law that is as dependable as the law of gravitation.
When this law is put into operation for the purpose of bringing about material success or prosperity,
 it is called the Creative Law of Prosperity.

You may ask,
 how can this result be accomplished?
 How will the things be brought to you that will make you harmonious, prosperous, and happy?
 They will come to you through the operation of Natural Laws.

Spirit, Universal Mind, life, energy—they express through all forms of the seen and unseen side of life.
 The human brain is the finest, most vibrant vehicle on this plane and thus it has power or control over all things.

If you think or concentrate along any particular line, you start a train of causation;
 and if your thought is sufficiently concentrated and kept continuously in mind, what happens?

There is only one thing that can occur. Whatever the vision you have, the imagination you have, the image is accepted by the Universal Intelligence expressing through the cells of your physical body and environment, and these cells send out their calls into the great formless energy everywhere around you for the material that corresponds with the image and harmonizes in its vibration with it, and whether the image is for success along any particular line or fear of a particular thing, you call the atoms from out of the formless energy which make for the success or the thing you fear—you relate with conditions necessary to bring into manifestation the thing you desire or the thing you fear.
Thoughts of anger, hatred, fear, jealousy, worry, etc., act directly on the secretions causing an actual poison in the system,
 which in time will destroy the body unless they are overcome with love, harmony, joy, faith, etc.
 Constructive thoughts and love is the strongest of all.

We are told by the greatest of teachers that the fundamental or foundation law of our being is love.
 Love God, love your neighbor, love yourself, love your enemy, love everybody and everything.
 No one can afford to hate because hate always destroys the hater. It is said that "Whom the gods would destroy, they first make angry."

Prosperity is a harmonious, creative state of being.
 Creative law will overcome every kind of inharmony, whether it be financial, physical, mental, moral, or social.

Every thought of lack or poverty acts directly on the heart,
affecting the circulation causing constipation, congestion, and many forms of disease due to poor circulation.

Thoughts of prosperity, love, joy, and happiness also act upon the heart,
 causing good circulation and a healthy body.
 There is much truth in the sayings "Laugh and grow fat" and "A merry heart doeth good like a medicine."

Any physician will tell you that if he can get a good circulation of pure blood to the part or organ of the body affected,
 he can heal it, regardless as to what may appear to be the difficulty.

All possession is based on consciousness.
 All gain is the result of an accumulative consciousness.
 All loss is the result of a scattering consciousness.
 This is another way of saying that thoughts are things and that things are thoughts—what one thinks materializes.
 Thoughts are today being photographed showing that they take form in the surrounding ether, or universal substance.
 These are scientific facts.

Thought is a creative energy and will automatically correlate with it object and bring it into manifestation
 because thought is spiritual energy or vibration.

All this brings us back to the fact that prosperity is the result of right, or creative, thinking and that poverty is the result of wrong,
 or destructive, thinking.

You can prove this for yourself in a very short time.

Begin by taking these words: "I am whole, perfect, strong, powerful, loving, harmonious, prosperous, and happy."
Repeat them over and over to yourself as often as you can think to do it,
especially the last thing before dropping off to sleep at night and the first thing upon awaking in the morning.
Remember, these are creative words.

Every thought or word opposed to them is destructive and must not be allowed to enter your mind or to be expressed in words.
 Every thought of disease, sickness, and pain is opposed to wholeness and perfection and should be eliminated by declaring,
 "I am whole and perfect!" Every thought of weakness is opposed to strength and should be put out of mind by saying,
 "I am strong and powerful!"

PLEASE SHARE THIS POST IF YOU LIKE THIS.............




Need for inline functions

TO understand why inline fuction is needed
firstly, we have to understand what happen when funcion is called
from figure:
when function is called the CPU stores the memory address of the instruction following the function call(RIP)
return instruction pointer, then  copies the arguments of the function on the stack and finally transfers control to the specified function then executes the function code
AFTER FUNCTION EXECUTION THE EIP GOES TO RIP;
This can become overhead if the execution time of function is less than the switching time from the caller function to called function (callee)
FOR larger function this overhead is negligible
but for small functions the time needed to make the function call is often a lot more than the time needed to actually execute the function’s code

This overhead occurs for small functions because execution time of small function is less than the switching time.
C++  provides
inline functions to reduce the function call overhead

Inline Functions in C++

Inline Functions in C++

Inline function is one of the important feature of C++.
Inline function is a function that is expanded in line when it is called.
When the inline function is called whole code of the inline function gets inserted or substituted at the point of inline function call.
This substitution is performed by the C++ compiler at compile time. Inline function may increase efficiency if it is small.
it work's like macros
The syntax for defining the function inline is:

inline return-type function-name(parameters)
{
    // function code
}

NOTE::
inlining is only a request to the compiler, not a command.
Compiler can ignore the request for inlining. Compiler may not perform inlining in such circumstances like:
1) If a function contains a loop.
2) If a function contains static variables.
3) If a function is recursive.
4) If a function return type is other than void, and the return statement doesn’t exist in function body.
5) If a function contains switch or goto statement.


 keep in mind that inline functions are the valuable feature of C++.
 An appropriate use of inline function can provide performance enhancement but if inline functions are used
 arbitrarily then they can’t provide better result. In other words don’t expect better performance of program. Don’t make every function inline.
 It is better to keep inline functions as small as possible.


in next post i will tell you why inline function is needed.................,

C++: Templates

TEMPLATES
Templates is used to pass data type as
a parameter(arguments) so that we don’t need to
write same code for different data types.
Template is an example of compile time polymorphism


Declration of Templates:
template <typename T>
return_type function_name(arguments)

example:
 A software company may need sort() for different
 data types. Rather than writing and maintaining the
 multiple codes, we can write one sort()
 and pass data type as a parameter.


How templates works???...



Templates are expended at compiling time.
This is like macros. The difference is,
compiler does type checking before template expansion.
The idea is simple, source code contains only function/class,
but compiled code may contain multiple copies of
same function/class


example:


#include <iostream>
using namespace std;

template <typename T>
void fun(const T&x)
{
    static int count = 0;
    cout << "x = " << x << " count = " << count << endl;
    ++count;
    return;
}

int main()
{
    fun<int> (1);   //x=1 count=0
    cout << endl;  
    fun<int>(1);    //x=1 count=1
    cout << endl;
    fun<double>(1.1);//x=1.1 count=0
    cout << endl;
    return 0;
}

This is because there is diffrent funtion for doubled(data type)
which is created by compiler itself


Function Templates


function that can be used for different data types
This would work
even for user defined dattypes

#include <iostream>
using namespace std;

template <typename T>
T min(T x, T y)     
{
   return (x > y)? x: y;
}

int main()
{
  cout << min<int>(3, 7) << endl;  // Call min for int
  cout << min<double>(3.0, 7.0) << endl; // call min for double
  cout << min<char>('g', 'e') << endl;   // call min for char

  return 0;
}

O/P 3
    3.0
    e


Function Templates with multiple parameters


example:
template<class T1,class T2>
return_type function_name(T1 x,T2 y)

in this fuction we can pass two diffrent datatype
in arguments
void fun( 3,3.0)//one is int type and other is float type



Template Specialization

it is used
if we want a different code for a particular data type

example:
consider the following simple code
where we have general template fun() for all data types
except int.
For int, there is a specialized version of fun().

#include <iostream>
using namespace std;

template <class T>
void fun(T a)
{
   cout << "The main template function " << a << endl;
}

template<>
void fun(int a)
{
    cout << "Specialized Template for int type: " << a << endl;
}

int main()
{                                 outputs
    fun<char>('a');      //The main template function a
    fun<int>(10);        //Specialized Template for int type
    fun<float>(10.14);   //The main template function 10.14
}

If a specialized version is present, compiler first
checks with the specialized version and then
the main template. Compiler first checks with the most
specialized version by matching the passed parameter
with the data type(s) specified in a specialized version.


Overloading of Template function

it is same as simple funtion overloading


example:

template<class T>
void fun(T x)
{ //code of this function};

template<class T, class T1)
void fun(T x,T1 y)
{//code of overloaded function};





Function Templates and static variables:



Each instantiation of function template has its own copy
of local static variables.
For example, in the following program
there are two instances: void fun(int ) and
void fun(double ).
So two copies of static variable i exist.

#include <iostream>

using namespace std;

template <typename T>
void fun(const T& x)
{
  static int i = 10;
  cout << "i="<<i;
  return;
}

int main()
{   
  fun<int>(1);       //  i=10
  cout << endl;
  fun<int>(2);      //   i=11
  cout << endl;
  fun<double>(1.1); //   i=10
  cout << endl;
  getchar();
  return 0;
}

if it is not clear
please read How Templates work???...






Class Templates


Like function templates, class templates are useful
when a class defines something that is independent
of data type

example:

#include<iostream>
using namespace std;

template<class T, class U>
class A 
{
    T x;
    U y;
Public:
    A()
    {   
    cout<<"I am here"<<endl;  
    }
};

int main()
{
   A<char, char> a;  //I am here
   A<int, double> b; //I am here
   return 0;
}

a & b is object name
it is also a example of class Templates with multiple parameters


Class Templates Specialization


#include <iostream>
using namespace std;

template <class T>
class Test
{
 
public:
   Test()
   {
      
       cout << "General template object \n";
   }
   t
};

template <>
class Test <int>
{
public:
   Test()
   {
      
       cout << "Specialized template object\n";
   }
};

int main()
{
    Test<int> a;    //Specialized template object
    Test<char> b;   //General template object
    Test<float> c;  //General template object
    return 0;
}




Class templates and static variables:


The rule for class templates is same as function templates
Each instantiation of class template has its own copy of member static variables. For example, in the following program there are two instances Test and Test. So two copies of static variable count exist.

#include <iostream>

using namespace std;

template <class T>
class Test

  private:
  T val;
  public:
  static int count;
  Test()
  {
    count++;
   
  }
 
};

template<class T>
int Test<T>::count = 0;  //declration of static variable

int main()
{
  Test<int> a;
  Test<int> b; 
  Test<double> c; 
  cout << Test<int>::count   << endl;     // value of count is 2
  cout << Test<double>::count << endl; //value of count is 1
  
  getchar();
  return 0;
}


if it is not clear
read How Templates Work

GATE Questions on C language

1->
The C language is.
a) A context free language
b) A context sensitive language
c) A regular language
d) Parsable fully only by a Turing machine



2->
The value of j at the end of the execution of the following C program.

int incr (int i)
{
   static int count = 0;
   count = count + i;
   return (count);
}
main ()
{
   int i,j;
   for (i = 0; i <=4; i++)
      j = incr(i);
}

(a) 10
(b) 4
(c) 6
(d) 7



3->
Consider the following C declaration

struct {
    short s [5]
    union {
         float y;
         long z;
    }u;
} t;

Assume that objects of the type short, float and long occupy 2 bytes, 4 bytes and 8 bytes,
respectively.
The memory requirement for variable t, ignoring alignment
considerations, is
(a) 22 bytes
(b) 14 bytes
(c) 18 bytes
(d) 10 bytes



4->
The number of tokens in the following C statement.

 printf("i = %d, &i = %x", i, &i);

is
(a) 3
(b) 26
(c) 10
(d) 21



5->
The following C declarations

struct node
{
   int i;
   float j;
};
struct node *s[10] ;

define s to be

(a) An array, each element of which is a pointer to a structure of type node
(b) A structure of 2 fields, each field being a pointer to an array of 10 elements
(c) A structure of 3 fields: an integer, a float, and an array of 10 elements
(d) An array, each element of which is a structure of type node.




6->
Consider the following C program segment:

char p[20];
char *s = "string";
int length = strlen(s);
int i;
for (i = 0; i < length; i++)
     p[i] = s[length — i];
printf("%s",p);

The output of the program is
a) gnirts
b) gnirt
c) string
d) no output is printed



7->
Consider the following C function

void swap (int a, int b)
{
   int temp;
   temp = a;
   a = b;
   b = temp;
}

In order to exchange the values of two variables x and y.
a) call swap (x, y)
b) call swap (&x, &y)
c) swap (x,y) cannot be used as it does not return any value
d) swap (x,y) cannot be used as the parameters are passed by value



8->
Consider the following C function:

int f(int n)
{
   static int i = 1;
   if (n >= 5)
      return n;
   n = n+i;
   i++;
   return f(n);
}

The value returned by f(1) is
a) 5
b) 6
c) 7
d) 8



9->
Consider the following program fragment for reversing the digits in
a given integer to obtain a new integer.
 Let n = D1D2…Dm

int n, rev;
rev = 0;
while (n > 0)
{
   rev = rev*10 + n%10;
   n = n/10;
}

The loop invariant condition at the end of the ith iteration is:

a) n = D1D2….Dm-i and rev = DmDm-1…Dm-i+1
b) n = Dm-i+1…Dm-1Dm and rev = Dm-1….D2D1
c) n \not = rev
d) n = D1D2….Dm and rev = DmDm-1…D2D1



10->
Consider the following C program

main()
{
   int x, y, m, n;
   scanf ("%d %d", &x, &y);
   /* x > 0 and y > 0 */
   m = x; n = y;
   while (m != n)
   {
      if(m>n)
         m = m - n;
      else
         n = n - m;
   }
   printf("%d", n);
}

The program computes
a) x + y using repeated subtraction
b) x mod y using repeated subtraction
c) the greatest common divisor of x and y
d) the least common multiple of x and y



11->
Assume the following C variable declaration

 int *A [10], B[10][10]; 

Of the following expressions
I A[2]
II A[2][3]
III B[1]
IV B[2][3]
which will not give compile-time errors if used as left hand sides of
assignment statements in a C program

a) I, II, and IV only
b) II, III, and IV only
c) II and IV only
d) IV only



12->
Consider the following declaration of a ‘two-dimensional array in C:

 char a[100][100];

Assuming that the main memory is byte-addressable and that the array is
stored starting from memory address 0, the address of a[40][50] is
a) 4040
b) 4050
c) 5040
d) 5050



13->
Consider the following three C functions :

[FI] int * g (void)
{
  int x = 10;
  return (&x);
}

[F2] int * g (void)
{
  int * px;
  *px = 10;
  return px;
}

[F3] int *g (void)
{
  int *px;
  px = (int *) malloc (sizeof(int));
  *px = 10;
  return px;
}

Which of the above three functions are likely to cause problems with pointers?
(a) Only F3
(b) Only F1 and F3
(c) Only F1 and F2
(d) F1, F2 and F3



14->
The most appropriate matching for the following pairs

X: m=malloc(5); m= NULL;        1: using dangling pointers
Y: free(n); n->value=5;         2: using uninitialized pointers
Z: char *p; *p = ’a’;           3. lost memory is:


(a) X—1 Y—3 Z-2
(b) X—2 Y—1 Z-3
(C) X—3 Y—2 Z-1
(d) X—3 Y—1 Z-2



15->
Consider the following C-program:

void foo(int n, int sum)
{
  int k = 0, j = 0;
  if (n == 0) return;
    k = n % 10;
  j = n / 10;
  sum = sum + k;
  foo (j, sum);
  printf ("%d,", k);
}

int main ()
{
  int a = 2048, sum = 0;
  foo (a, sum);
  printf ("%d\n", sum);
 
  getchar();
}

What does the above program print?
(a) 8, 4, 0, 2, 14
(b) 8, 4, 0, 2, 0
(C) 2, 0, 4, 8, 14
(d) 2, 0, 4, 8, 0


DOUBLY LINKED LIST

A Doubly Linked List (DLL) contains an extra pointer, typically called previous pointer, together with next pointer and data which are there in singly linked list.
DLL
Following is representation of a DLL node in C language.
/* Node of a doubly linked list */
struct node
{
  int data;
  struct node *next; // Pointer to next node in DLL
  struct node *prev; // Pointer to previous node in DLL  
};
Following are advantages/disadvantages of doubly linked list over singly linked list.
Advantages over singly linked list
1) A DLL can be traversed in both forward and backward direction.
2) The delete operation in DLL is more efficient if pointer to the node to be deleted is given.
In singly linked list, to delete a node, pointer to the previous node is needed. To get this previous node, sometimes the list is traversed. In DLL, we can get the previous node using previous pointer.
Disadvantages over singly linked list
1) Every node of DLL Require extra space for an previous pointer. It is possible to implement DLL with single pointer though .
2) All operations require an extra pointer previous to be maintained. For example, in insertion, we need to modify previous pointers together with next pointers. For example in following functions for insertions at different positions, we need 1 or 2 extra steps to set previous pointer.
Insertion
A node can be added in four ways
1) At the front of the DLL
2) After a given node.
3) At the end of the DLL
4) Before a given node.
1) Add a node at the front: (A 5 steps process)
The new node is always added before the head of the given Linked List. And newly added node becomes the new head of DLL. For example if the given Linked List is 10<->15<->20<->25 and we add an item 5 at the front, then the Linked List becomes 5<->10<->15<->20<->25. Let us call the function that adds at the front of the list is push(). The push() must receive a pointer to the head pointer, because push must change the head pointer to point to the new node
Following are the 5 steps to add node at the front.
/* Given a reference (pointer to pointer) to the head of a list 
   and an int, inserts a new node on the front of the list. */
void push(struct node** head_ref, int new_data)
{
    /* 1. allocate node */
    struct node* new_node = (struct node*) malloc(sizeof(struct node));
  
    /* 2. put in the data  */
    new_node->data  = new_data;
  
    /* 3. Make next of new node as head and previous as NULL */
    new_node->next = (*head_ref);
    new_node->prev = NULL;

    /* 4. change prev of head node to new node */
    if((*head_ref) !=  NULL)
      (*head_ref)->prev = new_node ;
  
    /* 5. move the head to point to the new node */
    (*head_ref)    = new_node;
}

2) Add a node after a given node.: (A 7 steps process)
We are given pointer to a node as prev_node, and the new node is inserted after the given node.
/* Given a node as prev_node, insert a new node after the given node */
void insertAfter(struct node* prev_node, int new_data)
{
    /*1. check if the given prev_node is NULL */
    if (prev_node == NULL)
    {
        printf("the given previous node cannot be NULL");
        return;
    }

    /* 2. allocate new node */
    struct node* new_node =(struct node*) malloc(sizeof(struct node));

    /* 3. put in the data  */
    new_node->data  = new_data;

    /* 4. Make next of new node as next of prev_node */
    new_node->next = prev_node->next;

    /* 5. Make the next of prev_node as new_node */
    prev_node->next = new_node;

    /* 6. Make prev_node as previous of new_node */
    new_node->prev = prev_node;

    /* 7. Change previous of new_node's next node */
    if (new_node->next != NULL)
      new_node->next->prev = new_node;
}

3) Add a node at the end: (7 steps process)
The new node is always added after the last node of the given Linked List. For example if the given DLL is 5<->10<->15<->20<->25 and we add an item 30 at the end, then the DLL becomes 5<->10<->15<->20<->25<->30.
Since a Linked List is typically represented by the head of it, we have to traverse the list till end and then change the next of last node to new node.
Following are the 7 steps to add node at the end.
/* Given a reference (pointer to pointer) to the head
   of a DLL and an int, appends a new node at the end  */
void append(struct node** head_ref, int new_data)
{
    /* 1. allocate node */
    struct node* new_node = (struct node*) malloc(sizeof(struct node));

    struct node *last = *head_ref;  /* used in step 5*/

    /* 2. put in the data  */
    new_node->data  = new_data;

    /* 3. This new node is going to be the last node, so 
          make next of it as NULL*/
    new_node->next = NULL;

    /* 4. If the Linked List is empty, then make the new
          node as head */
    if (*head_ref == NULL)
    {
        new_node->prev = NULL; 
        *head_ref = new_node;
        return;
    }

    /* 5. Else traverse till the last node */
    while (last->next != NULL)
        last = last->next;

    /* 6. Change the next of last node */
    last->next = new_node;

    /* 7. Make last node as previous of new node */
    new_node->prev = last;

    return;
}

4) Add a node before a given node
This is left as an exercise for the readers.
A complete working program to test above functions.
Following is complete C program to test above functions.
// A complete working C program to demonstrate all insertion methods
#include <stdio.h>
#include <stdlib.h>

// A linked list node
struct node
{
    int data;
    struct node *next;
    struct node *prev;
};

/* Given a reference (pointer to pointer) to the head of a list
   and an int, inserts a new node on the front of the list. */
void push(struct node** head_ref, int new_data)
{
    /* 1. allocate node */
    struct node* new_node = (struct node*) malloc(sizeof(struct node));

    /* 2. put in the data  */
    new_node->data  = new_data;

    /* 3. Make next of new node as head and previous as NULL */
    new_node->next = (*head_ref);
    new_node->prev = NULL;

    /* 4. change prev of head node to new node */
    if((*head_ref) !=  NULL)
      (*head_ref)->prev = new_node ;

    /* 5. move the head to point to the new node */
    (*head_ref)    = new_node;
}

/* Given a node as prev_node, insert a new node after the given node */
void insertAfter(struct node* prev_node, int new_data)
{
    /*1. check if the given prev_node is NULL */
    if (prev_node == NULL)
    {
        printf("the given previous node cannot be NULL");
        return;
    }

    /* 2. allocate new node */
    struct node* new_node =(struct node*) malloc(sizeof(struct node));

    /* 3. put in the data  */
    new_node->data  = new_data;

    /* 4. Make next of new node as next of prev_node */
    new_node->next = prev_node->next;

    /* 5. Make the next of prev_node as new_node */
    prev_node->next = new_node;

    /* 6. Make prev_node as previous of new_node */
    new_node->prev = prev_node;

    /* 7. Change previous of new_node's next node */
    if (new_node->next != NULL)
      new_node->next->prev = new_node;
}

/* Given a reference (pointer to pointer) to the head
   of a DLL and an int, appends a new node at the end  */
void append(struct node** head_ref, int new_data)
{
    /* 1. allocate node */
    struct node* new_node = (struct node*) malloc(sizeof(struct node));

    struct node *last = *head_ref;  /* used in step 5*/

    /* 2. put in the data  */
    new_node->data  = new_data;

    /* 3. This new node is going to be the last node, so
          make next of it as NULL*/
    new_node->next = NULL;

    /* 4. If the Linked List is empty, then make the new
          node as head */
    if (*head_ref == NULL)
    {
        new_node->prev = NULL;  
        *head_ref = new_node;
        return;
    }

    /* 5. Else traverse till the last node */
    while (last->next != NULL)
        last = last->next;

    /* 6. Change the next of last node */
    last->next = new_node;

    /* 7. Make last node as previous of new node */
    new_node->prev = last;

    return;
}

// This function prints contents of linked list starting from the given node
void printList(struct node *node)
{
    struct node *last;
    printf("\nTraversal in forward direction \n");
    while (node != NULL)
    {
        printf(" %d ", node->data);
        last = node;
        node = node->next;
    }

    printf("\nTraversal in reverse direction \n");
    while (last != NULL)
    {
        printf(" %d ", last->data);
        last = last->prev;
    }
}

/* Drier program to test above functions*/
int main()
{
    /* Start with the empty list */
    struct node* head = NULL;

    // Insert 6.  So linked list becomes 6->NULL
    append(&head, 6);

    // Insert 7 at the beginning. So linked list becomes 7->6->NULL
    push(&head, 7);

    // Insert 1 at the beginning. So linked list becomes 1->7->6->NULL
    push(&head, 1);

    // Insert 4 at the end. So linked list becomes 1->7->6->4->NULL
    append(&head, 4);

    // Insert 8, after 7. So linked list becomes 1->7->8->6->4->NULL
    insertAfter(head->next, 8);

    printf("\n Created DLL is: ");
    printList(head);

    getchar();
    return 0;
}
Output:
 Created DLL is:
Traversal in forward direction
 1  7  8  6  4
Traversal in reverse direction
 4  6  8  7  1