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.


Monday, May 31, 2010

Storage class

In C, storage class gives two information about an object (variable or function).
  1. Scope of an object - gives information on visibility of a variable or function.
  2. Memory allocation - determines the part of memory where storage is allocated for an object and life of that object.
Storage class:
  • auto
  • extern
  • static
  • register
Automatic variable - Any variable defined inside a program block or nested block, by default, has automatic storage class. Scope of such variable is limited to the block where they are defined. These variables are also referred as local variable. These variables should be initialized unless the value is undefined.


External variable - These variables are also called global variable. These variables remain in life throughout the execution of a program. Memory allocated for every byte of extern variable is initialized to zero. The keyword extern can be omitted for a variable that has scope of file. But it is must if the variable is used across several source files. So usually, deceleration and definition is associated with such variables.


Static variable/function - In case of variables, static defines lifetime but for functions it defines scope. As for extern/global variable, static variables are initialized to zero. Automatic initialization can be overridden explicitly by programmer. However, the initializer must be a constant expression. Static variable defined inside a program block has the same scope as that of automatic variable but the storage allocation remains in existence until program terminates.


Register variable - A programmer may instruct the compiler to allocate a register in CPU for a variable. However, a register variable may or may not be allocated CPU register at runtime. This keyword gives flexibility to a programmer to control the efficiency of a program to some extent. Generally, variables which are accessed repeatedly or whose access time are critical may be declared to be of storage class register. Interestingly, this is the only storage class that can be defined for function parameter.

Some interesting observation.
  1. A register variable must have to be defined within a block or it can also be declared as a function parameter.
  2. In C, pointers cannot reference a register variable. But this allowed in C++.
    register int myVar = 0;int* myVarPtr = &myVar;  /* NOT allowed */
    
  3. Register storage class can not be defined for a global variable.
  4. A register variable has the same life and scope as that of automatic variable.
  5. These are vaild.
    register float myFlt;
    register char myChar;
    register int* myIntPtr;
    register double* myDobPtr;
    register float* myFltPtr;
    register char* myChrPtr;
    
  6. This is also valid.
    int main(register int argc, char* argv[])
    {
        ....
        ....
        return 0;
    }

How about these?
register int main(int argc, char* argv[])
{
   ....
   ....
   return 0;      
}
register int func1(int aa, char cc)
{
   ....
   ....
   return 0;      
}
int func2(int aa, char cc)
{
   static register int myInt = 0;
   ....
   return 0;      
}

C Questions

As a C programmer you would like to give some thought to following C question.

  1. Can structures be passed to the functions by value?
  2. Why cannot arrays be passed by values to functions?
  3. What are advantages and disadvantages of using macro and inline functions?
  4. What happens when recursion functions are declared inline?
  5. What is scope of static variables?
  6. What is the output of printf("\nab\bcd\ref"); C statement?
  7. #define cat(x,y) x##y concatenates x to y. But cat(cat(1,2),3) does not expand but gives preprocessor warning. Why?
  8. Is it possible to define a constant volatile variable? 
  9. Is it possible to define a volatile pointer?
  10. What does ++*ip increments?
  11. Describe an operation involving unsigned and signed.
  12. a+++b;
  13. Is this C statement valid? malloc(sizeof(0))
  14. main() {fork();fork();fork();printf("hello world"); }
  15. what is void (*fptr[10])()?
  16. Which way of writing infinite loops is more efficient than others?
  17. # error — what it does? 
  18. How is function itoa() written?
  19. How to know whether system uses big endian or little endian format and how to convert among them?
  20. What is forward reference w.r.t. pointers in c?
  21. How is generic list manipulation function written which accepts elements of any kind?
  22. How can you define a structure with bit field members?
  23. How do you write a function which takes 2 arguments - a byte and a field in the byte and returns the value of the field in that byte?
  24. What are the different storage classes in C?
  25. What are the different qualifiers in C?
  26. What is void pointer and what is its use?
  27. What is lvalue and rvalue?
  28. Using a variable define these -
    1. An integer
    2. A pointer to integer
    3. A pointer to a pointer integer
    4. An array of 10 integer
    5. An array of 10 pointer to integer
    6. A pointer to an array of 10 integer
    7. A pointer to a function that takes an integer as an argument and returns an integer
    8. An array of 10 pointer to function that take an integer and return an integer
  29. What do the following declarations mean?
    1. const int a;
    2. int const a;
    3. const int *a;
    4. int * const a;
    5. int const* a const;
  30. Is 3[myIntArr] = 5; valid where myIntArr is an array of 10 integers?

Monday, May 24, 2010

Const & Volatile

Const and Volatile are not opposite of each other!

Const - A variable whose value can not be changed, that is a constant. A programmer can not change the value of a variable declared as constant later in program. If it is not initialized at deceleration, it can not be assigned/initialized later.

An integer constant can be defined as:

const int myConst = 10;
int const myConst = 10;

Both the declaration have the same meaning. But in case of pointers, things are different.

const int *myPtr = (int *)0xFFFFFF04;     /* 1 */
int const *myPtr = (int *)0xFFFFFF05;     /* 2 */
int* const myPtr = (int *)0xFFFFFF06;     /* 3 */

Declaration 1 & 2 are the same and indicates the myPtr is an ordinary integer pointer and the integer pointed by it can not be modified. As a programmer, I can modify myPtr as:

int anInt = 10;
myPtr = &anInt;

But I can not do:

*myPtr = anInt;

However, the deceleration 3 defines a pointer myPtr that can not be modified but the value pointer by it can be modified.


Const, actually volatile also, variables are useful in real-time C programs. A const variable may never be initialized. An use case of this can be a the address of memory mapped I/O which is read only.

Volatile - Linux for you and Netrino articles have clearly explained volatile keyword. So, I will just be summarizing it here.

When a programmer declares a variable volatile, (s)he informs the compiler that the variable at any time during the life of program can change its value, so be careful while optimizing the code. In reference to the example of memory mapped I/O, I would define a pointer holding the address as a const variable but the value pointed by as volatile.

volatile int* const memIO = 0xFFFFFF05;

Some more declerations.

int volatile alcohol;
volatile int alcohol;            /* are the same - alcohol is volatile */

Now the pointer and volatile.

volatile int *myPtr;                    /* ordinary integer pointer to volatile integer data*/
int* volatile myPtr;                    /* volatile integer pointer to usual integer data*/
volatile int* volatile myPtr;       /* volatile integer pointer to volatile integer data*/ 


Now do NOT confuse in an interview.

Usage of volatile variable (as pointer in Netrino article)
  • Memory-mapped peripheral registers
  • Global variables modified by an interrupt service routine
  • Global variables accessed by multiple tasks within a multi-threaded application
What does volatile long * const timer = 0x0000ABCD mean?

Have fun!

Friday, May 21, 2010

Naming core dump file

Linux Kernel 2.6 provides user an option to name the core dump file. User can define template in file /proc/sys/kernel/core_pattern for naming the core dump file. The template contains % specifiers that get substituted when core dump file is generated.
  • %% a single % character
  • %p PID of dumped process
  • %u (numeric) real UID of dumped process
  • %g (numeric) real GID of dumped process
  • %s number of signal causing dump
  • %t time of dump, expressed as seconds since the Epoch (00:00h, 1 Jan 1970, UTC)
  • %h hostname (same as nodename returned by uname(2))
  • %e executable filename (without path prefix)
  • %c core file size soft resource limit of crashing process (since Linux 2.6.24)
Example:
I want my core dump filename look something like this signal-no_pid_exe-name_timestamp.core. On Ubuntu machine:

userOne@shangri-la:~/myTests/coredump$ su
root@shangri-la:/home/userOne/myTests/coredump# echo '%s_%p_%e_%t.core' > /proc/sys/kernel/core_pattern
root@shangri-la:/home/userOne/myTests/coredump# exit
userOne@shangri-la:~/myTests/coredump$ cat /proc/sys/kernel/core_pattern
%s_%p_%e_%t.core

After running the culprit program coredump, I got
11_12945_coredump_1274446084.core file.

Simple and nice!