Sunday, November 29, 2015

Byte Alignment

Byte alignment is associated with how efficiently a processor can read & write information stored to & from memory. A processor may provide instruction to access data from memory in chunks of 4-bytes, 2-bytes or 1-byte. It may only be possible to access a memory location whose address is multiple of 2 or 4. Some processor throw exception if a program tries to access memory location which is not an integral multiple of 2 or 4. In such case, if the operating system does not take care of such situation the program may crash.  In other case, the memory access at such address take more CPU cycles thereby reducing the efficiency. In order to handle such scenario padding is done so the data ends at 2-byte or 4 byte boundary. Lets look at an example. How is following structure is stored in memory?
struct recordType1 {
 unsigned char name[10];
 unsigned int id;
 unsigned int age;
 unsigned char grade;
 float exp;
};

On my X86/Linux PC, it consumes 28 bytes. I have initialized the above structure and print it byte by byte.
#include <stdio.h>
#include <stdlib.h>

void printStruct(unsigned char *ptr, unsigned int size) {
 unsigned int indx = 0;
 printf("Size: %dn", size);

 for(; indx < size; indx++)
  printf("%02x ", ptr[indx]);

 printf("n");
}

int main() {
 struct recordType1 emp1 = {"MyName", 1102, 31, 'A', 7.2};

 printStruct((unsigned char *) &emp1, sizeof(emp1));

 return 0;
}

Here is the output.

Size in bytes : 28
4d 79 4e 61 6d 65 00 00 00 00 b4 bf 4e 04 00 00 1f 00 00 00 41 80 79 b7 66 66 e6 40

First 10 underlined bytes is name field, then four underlined bytes is for id field and so on. There are 2 bytes after name field & 3 bytes after grade field. These additional bytes are padded so that each filed in struct recordType1 falls on 2-byte boundary. And that is why the structure is taking 28 bytes of memory. Let's do some modification to this structure.
 struct recordType2 {
 unsigned int id;
 unsigned int age;
 float exp;
 unsigned char name[10];
 unsigned char grade;
};

With the same initialization as above, lets check the byte of memory consumed and layout.

Length in bytes : 24
4e 04 00 00 1f 00 00 00 66 66 e6 40 4d 79 4e 61 6d 65 00 00 00 00 41 08

We saved 4 bytes with such a simple modification. This is on the memory consumption part.

Let's see how the speed of execution is affected by byte aligned access. Here is a simple program. There are two pointer ptr1 and ptr2, which write a buffer with 10 meg of data. The ptr1 starts with the buffer address which is divisible by 4 but ptr2 is not.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#define MEGA_10    (1024*1024*10)
#define MEGA_100 (10 * MEGA_10)

int main()
{
 unsigned char *buffer;
 unsigned int *ptr1, *ptr2, bufSize = (MEGA_100/4), indx = 0;
 unsigned isOn4bdry = 0;
 struct timeval t1, t2;

 buffer = (unsigned char *)calloc(MEGA_100+1, sizeof(unsigned char));

 isOn4bdry = (((unsigned int)buffer % 4) == 0) ? 1 : 0;
 printf("Buffer pointer: %p, On 4 boundary: %dn", buffer, isOn4bdry);

 gettimeofday(&t1, (struct timezone *)NULL);
 ptr1 = (unsigned int *)buffer;
 for( ; indx < bufSize; indx++){
  *ptr1 = 0xDEADBEEF;
  ptr1++;
 }

 gettimeofday(&t2, (struct timezone *)NULL);
 printf("Time taken: %dn", (int)(t2.tv_usec - t1.tv_usec));

 memset((void *)buffer, 0x0, bufSize);

 gettimeofday(&t1, (struct timezone *)NULL);
 buffer += 1;
 ptr2 = (unsigned int *)buffer;
 isOn4bdry = (((unsigned int)buffer % 4) == 0) ? 1 : 0;
 printf("Buffer pointer: %p, On 4 boundary: %dn", buffer, isOn4bdry);
 bufSize -= 1;

 for(indx = 0 ; indx < bufSize; indx++){
  *ptr2 = 0xDEADBEEF;
  ptr2++;
 }

 gettimeofday(&t2, (struct timezone *)NULL);
 printf("Time taken: %dn", (int)(t2.tv_usec - t1.tv_usec));

 buffer -= 1;
 free(buffer);

 return(0);
}

And the output.

Buffer pointer: 0xb11c6008, On 4 boundary: 1
Time taken: 58653
Buffer pointer: 0xb11c6009, On 4 boundary: 0
Time taken: 60675

Please note, I have not taken care of wrapping of tv_usec field and the above time values are in microseconds.

Look at the difference time taken to initialize the same buffer. In first case i.e. byte aligned access, we are saving a little more than 2.022 ms.

Saturday, November 28, 2015

Find median of a random stream

In statistics and probability theory, a median is the number separating the higher half of a data sample, a population, or a probability distribution, from the lower half. The median of a finite list of numbers can be found by arranging all the observations from lowest value to highest value and picking the middle one (e.g., the median of {3, 3, 5, 9, 11} is 5). If there is an even number of observations, then there is no single middle value; the median is then usually defined to be the mean of the two middle values (the median of {3, 5, 7, 9} is (5 + 7) / 2 = 6), which corresponds to interpreting the median as the fully trimmed mid-range. [Wikipedia]

Hacker Rank Question: The median of a finite list of numbers can be found by arranging all the integers from lowest to highest value and picking the middle one. For example, the median of {3,3,5,9,11} is 5. If there is an even number of integers, then there is no single middle value, and the median is then usually defined to be the mean of the two middle values. For examples, the median of {3,5,7,9} is (5+7)2=6. [Hackerrank]

The comparison of different approach and optimal algorithm is explained in detail in reference [1] & [2]. However, following is the steps for implementation using heap.

  1. Define two heaps, min heap and max heap.
  2. Insert data into min heap if data from stream is greater than median else insert into max heap.
  3. Calculate new median.
    1. If the count of data in min heap is greater than that of max heap by 1, median is root of min heap.
    2. If the count of data in max heap is greater than that of min heap by 1, median is root of max heap.
    3. If the count of data in both the heaps are same, then the median is the average of data in root of min and max heap.
  4. If the count of data in either of the heaps differ by more than 1, the data from one heap needs to be moved to other heap.
    1. If the count of data in min heap is more, move the minimum data i.e. root of heap to max heap.
    2. If the count of data in max heap is more, move the maximum data i.e. root of heap to min heap.
Following is the C implementation of above steps. However, for a stream of 100000 data the algorithm takes 18.70 secs.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

//pointers to array which hold maxHeap and minHeap
int* maxHeap;
int* minHeap;
//length of the arrays
int maxHeapLen = 0, minHeapLen = 0;
//median
float median;

int getLeftChildIndex(int cIndx) {
    cIndx += 1;
    return (2 * cIndx - 1);
}

int getRightChildIndex(int cIndx) {
    cIndx += 1;
    return (2 * cIndx);
}

void maxHeapify(void) {
    if(maxHeap == NULL || maxHeapLen == 0)
        return;
    
    int lChildIndx, rChildIndx;
    
    for(int indx = maxHeapLen/2 + 1; indx >= 0; indx--) {
        lChildIndx = getLeftChildIndex(indx);
        rChildIndx = getRightChildIndex(indx);
        int tmp;
        
        if(lChildIndx < maxHeapLen && maxHeap[indx] <= maxHeap[lChildIndx]) {
            tmp = maxHeap[indx];
            maxHeap[indx] = maxHeap[lChildIndx];
            maxHeap[lChildIndx] = tmp;
        } 
        
        if(rChildIndx < maxHeapLen && maxHeap[indx] <= maxHeap[rChildIndx]) {
            tmp = maxHeap[indx];
            maxHeap[indx] = maxHeap[rChildIndx];
            maxHeap[rChildIndx] = tmp;
        }
    }
}

void minHeapify(void) {
    if(minHeap == NULL || minHeapLen == 0)
        return;
    
    int lChildIndx, rChildIndx;
    
    for(int indx = minHeapLen/2 + 1; indx >= 0; indx--) {
        lChildIndx = getLeftChildIndex(indx);
        rChildIndx = getRightChildIndex(indx);
        int tmp;
        
        if(lChildIndx < minHeapLen && minHeap[indx] >= minHeap[lChildIndx]) {
            tmp = minHeap[indx];
            minHeap[indx] = minHeap[lChildIndx];
            minHeap[lChildIndx] = tmp;
        } 
        
        if(rChildIndx < minHeapLen && minHeap[indx] >= minHeap[rChildIndx]) {
            tmp = minHeap[indx];
            minHeap[indx] = minHeap[rChildIndx];
            minHeap[rChildIndx] = tmp;
        }
    }
}

//extracts the root from the heap and runs heapify
int extractMax(void) {
    if(maxHeap == NULL || maxHeapLen == 0)
        return -1;
    
    int max = maxHeap[0];
    maxHeap[0] = maxHeap[maxHeapLen - 1];
    maxHeapLen -= 1;
    maxHeapify();
    
    return max;
}

int extractMin(void) {
    if(minHeap == NULL || minHeapLen == 0)
        return -1;
    
    int min = minHeap[0];
    minHeap[0] = minHeap[minHeapLen - 1];
    minHeapLen -= 1;
    minHeapify();
    
    return min;
}

//inserts new data element to the heaps and runs heapify
void insertMaxHeap(int data) {
    maxHeap[maxHeapLen] = data;
    maxHeapLen += 1;
    maxHeapify();
}

void insertMinHeap(int data) {
    minHeap[minHeapLen] = data;
    minHeapLen += 1;
    minHeapify();
}

//generates median after receiving data element from steam
void genMedian(int num) {
 if(num >= median) {
     insertMinHeap(num);
    } else {
  insertMaxHeap(num);
    }
       
    if(abs(maxHeapLen - minHeapLen) >= 2) {
  if(maxHeapLen > minHeapLen)
   insertMinHeap(extractMax());
  else
   insertMaxHeap(extractMin());       
 }
       
 if(minHeapLen > maxHeapLen) {
        median = minHeap[0];
    } else if(minHeapLen < maxHeapLen) {
     median = maxHeap[0];
    } else {
        median = (maxHeap[0] + minHeap[0])/2.0;
    }
}

The above gprof results shows that getLeftChildIndex() and getRightChildIndex() functions are called the most. These function calls can be optimized by inline-ing as follows.
int getLeftChildIndex(int) __attribute__((always_inline));
int getRightChildIndex(int) __attribute__((always_inline));

//pointers to array which hold maxHeap and minHeap
int* maxHeap;
int* minHeap;
//length of the arrays
int maxHeapLen = 0, minHeapLen = 0;
//median
float median;

int inline getLeftChildIndex(int cIndx) {
    cIndx += 1;
    return (2 * cIndx - 1);
}

int inline getRightChildIndex(int cIndx) {
    cIndx += 1;
    return (2 * cIndx);
}

Inline-ing reduces the execution time by almost 4.5 secs.

The maxHeapify() and minHeapify() functions still taking most of the program execution time which are being called more than 150k times.

Median calculation depends on
  1. The maximum data of left half and minimum data of right half of the sorted series and
  2. If the left half and right half must be balanced (the length of left and right half should not exceed more than 1) if the length of one half exceeds that of another by 1
So, the heapify operations need not be called every time a new data elements arrives from stream if, the above conditions are met.
//generates median after receiving data element from steam
void genMedian(int num) {
 if(num >= median) {
  if(minHeapLen > 0 && num < minHeap[0]) {
   int tmp = minHeap[0];
   minHeap[0] = num;
   minHeap[minHeapLen] = tmp;
   minHeapLen += 1;
  } else {
   minHeap[minHeapLen] = num;
   minHeapLen += 1;
  }
    } else {
  if(maxHeapLen > 0 && num > maxHeap[0]) {
   int tmp = maxHeap[0];
   maxHeap[0] = num;
   maxHeap[maxHeapLen] = tmp;
   maxHeapLen += 1;
  } else {
   maxHeap[maxHeapLen] = num;
   maxHeapLen += 1;
  }
    }
       
    if(abs(maxHeapLen - minHeapLen) >= 2) {
  if(maxHeapLen > minHeapLen)
   insertMinHeap(extractMax());
  else
   insertMaxHeap(extractMin());       
 }
       
 if(minHeapLen > maxHeapLen) {
        median = minHeap[0];
    } else if(minHeapLen < maxHeapLen) {
     median = maxHeap[0];
    } else {
        median = (maxHeap[0] + minHeap[0])/2.0;
    }
}


The above optimization reduced the call to heapify functions by half and the execution time reduces to almost 4.5 secs.


References
  1. http://www.geeksforgeeks.org/median-of-stream-of-integers-running-integers/
  2. http://algorithmsandme.in/2014/08/heaps-find-median-of-stream-of-integers/
  3. http://www.ardendertat.com/2011/11/03/programming-interview-questions-13-median-of-integer-stream/

Saturday, November 21, 2015

Linked List Interview Questions



  1. How do you reverse a singly linked list? How do you reverse a doubly linked list? Write a C program to do the same
  2. Given only a pointer to a node to be deleted in a singly linked list, how do you delete it?
  3. How do you sort a linked list? Write a C program to sort a linked list.
  4. How to declare a structure of a linked ist?
  5. Write a C program to implement a Generic Linked list.
  6. How do you reverse a linked list without using any C pointers?
  7. How would you detect a loop in a linked list? Write a C program to detect a loop in a linked list.
  8. How do you find the middle of a linked list? Write a C program to return the middle of a linked list.
  9. If you are using C language to implement the heterogeneous linked list, what pointer type will you use?
  10. How to compare two linked lists? Write a C program to compare two linked lists.
  11. How to create a copy of a linked list? Write a C program to create a copy of a linked list.
  12. Write a C program to free the nodes of a linked list.
  13. Can we do a Binary search on a linked list?
  14. Write a C program to return the nth node from the end of a linked list.
  15. How would you find out if one of the pointers in a linked list is corrupted or not?
  16. Write a C program to insert nodes into a linked list in a sorted fashion.
  17. Write a C program to remove duplicates from a sorted linked list.
  18. How to read a singly linked list backwards?
  19. How can I search for data in a linked list?
  20. What is the difference between a linked list and Array?
  21. Implement a linked list. Why did you pick the method you did?
  22. Implement an algorithm to sort a linked list. Why did you pick the method you did? Now, do it in O(n) time.
  23. Given two sorted linked lists, write a function to merge them into one.
  24. Delete an element from a doubly linked list.
  25. Find the nth node from the end of a singly link list in a single pass
  26. Write a program to swap nodes in a linked list without swapping the data.

Wednesday, November 18, 2015

[C] Find next lexicographically greater string

Given a word w, rearrange the letters of w to construct another word s in such a way that s is lexicographically greater than w. In the case of multiple possible answers, find the lexicographically smallest one among them.

Example - Let the given word is 'lgeuvf', then the next lexicographically greater is 'lgevfu'. In the case of the word 'ywwwsqonmkjjjec', there is no greater word since it is already the greatest word of the given combination. 

While finding the next greater word, we try to permute the given combination such that there is minimal change and the resulting word is closest to the original word. Find the right-most non-increasing longest (say RNL) sub-string. In 'lgeuvf', 'vf' is the RNL sub-string. However, in 'ywwwsqonmkjjjec' the entire string is the RNL sub-string. Such sub-string is the greatest lexicographical combination and there is no greater string. We mark the character left to the sub-string and call it pivot. The character 'u' is the pivot in 'lgeuvf. Note, 'u' less than 'v'.

Now, we find the right-most character in RNL sub-string which is greater than the pivot. Let's call this RGC. The character 'v' is RGC in above example string. We get the next lexicographically greater word, by swapping the RGC & the pivot and sorting the modified RNL. After swapping RGC & pivot in 'lgeuvf', we get 'lgevuf'. And sorting the modified RNL (which is 'vf'), we get 'lgevfu'.

Following is the C implementation of described algorithm.

#include <stdio.h>;
#include <string.h>;
#include <math.h>;
#include <stdlib.h>;
 
#define NO_ANS "no answer"
#define BUF_SIZE 501
 
int findPivot(char* iStr);
int getModifiedRNL(char* iStr, char);
void swap(char* a, char* b);
char* strPermute(char* iStr);
void quickSort(char* iStr);
void quickSortItr(char* iStr, int start, int end);
 
char* testip[] = {"mqyvczrlabtesyeiteblqklfhkchcryggkewpsfxsumvsjerssbltntydzwrjvf",
"pzxgfnsapnchz",
"erwidqokyjfpctpfxuojyloafghxgifdvhcmzjogoqoikjhjngbhfetvtraaojkfqvyujbhdizrkvqmfpzbidysbkhvuebtr",
"zedawdvyyfumwpupuinbdbfndyehircmylbaowuptgmw",
"zyyxwwtrrnmlggfeb",
"zzzyyyyxxxxwwwwwvvuuuuuuuttttsssrrrqqqqpppooooonnnnmmmllkjjjjiiiiihhhgggfeeeddcccbbbaa",
"lgeuvf",
"ywwwsqonmkjjjec",
"cfvhmxuuvzeycgzltorcfbpqtejfubfpkyqfrugixsvmnyizmzotttyriqpjdwbyoggjgbo",
"zssfzbdeamejrtmqgpywlwwulxerrftkxlvzffztvmfraygtkoeyyitiqgonknchdccjxfqsdgpduuhxatmkdlbww",
"dqwrmse"};
 
char* testop[] = {"mqyvczrlabtesyeiteblqklfhkchcryggkewpsfxsumvsjerssbltntydzwrvfj",
"pzxgfnsapnczh",
"erwidqokyjfpctpfxuojyloafghxgifdvhcmzjogoqoikjhjngbhfetvtraaojkfqvyujbhdizrkvqmfpzbidysbkhvuerbt",
"zedawdvyyfumwpupuinbdbfndyehircmylbaowuptgwm",
"no answer",
"no answer",
"lgevfu",
"no answer",
"cfvhmxuuvzeycgzltorcfbpqtejfubfpkyqfrugixsvmnyizmzotttyriqpjdwbyoggjgob",
"zssfzbdeamejrtmqgpywlwwulxerrftkxlvzffztvmfraygtkoeyyitiqgonknchdccjxfqsdgpduuhxatmkdlwbw",
"dqwrsem"
};
 
 
int main() {
    int N = 11;
 
    for(int indx = 0; indx < N; indx++) {
 
        char* oStr = strPermute(testip[indx]);
  printf("test case %d: ", indx + 1);
  if(strcmp(oStr, testop[indx]) != 0) {
   printf("FAILntinput: %s ntoutput: %sn", testip[indx], oStr);
  } else
   printf("PASSntinput: %s ntoutput: %sn", testip[indx], oStr);
        free(oStr);
 
    }
 
    return 0;
}
 
char* strPermute(char* iStr) {
    char *oStr = NULL;
     
    int fCharIndex = findPivot(iStr);
    if(fCharIndex == -1) {
        oStr = (char*) calloc(strlen(NO_ANS) + 1, sizeof(char));
        memcpy(oStr, NO_ANS, strlen(NO_ANS));
        return oStr;
    }
     
    int sCharIndex = getModifiedRNL(iStr + fCharIndex + 1, iStr[fCharIndex]);
    if(sCharIndex == -1) {
        oStr = (char*) calloc(strlen(NO_ANS) + 1, sizeof(char));
        memcpy(oStr, NO_ANS, strlen(NO_ANS));
        return oStr;
    }
     
    oStr = (char*) calloc(strlen(iStr) + 1, sizeof(char));
    memcpy(oStr, iStr, strlen(iStr));
    swap(oStr + fCharIndex, oStr + fCharIndex + 1 + sCharIndex);
    quickSort(oStr + fCharIndex + 1);
 if(strcmp(iStr, oStr) == 0) {
        memcpy(oStr, NO_ANS, strlen(NO_ANS)+1);
        return oStr;
    }
     
    return oStr;
}
 
int findPivot(char* iStr) {
    if(iStr == NULL || strlen(iStr) == 1)
        return -1;
     
    int isLen = strlen(iStr);
    int indx = isLen - 2;
 while(indx >;= 0 &amp;&amp; iStr[indx] >;= iStr[indx + 1])
  indx--;
 
    return indx;
}
 
int getModifiedRNL(char* iStr, char fChar) {
 int iLen = strlen(iStr);
 if(iLen == 1)
  return 0;
     
    int indx = iLen - 1;
    while(indx >;= 0 &amp;&amp; fChar >;= iStr[indx]) {
  indx--;
    }
 
 return indx;
}
 
void quickSort(char* iStr) {
    quickSortItr(iStr, 0, strlen(iStr) - 1);
}
 
void quickSortItr(char* iStr, int start, int end) {
    if(start >;= end)
        return;
     
    int indx = 0, pIndx = 0;
    while(indx < end) {
        if(iStr[indx] <= iStr[end]) {
            swap(iStr + indx, iStr + pIndx);
            pIndx++;
        }
        indx++;
    }
    swap(iStr + pIndx, iStr + end);
     
    quickSortItr(iStr, start, pIndx - 1);
    quickSortItr(iStr, pIndx + 1, end);
}
 
void swap(char* a, char* b){
    char tmp = *a;
    *a = *b;
    *b = tmp;
}
Compilation on Ubuntu:
   gcc -std=gnu99 strPermute.c -o strPermute 
Output for the test cases.
test case 1: PASS
 input: mqyvczrlabtesyeiteblqklfhkchcryggkewpsfxsumvsjerssbltntydzwrjvf 
 output: mqyvczrlabtesyeiteblqklfhkchcryggkewpsfxsumvsjerssbltntydzwrvfj
test case 2: PASS
 input: pzxgfnsapnchz 
 output: pzxgfnsapnczh
test case 3: PASS
 input: erwidqokyjfpctpfxuojyloafghxgifdvhcmzjogoqoikjhjngbhfetvtraaojkfqvyujbhdizrkvqmfpzbidysbkhvuebtr 
 output: erwidqokyjfpctpfxuojyloafghxgifdvhcmzjogoqoikjhjngbhfetvtraaojkfqvyujbhdizrkvqmfpzbidysbkhvuerbt
test case 4: PASS
 input: zedawdvyyfumwpupuinbdbfndyehircmylbaowuptgmw 
 output: zedawdvyyfumwpupuinbdbfndyehircmylbaowuptgwm
test case 5: PASS
 input: zyyxwwtrrnmlggfeb 
 output: no answer
test case 6: PASS
 input: zzzyyyyxxxxwwwwwvvuuuuuuuttttsssrrrqqqqpppooooonnnnmmmllkjjjjiiiiihhhgggfeeeddcccbbbaa 
 output: no answer
test case 7: PASS
 input: lgeuvf 
 output: lgevfu
test case 8: PASS
 input: ywwwsqonmkjjjec 
 output: no answer
test case 9: PASS
 input: cfvhmxuuvzeycgzltorcfbpqtejfubfpkyqfrugixsvmnyizmzotttyriqpjdwbyoggjgbo 
 output: cfvhmxuuvzeycgzltorcfbpqtejfubfpkyqfrugixsvmnyizmzotttyriqpjdwbyoggjgob
test case 10: PASS
 input: zssfzbdeamejrtmqgpywlwwulxerrftkxlvzffztvmfraygtkoeyyitiqgonknchdccjxfqsdgpduuhxatmkdlbww 
 output: zssfzbdeamejrtmqgpywlwwulxerrftkxlvzffztvmfraygtkoeyyitiqgonknchdccjxfqsdgpduuhxatmkdlwbw
test case 11: PASS
 input: dqwrmse 
 output: dqwrsem

Saturday, November 14, 2015

The "Clockwise/Spiral Rule'' By David Anderson

There is a technique known as the  "Clockwise/Spiral Rule'' which enables any C programmer to parse any C declaration!

There are three simple steps to follow:
  1. Starting with the unknown element, move in a spiral/clockwise direction; when encountering the following elements replace them with the corresponding english statements:
    1. [X] or []: Array X size of... or Array undefined size of...
    2. (type1, type2): function passing type1 and type2 returning...
    3. *: pointer(s) to...
  2. Keep doing this in a spiral/clockwise direction until all tokens have been covered.
  3. Always resolve anything in parenthesis first!
Example #1: Simple declaration


  1. What is str? "str is an...
  2. We move in a spiral clockwise direction starting with 'str' and the first character we see is a '[' so, that means we have an array, so..."str is an array 10 of...
  3. Continue in a spiral clockwise direction, and the next thing we encounter is the '*' so, that means we have pointers, so..."str is an array 10 of pointers to...
  4. Continue in a spiral direction and we see the end of the line (the ';'), so keep going and we get to the type 'char', so..."str is an array 10 of pointers to char''
  5. We have now "visited'' every token; therefore we are done!

Example #2: Pointer to Function declaration

  1. What is fp? "fp is a...
  2. Moving in a spiral clockwise direction, the first thing we see is a `)'; therefore, fp is inside parenthesis, so we continue the spiral inside the parenthesis and the next character seen is the `*', so..."fp is a pointer to...
  3. We are now out of the parenthesis and continuing in a spiral clockwise direction, we see the '('; therefore, we have a function, so..."fp is a pointer to a function passing an int and a pointer to float returning...
  4. Continuing in a spiral fashion, we then see the '*' character, so..."fp is a pointer to a function passing an int and a pointer to float returning a pointer to...
  5. Continuing in a spiral fashion we see the ';', but we haven't visited all tokens, so we continue and finally get to the type 'char', so..."fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char"
Example #3: The "Ultimate"


  1. What is 'signal'? Notice that signal is inside parenthesis, so we must resolve this first!
  2. Moving in a clockwise direction we see '(' so we have..."signal is a function passing an int and a...
  3. Hmmm, we can use this same rule on 'fp', so... What is fp? fp is also inside parenthesis so continuing we see an '*', so..."fp is a pointer to...
  4. Continue in a spiral clockwise direction and we get to '(', so..."fp is a pointer to a function passing int returning...''
  5. Now we continue out of the function parenthesis and we see void, so... "fp is a pointer to a function passing int returning nothing (void)''
  6. We have finished with fp so let's catch up with 'signal', we now have... "signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning...
  7. We are still inside parenthesis so the next character seen is a '*', so... "signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to...
  8. We have now resolved the items within parenthesis, so continuing clockwise, we then see another '(', so..."signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning...
  9. Finally we continue and the only thing left is the word 'void', so the final complete definition for signal is: "signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning nothing (void)"

[C] Precedence & Associativity

Precedence determines the order of the operators to be evaluated in an expression with more than one operators. Associativity defines the order of the operators to be evaluated when an expression contains more than one operator of the same precedence.

Precedence and Associativity determine the order of evaluation of sub-expression when the order of evaluation is not defined with brackets.