0% found this document useful (0 votes)
207 views57 pages

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

The document discusses different methods for reversing and sorting linked lists in C. It provides code examples for: 1. Reversing a singly linked list iteratively and recursively. 2. Reversing a doubly linked list by swapping the next and prev pointers. 3. Sorting a singly linked list using bubble sort by swapping nodes out of order. 4. Sorting a singly linked list using merge sort recursively by dividing the list in half and merging the sorted halves.
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF or read online on Scribd
Download as doc or pdf
0% found this document useful (0 votes)
207 views57 pages

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

The document discusses different methods for reversing and sorting linked lists in C. It provides code examples for: 1. Reversing a singly linked list iteratively and recursively. 2. Reversing a doubly linked list by swapping the next and prev pointers. 3. Sorting a singly linked list using bubble sort by swapping nodes out of order. 4. Sorting a singly linked list using merge sort recursively by dividing the list in half and merging the sorted halves.
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOC, PDF or read online on Scribd
Download as doc or pdf
Download as doc or pdf
You are on page 1/ 57

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.

This is THE most frequently asked interview question. The most!.


Singly linked lists
Here are a few C programs to reverse a singly linked list.
Method1 (Iterative)

#include <stdio.h>

// Variables
typedef struct node
{
int value;
struct node *next;
}mynode;

// Globals (not required, though).


mynode *head, *tail, *temp;

// Functions
void add(int value);
void iterative_reverse();
void print_list();

// The main() function


int main()
{
head=(mynode *)0;

// Construct the linked list.


add(1);
add(2);
add(3);

//Print it
print_list();

// Reverse it.
iterative_reverse();

//Print it again
print_list();

return(0);
}
// The reverse function
void iterative_reverse()
{
mynode *p, *q, *r;

if(head == (mynode *)0)


{
return;
}

p = head;
q = p->next;
p->next = (mynode *)0;

while (q != (mynode *)0)


{
r = q->next;
q->next = p;
p = q;
q = r;
}

head = p;
}

// Function to add new nodes to the linked list


void add(int value)
{
temp = (mynode *) malloc(sizeof(struct node));
temp->next=(mynode *)0;
temp->value=value;

if(head==(mynode *)0)
{
head=temp;
tail=temp;
}
else
{
tail->next=temp;
tail=temp;
}
}

// Function to print the linked list.


void print_list()
{
printf("\n\n");
for(temp=head; temp!=(mynode *)0; temp=temp->next)
{
printf("[%d]->",(temp->value));
}
printf("[NULL]\n\n");
}

Method2 (Recursive, without using any temporary variable)

#include <stdio.h>
// Variables
typedef struct node
{
int value;
struct node *next;
}mynode;

// Globals.
mynode *head, *tail, *temp;

// Functions
void add(int value);
mynode* reverse_recurse(mynode *root);
void print_list();

// The main() function


int main()
{
head=(mynode *)0;

// Construct the linked list.


add(1);
add(2);
add(3);

//Print it
print_list();

// Reverse it.
if(head != (mynode *)0)
{
temp = reverse_recurse(head);
temp->next = (mynode *)0;
}

//Print it again
print_list();

return(0);
}

// Reverse the linked list recursively


//
// This function uses the power of the stack to make this
// *magical* assignment
//
// node->next->next=node;
//
// :)

mynode* reverse_recurse(mynode *root)


{
if(root->next!=(mynode *)0)
{
reverse_recurse(root->next);
root->next->next=root;
return(root);
}
else
{
head=root;
}
}

// Function to add new nodes to the linked list.


void add(int value)
{
temp = (mynode *) malloc(sizeof(struct node));
temp->next=(mynode *)0;
temp->value=value;

if(head==(mynode *)0)
{
head=temp;
tail=temp;
}
else
{
tail->next=temp;
tail=temp;
}
}

// Function to print the linked list.


void print_list()
{
printf("\n\n");
for(temp=head; temp!=(mynode *)0; temp=temp->next)
{
printf("[%d]->",(temp->value));
}
printf("[NULL]\n\n");
}

Method3 (Recursive, but without ANY global variables. Slightly messy!)

#include <stdio.h>
// Variables
typedef struct node
{
int value;
struct node *next;
}mynode;

// Functions
void add(mynode **head, mynode **tail, int value);
mynode* reverse_recurse(mynode *current, mynode *next);
void print_list(mynode *);

int main()
{
mynode *head, *tail;
head=(mynode *)0;

// Construct the linked list.


add(&head, &tail, 1);
add(&head, &tail, 2);
add(&head, &tail, 3);

//Print it
print_list(head);

// Reverse it.
head = reverse_recurse(head, (mynode *)0);
//Print it again
print_list(head);

getch();
return(0);
}

// Reverse the linked list recursively


mynode* reverse_recurse(mynode *current, mynode *next)
{
mynode *ret;

if(current==(mynode *)0)
{
return((mynode *)0);
}

ret = (mynode *)0;


if (current->next != (mynode *)0)
{
ret = reverse_recurse(current->next, current);
}
else
{
ret = current;
}

current->next = next;
return ret;
}

// Function to add new nodes to the linked list.


// Takes pointers to pointers to maintain the
// *actual* head and tail pointers (which are local to main()).

void add(mynode **head, mynode **tail, int value)


{
mynode *temp1, *temp2;

temp1 = (mynode *) malloc(sizeof(struct node));


temp1->next=(mynode *)0;
temp1->value=value;

if(*head==(mynode *)0)
{
*head=temp1;
*tail=temp1;
}
else
{
for(temp2 = *head; temp2->next!= (mynode *)0; temp2=temp2->next);
temp2->next = temp1;
*tail=temp1;
}
}

// Function to print the linked list.


void print_list(mynode *head)
{
mynode *temp;
printf("\n\n");
for(temp=head; temp!=(mynode *)0; temp=temp->next)
{
printf("[%d]->",(temp->value));
}
printf("[NULL]\n\n");
}

Doubly linked lists

This is really easy, just keep swapping the prev and next pointers and at the end swap the
head and the tail:)

#include<stdio.h>
#include<ctype.h>

typedef struct node


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

mynode *head, *tail;


void add_node(int value);
void print_list();
void reverse();

int main()
{
head=NULL;
tail=NULL;
add_node(1);
add_node(2);
add_node(3);
add_node(4);
add_node(5);

print_list();
reverse();
print_list();
return(1);

void add_node(int value)


{
mynode *temp, *cur;

temp = (mynode *)malloc(sizeof(mynode));


temp->next=NULL;
temp->prev=NULL;

if(head == NULL)
{
printf("\nAdding a head pointer\n");
head=temp;
tail=temp;
temp->value=value;
}
else
{
for(cur=head;cur->next!=NULL;cur=cur->next);
cur->next=temp;
temp->prev=cur;
temp->value=value;
tail=temp;
}
}

void print_list()
{
mynode *temp;

printf("\n--------------------------------\n");
for(temp=head;temp!=NULL;temp=temp->next)
{
printf("\n[%d]\n",temp->value);
}
}

void reverse()
{
mynode *cur, *temp, *save_next;
if(head==tail)return;
if(head==NULL || tail==NULL)
return;
for(cur=head;cur!=NULL;)
{
printf("\ncur->value : [%d]\n",cur->value);
temp=cur->next;
save_next=cur->next;
cur->next=cur->prev;
cur->prev=temp;
cur=save_next;
}
temp=head;
head=tail;
tail=temp;
}

3.How do you sort a linked list? Write a C program to sort a linked list.

Method1 (Usual method)

The general idea is to decide upon a sorting algorithm (say bubble sort). Then, one needs
to come up with different scenarios to swap two nodes in the linked list when they are not
in the required order. The different scenarios would be something like

1. When the nodes being compared are not adjacent and one of them is the first node.
2. When the nodes being compared are not adjacent and none of them is the first node
3. When the nodes being compared are adjacent and one of them is the first node.
4. When the nodes being compared are adjacent and none of them is the first node.

One example bubble sort for a linked list goes like this

for(i = 1; i < n; i++)


{
p1 = head;
p2 = head->next;
p3 = p2->next;
for(j = 1; j <= (n - i); j++)
{
if(p2->value < p3->value)
{
p2->next = p3->next;
p3->next = p2;
p1->next = p3;
p1 = p3;
p3 = p2->next;
}
else
{
p1 = p2;
p2 = p3;
p3 = p3->next;
}
}
}

As you can see, the code becomes quite messy because of the pointer logic. Thats why I
have not elaborated too much on the code, nor on variations such as soring a doubly
linked list. You have to do it yourself once to understand it.

Method1 (Divide and Conquer using merge sort)

The pseudocode for this method is

typedef struct node


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

mynode *head, *tail;


int size;

mynode *mergesort(mynode *list, int size);


void display(mynode *list);

mynode *mergesort(mynode *list, int size)


{
int size1, size2;
mynode *tempnode1, *tempnode2, *tempnode3;

if( size<=2 )
{
if(size==1)
{
// Nothing to sort!
return(list);
}
else
{
if(list->value < list->next->value
{
// These 2 nodes are already in right order, no need to sort
return(list);
}
else
{
// Need to swap these 2 nodes
/* Here we have 2 nodes
*
*node 1 -> node2 -> NULL
*
* This should be converted to
*
* node2 -> node1 -> NULL
*
*/
tempnode1 = list;
tempnode2 = list->next;
tempnode2->next = tempnode1;
tempnode1->next = NULL;
return(tempnode2);
}
}
}
else
{
// The size of the linked list is more than 2.
// Need to split this linked list, sort the
// left and right sub-linked lists and merge.
// Split.
// tempnode1 will have the first half of the linked list of size "size1".
// tempnode2 will have the second half of the linked list of size "size2".

<CODE TO SPLIT THE LINKED LIST INTO TWO>


// Sort the two halves recursively
tempnode1 = mergesort(tempnode1, size1);
tempnode2 = mergesort(tempnode2, size2);
// Now merge the sorted lists back, let tempnode3 point to that new list.

<CODE TO MERGE THE 2 LINKED LISTS BACK INTO A SINGLE


SORTED LINKED LIST>

return(tempnode3);
}
}

The code to merge the two already sorted sub-linked lists into a sorted linked list could be
something like this..

mynode * merge(mynode *a, mynode *b)


{
mynode *i, *j, *k, *c;

i = a;
j = b;
c = getNewNode();
k = getNewNode();

while(i != NULL && j != NULL)


{
if( i -> value < j -> value )
{
k -> next = i;
i = i -> next;
}
else
{
k -> next = j;
j = j -> next;
}
}

if( i != NULL)
k -> next = i ;
else
k -> next = j;

return( c -> next );

5.Write a C program to implement a Generic Linked List.


Here is a C program which implements a generic linked list. This is also one of the very
popular interview questions thrown around. The crux of the solution is to use the void C
pointer to make it generic. Also notice how we use function pointers to pass the address
of different functions to print the different generic data.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct list


{
void *data;
struct list *next;
} List;

struct check
{
int i;
char c;
double d;
}chk[] = { { 1, 'a', 1.1 },{ 2, 'b', 2.2 }, { 3, 'c', 3.3 } };

void insert(List **, void *, unsigned int);


void print(List *, void (*)(void *));
void printstr(void *);
void printint(void *);
void printchar(void *);
void printcomp(void *);

List *list1, *list2, *list3, *list4;

int main(void)
{
char c[] = { 'a', 'b', 'c', 'd' };
int i[] = { 1, 2, 3, 4 };
char *str[] = { "hello1", "hello2", "hello3", "hello4" };

list1 = list2 = list3 = list4 = NULL;

insert(&list1, &c[0], sizeof(char));


insert(&list1, &c[1], sizeof(char));
insert(&list1, &c[2], sizeof(char));
insert(&list1, &c[3], sizeof(char));

insert(&list2, &i[0], sizeof(int));


insert(&list2, &i[1], sizeof(int));
insert(&list2, &i[2], sizeof(int));
insert(&list2, &i[3], sizeof(int));

insert(&list3, str[0], strlen(str[0])+1);


insert(&list3, str[1], strlen(str[0])+1);
insert(&list3, str[2], strlen(str[0])+1);
insert(&list3, str[3], strlen(str[0])+1);

insert(&list4, &chk[0], sizeof chk[0]);


insert(&list4, &chk[1], sizeof chk[1]);
insert(&list4, &chk[2], sizeof chk[2]);

printf("Printing characters:");
print(list1, printchar);
printf(" : done\n\n");

printf("Printing integers:");
print(list2, printint);
printf(" : done\n\n");

printf("Printing strings:");
print(list3, printstr);
printf(" : done\n\n");

printf("Printing composite:");
print(list4, printcomp);
printf(" : done\n");

return 0;
}

void insert( List **p, void *data, unsigned int n )


{
List *temp;
int i;

/* Error check is ignored */


temp = malloc( sizeof ( List ) );
temp -> data = malloc( n );
for (i = 0; i < n; i++)
*( char * ) ( temp -> data + i ) = *( char * ) ( data + i );
temp -> next = *p;
*p = temp;
}

void print( List *p, void ( *f ) ( void * ) )


{
while ( p )
{
( *f ) ( p -> data );
p = p -> next;
}
}

void printstr( void *str )


{
printf( " \"%s\"", ( char * ) str );
}

void printint( void *n )


{
printf( " %d", *( int * ) n );
}

void printchar( void *c )


{
printf( " %c", *( char * ) c );
}

void printcomp( void *comp )


{
struct check temp = *( struct check * )comp;
printf( " '%d:%c:%f ", temp.i, temp.c, temp.d );
}

8.How do you find the middle of a linked list? Write a C program to return the
middle of a linked list
Another popular interview question

Here are a few C program snippets to give you an idea of the possible solutions.

Method1

p = head;
q = head;

if( q -> next -> next != NULL)


{
p = p -> next;
q = q -> next -> next;
}
printf("The middle element is %d",p->data);
9.If you are using C language to implement the heterogeneous linked list, what
pointer type will you use?

The heterogeneous linked list contains different data types in its nodes and we
need a link, pointer to connect them. It is not possible to use ordinary pointers for this. So
we go for void pointer. Void pointer is capable of storing pointer to any type as it is a
generic pointer type.
Check out the C program to implement a Generic linked list in the same FAQ.
10.How to compare two linked lists? Write a C program to compare two linked lists.

Here is a simple C program to accomplish the same.

int compare_linked_lists( struct node *q, struct node *r )


{
static int flag ;
if ( ( q == NULL ) && ( r == NULL ) )
{
flag=1;
}
else
{
if ( q == NULL || r == NULL )
{
flag = 0 ;
}
if ( q -> data != r -> data )
{
flag = 0;
}
else
{
compare_linked_lists ( q -> link , r -> link ) ;
}
}
return ( flag ) ;
}
Another way is to do it on similar lines as strcmp() compares two strings, character by
character (here each node is like a character).

11.How to create a copy of a linked list? Write a C program to create a copy of a


linked list.

Check out this C program which creates an exact copy of a linked list.

copy_linked_lists ( struct node *q , struct node **s )


{
if ( q != NULL )
{
*s = malloc ( sizeof ( struct node ) ) ;
( *s ) -> data = q -> data ;
( *s ) -> link = NULL ;
copy_linked_list ( q -> link , & ( ( *s ) -> link ) );
}
}

12.Write a C program to free the nodes of a linked list

Before looking at the answer, try writing a simple C program (with a for loop) to do this.
Quite a few people get this wrong.

This is the wrong way to do it:


struct list *listptr, *nextptr ;
for( listptr = head ; listptr != NULL ; listptr = listptr -> next )
{
free( listptr ) ;
}
If you are thinking why the above piece of code is wrong, note that once you free
the listptr node, you cannot do something like listptr = listptr->next!. Since listptr is
already freed, using it to get listptr->next is illegal and can cause unpredictable results
This is the right way to do it:
struct list *listptr, *nextptr;
for( listptr = head ; listptr != NULL ; listptr = nextptr )
{
nextptr = listptr -> next ;
free( listptr ) ;
}
14.Write a C program to return the nth node from the end of a linked list.

Here is a solution which is often called as the solution that uses frames.

Suppose one needs to get to the 6th node from the end in this LL. First, just keep on
incrementing the first pointer (ptr1) till the number of increments cross n (which is 6 in
this case)

STEP 1 : 1(ptr1,ptr2) -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10

STEP 2 : 1(ptr2) -> 2 -> 3 -> 4 -> 5 -> 6(ptr1) -> 7 -> 8 -> 9 -> 10
Now, start the second pointer (ptr2) and keep on incrementing it till the first pointer (ptr1)
reaches the end of the LL.

STEP 3 : 1 -> 2 -> 3 -> 4(ptr2) -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 (ptr1)
So here you have!, the 6th node from the end pointed to by ptr2!

Here is some C code..

struct node
{
int data;
struct node *next;
}mynode;

mynode * nthNode(mynode *head, int n /*pass 0 for last node*/)


{
mynode *ptr1,*ptr2 ;
int count ;

if( !head )
{
return( NULL ) ;
}

ptr1 = head ;
ptr2 = head ;
count = 0 ;

while( count < n )


{
count++ ;
if ( ( ptr1 = ptr1 -> next ) == NULL )
{
//Length of the linked list less than n. Error.
return( NULL );
}
}
while( ( ptr1 = ptr1 -> next ) != NULL )
{
ptr2 = ptr2 -> next ;
}
return( ptr2 );
}
15.How would you find out if one of the pointers in a linked list is corrupted or not?
This is a really good interview question. The reason is that linked lists are
used in a wide variety of scenarios and being able to detect and correct pointer
corruptions might be a very valuable tool. For example, data blocks associated with files
in a file system are usually stored as linked lists. Each data block points to the next data
block. A single corrupt pointer can cause the entire file to be lost!Discover and fix bugs
when they corrupt the linked list and not when effect becomes visible in some other part
of the program. Perform frequent consistency checks (to see if the linked list is indeed
holding the data that you inserted into it).
lIt is good programming practice to set the pointer value to NULL immediately
after freeing the memory pointed at by the pointer. This will help in debugging,
because it will tell you that the object was freed somewhere beforehand. Keep
track of how many objects are pointing to a object using reference counts if
required.
lUse a good debugger to see how the datastructures are getting corrupted and
trace down the problem. Debuggers like ddd on linux and memory profilers like
Purify, Electric fence are good starting points. These tools should help you track
down heap corruption issues easily.
lAvoid global variables when traversing and manipulating linked lists. Imagine
what would happen if a function which is only supposed to traverse a linked list
using a global head pointer accidently sets the head pointer to NULL!.
lIts a good idea to check the addNode() and the deleteNode() routines and test
them for all types of scenarios. This should include tests for inserting/deleting
nodes at the front/middle/end of the linked list, working with an empty linked list,
running out of memory when using malloc() when allocating memory for new
nodes, writing through NULL pointers, writing more data into the node fields then
they can hold (resulting in corrupting the (probably adjacent) "prev" and "next"
pointer fields), make sure bug fixes and enhancements to the linked list code are
reviewed and well tested (a lot of bugs come from quick and dirty bug fixing), log
and handle all possible errors (this will help you a lot while debugging), add
multiple levels of logging so that you can dig through the logs. The list is
endless...
lEach node can have an extra field associated with it. This field indicates the
number of nodes after this node in the linked list. This extra field needs to be kept
up-to-date when we inserte or delete nodes in the linked list (It might become
slightly complicated when insertion or deletion happens not at end, but anywhere
in the linked list). Then, if for any node, p->field > 0 and p->next == NULL, it
surely points to a pointer corruption.
lYou could also keep the count of the total number of nodes in a linked list and
use it to check if the list is indeed having those many nodes or not.
The problem in detecting such pointer corruptions in C is that its only the programmer
who knows that the pointer is corrupted. The program has no way of knowing that
something is wrong. So the best way to fix these errors is check your logic and test your
code to the maximum possible extent. I am not aware of ways in C to recover the lost
nodes of a corrupted linked list.

I have a hunch that interviewers who ask this question are probably hinting at something
called Smart Pointers in C++. Smart pointers are particularly useful in the face of
exceptions as they ensure proper destruction of dynamically allocated objects. They can
also be used to keep track of dynamically allocated objects shared by multiple owners.
This topic is out of scope here, but you can find lots of material on the Internet for Smart
Pointers.
If you have better answers to this question, let me know!

16.Write your own C program to implement the atoi() function


int myatoi( const char *string )
{
int i;
i = 0;
while( *string )
{
i = ( i << 3 ) + ( i << 1 ) + ( *string - '0' );
string++;
// Dont increment i!
}
return( i );
}

int myatoi(const char* string)


{
int value = 0;
if ( string )
{
while ( *string && ( *string <= '9' && *string >= '0' ) )
{
value = ( value * 10 ) + ( *string - '0' ) ;
string++;
}
}
return value;
}

17.Implement the memmove() function. What is the difference between the


memmove() and memcpy() function?

One more most frequently asked interview question!.


memmove() offers guaranteed behavior if the source and destination arguments overlap.
memcpy() makes no such guarantee, and may therefore be more efficient to implement.
It's always safer to use memmove().
Note that the prototype of memmove() is ...
void *memmove(void *dest, const void *src, size_t count);
Here is an implementation..

#include <stdio.h>
#include <string.h>

void *mymemmove(void *dest, const void *src, size_t count);

int main(int argc, char* argv[])


{
char *p1, *p2;
char *p3, *p4;
int size;
printf("\n--------------------------------\n");
-------------
*
* CASE 1 : From (SRC) < To (DEST)
*
* +--+---------------------+--+
*||||
* +--+---------------------+--+
*^^
*||
* From To
*
* --------------------------------------- */

p1 = (char *) malloc(12);
memset(p1,12,'\0');
size=10;

strcpy(p1,"ABCDEFGHI");

p2 = p1 + 2;

printf("\n--------------------------------\n");
printf("\nFrom (before) = [%s]",p1);
printf("\nTo (before) = [%s]",p2);

mymemmove(p2,p1,size);

printf("\n\nFrom (after) = [%s]",p1);


printf("\nTo (after) = [%s]",p2);
printf("\n--------------------------------\n");

/* ----------------------------------------
*
* CASE 2 : From (SRC) > To (DEST)
*
* +--+---------------------+--+
*||||
* +--+---------------------+--+
*^^
*||
* To From
*
* --------------------------------------- */

p3 = (char *) malloc(12);
memset(p3,12,'\0');
p4 = p3 + 2;

strcpy(p4, "ABCDEFGHI");

printf("\nFrom (before) = [%s]",p4);


printf("\nTo (before) = [%s]",p3);

mymemmove(p3, p4, size);

printf("\n\nFrom (after) = [%s]",p4);


printf("\nTo (after) = [%s]",p3);

printf("\n--------------------------------\n");

/* ----------------------------------------
*
* CASE 3 : No overlap
*
* --------------------------------------- */

p1 = (char *) malloc(30);
memset(p1,30,'\0');
size=10;

strcpy(p1,"ABCDEFGHI");
p2 = p1 + 15;

printf("\n--------------------------------\n");
printf("\nFrom (before) = [%s]",p1);
printf("\nTo (before) = [%s]",p2);

mymemmove(p2,p1,size);

printf("\n\nFrom (after) = [%s]",p1);


printf("\nTo (after) = [%s]",p2);

printf("\n--------------------------------\n");

printf("\n\n");

return 0;
}

void *mymemmove(void *to, const void *from, size_t size)


{
unsigned char *p1;
const unsigned char *p2;

p1 = (unsigned char *) to;


p2 = (const unsigned char *) from;

p2 = p2 + size;

// Check if there is an overlap or not.


while (p2 != from && --p2 != to);

if (p2 != from)
{
// Overlap detected!

p2 = (const unsigned char *) from;


p2 = p2 + size;
p1 = p1 + size;

while (size-- != 0)
{
*--p1 = *--p2;
}
}
else
{
// No overlap OR they overlap as CASE 2 above.
// memcopy() would have done this directly.

while (size-- != 0)
{
*p1++ = *p2++;
}
}

return(to);
}

And here is the output


--------------------------------
From (before) = [ABCDEFGHI]
To (before) = [CDEFGHI]

From (after) = [ABABCDEFGHI]


To (after) = [ABCDEFGHI]
--------------------------------
From (before) = [ABCDEFGHI]
To (before) = [??ABCDEFGHI]

From (after) = [CDEFGHI]


To (after) = [ABCDEFGHI]

--------------------------------

From (before) = [ABCDEFGHI]


To (before) = [FE??&:F]

From (after) = [ABCDEFGHI]


To (after) = [ABCDEFGHI]

--------------------------------
So then, whats the difference between the implementation of memmove() and memcpy().
Its just that memcpy() will not care if the memories overlap and will either copy from left
to right or right to left without checking which method to used depending on the type of
the overlap. Also note that the C code proves that the results are the same irrespective of
the Endian-ness of the machine.

18.Write C code to implement the strstr() (search for a substring) function.


This is also one of the most frequently asked interview questions.
Its asked almost 99% of the times. Here are a few C programs to implement your own
strstr() function.

string being searched */, int n /* length of this string */)


{
int i, j;
printf("\nstring :[%s]""\nlength :[%d]" "\npattern :[%s]""\nlength :[%d]\n\n",
y,n,x,m);

/* Searching */
for (j = 0; j <= (n - m); ++j)
{
for (i = 0; i < m && x[i] == y[i + j]; ++i);
if (i >= m) {printf("\nMatch found at\n\n->[%d]\n->[%s]\n",j,y+j);}
}
}

int main()
{
char *string = "hereroheroero";
char *pattern = "hero";

BF(pattern,strlen(pattern),string,strlen(string));
printf("\n\n");
return(0);
}

20.Implement the strcpy() function.


char *mystrcpy( char *dst, const char *src )
{
char *ptr;
ptr = dst;
while( *dst++ = *src++ ) ;
return ( ptr );
}

21.Implement the strcmp(str1, str2) function


int mystrcmp(const char *s1, const char *s2)
{
while (*s1==*s2)
{
if(*s1=='\0')
return(0);
s1++;
s2++;
}
return(*s1-*s2);
}
22.Implement the substr() function in C.
int main()
{
char str1[] = "India";
char str2[25];
substr(str2, str1, 1, 3);
printf("\nstr2 : [%s]", str2);
return(0);
}
substr(char *dest, char *src, int position, int length)
{
dest[0]='\0';
strncat(dest, (src + position), length);
}

23.Write your own copy() function


Here is some C code that simulates a file copy action.
#include <stdio.h> /* standard I/O routines. */
#define MAX_LINE_LEN 1000 /* maximum line length supported. */
void main(int argc, char* argv[])
{
char* file_path_from;
char* file_path_to;
FILE* f_from;
FILE* f_to;
char buf[MAX_LINE_LEN+1];
file_path_from = "<something>";
file_path_to = "<something_else>";
f_from = fopen(file_path_from, "r");
if (!f_from)
{
exit(1);
}
f_to = fopen(file_path_to, "w+");
if (!f_to) {exit(1);}
/* Copy source to target, line by line. */
while (fgets(buf, MAX_LINE_LEN+1, f_from))
{
if (fputs(buf, f_to) == EOF)
{
exit(1);
}
}
if (!feof(f_from))
{
exit(1);
}
if (fclose(f_from) == EOF)
{
exit(1);
}
if (fclose(f_to) == EOF)
{
exit(1);
}
return(0);
}
24.Write C programs to implement the toupper() and the isupper() functions
toUpper()
int toUpper(int ch)
{
if(ch>='a' && c<='z')
return('A' + ch - 'a');
else
return(ch);
}
isUpper()
int isUpper(int ch)
{
if(ch>='A' && ch <='Z')
return(1); //Yes, its upper!
else
return(0); // No, its lower!
}
25.Write a C program to implement your own strdup() function.
Here is a C program to implement the strdup() function.
char *mystrdup(char *s)
{
char *result = (char*)malloc(strlen(s) + 1);
if (result == (char*)0)
{
return (char*)0;
}
strcpy(result, s);
return result;
}

31.Write a C program to reverse the words in a sentence in place.


That is, given a sentence like this
I am a good boy
The in place reverse would be
boy good a am I
*/
#include <stdio.h>
void rev( char *l, char *r ) ;
int main( int argc, char *argv[] )
{
char buf[] = "the world will go on forever";
char *end, *x, *y;
// Reverse the whole sentence first..
for( end = buf ; *end ; end++ ) ;
rev( buf , end - 1 ) ;
// Now swap each word within sentence...
x = buf-1;
y = buf;
while( x++ < end )
{
if( *x == '\0' || *x == ' ' )
{
rev( y , x - 1 ) ;
y=x+1;
}
}
// Now print the final string....
printf("%s\n",buf ) ;
return( 0 ) ;
}
// Function to reverse a string in place...
void rev( char *l , char *r )
{
char t;
while ( l < r )
{
t = *l ;
*l++ = *r ;
*r-- = t;
}
}

37. How to generate fibonacci numbers? How to find out if a given number is a
fibonacci number or not? Write C programs to do both.
Lets first refresh ourselves with the Fibonacci sequence
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, .....
Fibonacci numbers obey the following rule
F(n) = F(n-1) + F(n-2)
Here is an iterative way to generate fibonacci numbers and also return the nth number.
int fib( int n )
{
int f[n+1];
f[1] = f[2] = 1;
printf("\nf[1] = %d", f[1]);
printf("\nf[2] = %d", f[2]);
for ( int i = 3 ; i <= n ; i++ )
{
f[i] = f[i-1] + f[i-2];
printf("\nf[%d] = [%d]",i,f[i]);
}
return f[n];
}
Here is a recursive way to generate fibonacci numbers.
int fib(int n)
{
if ( n <= 2 )
return 1;
else
return fib(n-1) + fib(n-2);
}
Here is an iterative way to just compute and return the nth number (without storing the
previous numbers).
int fib(int n)
{
int a = 1, b = 1;
for ( int i = 3 ; i <= n ; i++ )
{
int c = a + b;
a = b;
b = c;
}
return a;
}
39.What Little-Endian and Big-Endian? How can I determine whether a machine's
byte order is big-endian or little endian? How can we convert from one to another?
First of all, Do you know what Little-Endian and Big-Endian mean?
Little Endian means that the lower order byte of the number is stored in memory at the
lowest address, and the higher order byte is stored at the highest address. That is, the little
end comes first.
For example, a 4 byte, 32-bit integer
Byte3 Byte2 Byte1 Byte0 will be arranged in memory as follows:
Base_Address+0 Byte0
Base_Address+1 Byte1
Base_Address+2 Byte2
Base_Address+3 Byte3
Intel processors use "Little Endian" byte order.
"Big Endian" means that the higher order byte of the number is stored in memory at the
lowest address, and the lower order byte at the highest address. The big end comes first.
Base_Address+0 Byte3
Base_Address+1 Byte2
Base_Address+2 Byte1
Base_Address+3 Byte0
Motorola, Solaris processors use "Big Endian" byte order.
In "Little Endian" form, code which picks up a 1, 2, 4, or longer byte number proceed in
the same way for all formats. They first pick up the lowest order byte at offset 0 and
proceed from there. Also, because of the 1:1 relationship between address offset and byte
number (offset 0 is byte 0), multiple precision mathematic routines are easy to code. In
"Big Endian" form, since the high-order byte comes first, the code can test whether the
number is positive or negative by looking at the byte at offset zero. Its not required to
know how long the number is, nor does the code have to skip over any bytes to find the
byte containing the sign information. The numbers are also stored in the order in which
they are printed out, so binary to decimal routines are particularly efficient.
Here is some code to determine what is the type of your machine
int num = 1;
if ( * ( char * ) &num == 1 )
{
printf("\nLittle-Endian\n");
}
else
{
printf("Big-Endian\n");
}
And here is some code to convert from one Endian to another.
int myreversefunc( int num )
{
int byte0, byte1, byte2, byte3;
byte0 = ( num & x000000FF ) >> 0 ;
byte1 = ( num & x0000FF00 ) >> 8 ;
byte2 = ( num & x00FF0000 ) >> 16 ;
byte3 = ( num & xFF000000 ) >> 24 ;
return ( ( byte0 << 24 ) | ( byte1 << 16 ) | ( byte2 << 8 ) | ( byte3 << 0 ) ) ;
}

43.Write a C progam to convert from decimal to any base (binary, hex, oct etc...)
Here is some really cool C code
#include <stdio.h>
int main()
{
decimal_to_anybase( 10, 2 );
decimal_to_anybase( 255, 16 );
getch();
}
decimal_to_anybase ( int n , int base )
{
int i , m , digits[1000] , flag ;
i=0;
printf("\n\n[%d] converted to base [%d] : ", n, base);
while ( n )
{
m = n % base ;
digits[ i ] = "0123456789abcdefghijklmnopqrstuvwxyz" [ m ] ;
n = n / base ;
i++ ;
}
//Eliminate any leading zeroes
for( i-- ; i >= 0 ; i-- )
{
if ( !flag && digits[i] != '0' )
flag=1;
if ( flag )
printf("%c",digits[i]);
}
}

44.Write C code to check if an integer is a power of 2 or not in a single line?


Even this is one of the most frequently asked interview questions. I really dont know
whats so great in it. Nevertheless, here is a C program
Method1
if ( ! ( num & ( num - 1 ) ) && num )
{
// Power of 2!
}
Method2
if ( ( ( ~i + 1 ) & i ) == i )
{
//Power of 2!
}
53.Write a C program to check for palindromes.
An example of a palidrome is "avon sees nova"
There a number of ways in which we can find out if a string is a palidrome or not. Here
are a few sample C programs...
Method1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
boolean palindrome( char string[] )
{
int count, countback, end, N;
N = strlen ( string ) ;
end = N-1 ;
for( ( count = 0, count <= end ) ; count <= ( end / 2 ) ; ++count ,--countback )
{
if ( string[count] != string[countback] )
{
return( FALSE );
}
}
return(TRUE);
}

55.Write C code to implement the Binary Search algorithm.


Here is a C function
int binarySearch( int arr[] , int size , int item )
{
int left , right , middle ;
left = 0;
right = size-1;
while( left <= right )
{
middle = ( ( left + right ) / 2 ) ;
if( item == arr[middle] )
{
return( middle );
}
if( item > arr[middle] )
{
left = middle+1;
}
else
{
right = middle-1;
}
}
return(-1);
}
Note that the Binary Search algorithm has a prerequisite that the array passed to it must
be already sorted in ascending order. This will not work on an unsorted array. The
complexity of this algorithm is O(log(n)).
64.How to swap the two nibbles in a byte ?
Try this
#include <stdio.h>
unsigned char swap_nibbles(unsigned char c)
{
unsigned char temp1, temp2;
temp1 = c & 0x0F;
temp2 = c & 0xF0;
temp1 = temp1 << 4;
temp2 = temp2 >> 4;
return( temp2 | temp1 ) ; //adding the bits
}
int main(void)
{
char ch = 0x34 ;
printf("\nThe exchanged value is %x",swap_nibbles(ch));
return 0;
}
74.How can we sum the digits of a given number in single statement?
Try something like this
# include<stdio.h>
void main()
{
int num=123456;
int sum=0;
for( ; num > 0 ; sum += num % 10 , num /= 10 ) ; // This is the "single line".
printf("\nsum = [%d]\n", sum);
}
79.How to generate prime numbers? How to generate the next prime after a given
prime?
Brute Force
Test each number starting with 2 and continuing up to the number of primes we want to
generate. We divide each numbr by all divisors upto the square root of that number. If no
factors are found, its a prime.
Using only primes as divisors
Test each candidate only with numbers that have been already proven to be prime. To do
so, keep a list of already found primes (probably using an array, a file or bit fields).
Test with odd candidates only
We need not test even candidates at all. We could make 2 a special case and just print it,
not include it in the list of primes and start our candidate search with 3 and increment by
2 instead of one everytime.
Table method
Suppose we want to find all the primes between 1 and 64. We write out a table of these
numbers, and proceed as follows. 2 is the first integer greater than 1, so its obviously
prime. We now cross out all multiples of two. The next number we haven't crossed out is
3. We circle it and cross out all its multiples. The next non-crossed number is 5, sp we
circle it and cross all its mutiples. We only have to do this for all numbers less than the
square root of our upper limit, since any composite in the table must have atleast one
factor less than the square root of the upper limit. Whats left after this process of
elimination is all the prime numbers between 1 and 64.

81.Write your own trim() or squeeze() function to remove the spaces from a string.
Here is one version...
#include <stdio.h>
char *trim( char *s ) ;
int main( int argc , char *argv[] )
{
char str1[] = " Hello I am Good " ;
printf("\n\nBefore trimming : [%s]", str1);
printf("\n\nAfter trimming : [%s]", trim(str1));
getch( ) ;
}
// The trim() function...
char *trim( char *s )
{
char *p, *ps;
for ( ps = p = s ; *s != '\0' ; s++ )
{
if ( !isspace( *s ) )
{
*p++ = *s ;
}
}
*p = '\0' ;
return( ps ) ;
}

113.How to reverse the bits in an interger?


Here are some ways to reverse the bits in an integer.
Method1
unsigned int num; // Reverse the bits in this number.
unsigned int temp = num; // temp will have the reversed bits of num.
int i;
for (i = (sizeof(num)*8-1); i; i--)
{
temp = temp | (num & 1);
temp <<= 1;
num >>= 1;
}
temp = temp | (num & 1);

24) & 0xff] );


114.Check if the 20th bit of a 32 bit integer is on or off?
AND it with x00001000 and check if its equal to x00001000
if ( ( num & x00001000 ) == x00001000 )
Note that the digits represented here are in hex.
0 0 0 0 1 0 0 0
^
|
x0000 0000 0000 0000 0001 0000 0000 0000 = 32 bits
^ ^ ^
| | |
0th bit 20th bit 32nd bit

115.How to reverse the odd bits of an integer?


XOR each of its 4 hex parts with 0101.

136.What operations are valid on pointers? When does one get the Illegal use of
pointer in function error?
This is what is Valid
px<py
px>=py
px==py
px!=py
px==NULL
px=px+n
px=px-n
px-py
Everything else is invalid (multiplication, division, addition of two pointers)!
How can I find how many arguments a function was passed?
Any function which takes a variable number of arguments must be able to
determine from the arguments themselves, how many of them there have been passed.
printf() and some similar functions achieve this by looking for the format string. This is
also why these functions fail badly if the format string does not match the argument list.
Another common technique, applicable when the arguments are all of the same type, is to
use a sentinel value (often 0, -1, or an appropriately-cast null pointer) at the end of the
list. Also, one can pass an explicit count of the number of variable arguments. Some older
compilers did provided a nargs() function, but it was never portable.
Is this allowed?
int f(...)
{
...
}
No! Standard C requires at least one fixed argument, in part so that you can hand it to
va_start().

151.If I have the name of a function in the form of a string, how can I invoke that
function?
Keep a table of names and their function pointers:
int myfunc1(), myfunc2();
struct
{
char *name;
int (*func_ptr)();
} func_table[] = {"myfunc1", myfunc1,"myfunc2", myfunc2,};
Search the table for the name, and call via the associated function pointer.

157.Whats wrong with the expression a[i]=i++; ? Whats a sequence point?


Although its surprising that an expression like i=i+1; is completely valid, something like
a[i]=i++; is not. This is because all accesses to an element must be to change the value of
that variable. In the statement a[i]=i++; , the access to i is not for itself, but for a[i] and so
its invalid. On similar lines, i=i++; or i=++i; are invalid. If you want to increment the
value of i, use i=i+1; or i+=1; or i++; or ++i; and not some combination.
A sequence point is a state in time (just after the evaluation of a full expression, or
at the ||, &&, ?:, or comma operators, or just before a call to a function) at which there are
no side effects.
The ANSI/ISO C Standard states that
Between the previous and next sequence point an object shall have its stored
value modified at most once by the evaluation of an expression. Furthermore,
the prior value shall be accessed only to determine the value to be stored.
At each sequence point, the side effects of all previous expressions will be completed.
This is why you cannot rely on expressions such as a[i] = i++;, because there is no
sequence point specified for the assignment, increment or index operators, you don't
know when the effect of the increment on i occurs.
The sequence points laid down in the Standard are the following:
* The point of calling a function, after evaluating its arguments.
* The end of the first operand of the && operator.
* The end of the first operand of the || operator.
* The end of the first operand of the ?: conditional operator.
* The end of the each operand of the comma operator.
* Completing the evaluation of a full expression. They are the following:
o Evaluating the initializer of an auto object.
o The expression in an ?ordinary? statement?an expression followed by semicolon.
o The controlling expressions in do, while, if, switch or for statements.
o The other two expressions in a for statement.
o The expression in a return statement.

There are some limitations with respect to these bit fields, however:
1. Cannot scanf() directly into bit fields.
2. Pointers cannot be used on bit fields to access them.
3. Cannot have an array of bit fields.
The main use of bitfields is either to allow tight packing of data or to be able to specify
the fields within some externally produced data files. C gives no guarantee of the
ordering of fields within machine words, so if you do use them for the latter reason, you
program will not only be non-portable, it will be compiler-dependent too. The Standard
says that fields are packed into ?storage units?, which are typically machine words. The
packing order, and whether or not a bitfield may cross a storage unit boundary, are
implementation defined. To force alignment to a storage unit boundary, a zero width field
is used before the one that you want to have aligned. Be careful using them. It can require
a surprising amount of run-time code to manipulate these things and you can end up
using more space than they save. Bit fields do not have addresses?you can't have pointers
to them or arrays of them.

206.How can I insert or delete a line (or record) in the middle of a file?
The only way is to rewrite the file.
207.How can I recover the file name using its file descriptor?
Have a wrapper around fopen() to remember the names of files as you open them.

209.Whats the use of fopen(), fclose(), fprintf(), getc(), putc(), getw(), putw(),
fscanf(), feof(), ftell(), fseek(), rewind(), fread(), fwrite(), fgets(), fputs(), freopen(),
fflush(), ungetc()?
Whew!, thats a huge list.
fopen()
This function is used to open a stream.
FILE *fp;
fp = fopen("filename","mode");
fp = fopen("data","r");
fp = fopen("results","w");
Modes
"r" -> Open for reading.
"w" -> Open for writing.
"a" -> Open for appending.
"r+" -> Both reading and writing.
"w+" -> Both reading and writing, create new file if it exists,
"a+" -> Open for both reading and appending.
fopen()
fclose() is used to close a stream .
fclose(fp);
putc(), getc(), putw(), getw(), fgetc(), getchar(), putchar(), fputs()
These functions are used to read/write different types of data to the stream.
putc(ch,fp);
c=getc(fp);
putw(integer, fp);
integer=getw(fp);
fprintf(), fscanf()
Read/Write formatted data from/to the stream.
fprintf(fp,"control string",list);
fscanf(fp,"control string", list);
foef()
Check the status of a stream
if(feof(fp)!=0)
ftell(), fseek(), rewind(), fgetpos(), fsetpos()
Reposition the file pointer of a stream
n=ftell(fp); //Relative offset (in bytes) of the current position.
rewind(fp);
fseek(fp, offset, position);
Position can be
0->start of file
1->current position
2->end of file
fseek(fp,0L,0); // Same as rewind.
fseek(fp,0L,1); // Stay at current position.
fseek(fp,0L,2); // Past end of file.
fseek(fp,m,0); // Move to (m+1) byte.
fseek(fp,m,1) // Go forward m bytes.
fseek(fp,-m,1); // Go backward m bytes from current position.
fseek(fp,-m,2); // Go backward from end of file.
fread(), fwrite()
Binary stream input/output.
fwrite(&customer, sizeof(record),1,fp);
fread(&customer,sizeof(record),1,fp);
Here is a simple piece of code which reads from a file
#include <stdio.h>
#include <conio.h>
int main()
{
FILE *f;
char buffer[1000];
f=fopen("E:\\Misc\\__Temp\\FileDrag\\Main.cpp","r");
if(f)
{
printf("\nOpenened the file!\n");
while(fgets(buffer,1000,f))
{
printf("(%d)-> %s\n",strlen(buffer),buffer);
}
}
fclose(f);
getch();
return(0);
}
210.How to check if a file is a binary file or an ascii file?
Here is some sample C code. The idea is to check the bytes in the file to see if they are
ASCII or not...
#include <stdio.h>
int main(int argc, char *argv[])
{
unsigned char ch;
FILE *file;
int binaryFile = FALSE;
file = fopen(<FILE_PATH>, "rb"); // Open in Binary mode for the first
time.
while((fread(&ch, 1, 1, file) == 1) && (binaryFile == FALSE))
{
if(ch < 9 || ch == 11 || (ch > 13 && ch < 32) || ch == 255)
{
binaryFile = 1;
}
}
fclose(file);
if(binaryFile)
file = fopen(<FILE_PATH>, "rb");
else
file = fopen(<FILE_PATH>, "r");
if(binaryFile)
{
while(fread(&ch, 1, 1, file) == 1)
{
// Do whatever you want here with the binary file byte...
}
}
else
{
while(fread(&ch, 1, 1, file) == 1)
{
// This is ASCII data, can easily print it!
putchar(ch);
}
}
fclose(file);
return(0);
}

219.How does the function strtok() work?


strtok() is the only standard function available for "tokenizing" strings.
The strtok() function can be used to parse a string into tokens. The first call to strtok()
should have the string as its first argument. Subsequent calls should have the first
argument set to NULL. Each call returns a pointer to the next token, or NULL when no
more tokens are found. If a token ends with a delimiter, this delimiting character is
overwritten with a "\0" and a pointer to the next character is saved for the next call to
strtok(). The delimiter string delim may be different for each call.
The strtok_r() function works the same as the strtok() function, but instead of using a
static buffer it uses a pointer to a user allocated char* pointer. This pointer must be the
same while parsing the same string.
An example
main()
{
char str[]="This is a test";
char *ptr[10];
char *p;
int i=1;
int j;
p=strtok(str," ");
if(p!=NULL)
{
ptr[0]=p;
while(1)
{
p=strtok(NULL, " ");
if(p==NULL)
break;
else
{
ptr[i] = p;
i++;
}
}
}
for(j=0;j<i;j++)
{
printf("\n%s\n", ptr[i]);
}
}
223.What do memcpy(), memchr(), memcmp(), memset(), strdup(), strncat(),
strcmp(), strncmp(), strcpy(), strncpy(), strlen(), strchr(), strchr(), strpbrk(),
strspn(), strcspn(), strtok() do?
Here are the prototypes...
void *memchr(const void *s, int c, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
void *memset(void *s, int c, size_t n);
char *strcat(char *restrict s1, const char *restrict s2);
char *strchr(const char *s, int c);
int strcmp(const char *s1, const char *s2);
char *strcpy(char *restrict s1, const char *restrict s2);
size_t strcspn(const char *s1, const char *s2);
char *strdup(const char *s1);
size_t strlen(const char *s);
char *strncat(char *restrict s1, const char *restrict s2, size_t n);
int strncmp(const char *s1, const char *s2, size_t n);
char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
char *strpbrk(const char *s1, const char *s2);
char *strrchr(const char *s, int c);
size_t strspn(const char *s1, const char *s2);
char *strstr(const char *s1, const char *s2);
char *strtok(char *restrict s1, const char *restrict s2);
The memchr() function shall locate the first occurrence of c (converted to an unsigned
char) in the initial n bytes (each interpreted as unsigned char) of the object pointed to by
s. The memchr() function shall return a pointer to the located byte, or a null pointer if the
byte does not occur in the object.
The memcmp() function shall compare the first n bytes (each interpreted as unsigned
char) of the object pointed to by s1 to the first n bytes of the object pointed to by s2. The
sign of a non-zero return value shall be determined by the sign of the difference between
the values of the first pair of bytes (both interpreted as type unsigned char) that differ in
the objects being compared. The memcmp() function shall return an integer greater than,
equal to, or less than 0, if the object pointed to by s1 is greater than, equal to, or less than
the object pointed to by s2, respectively.
The memcpy() function shall copy n bytes from the object pointed to by s2 into the
object pointed to by s1. If copying takes place between objects that overlap, the behavior
is undefined. The memcpy() function returns s1; no value is reserved to indicate an error.
The memmove() function shall copy n bytes from the object pointed to by s2 into the
object pointed to by s1. Copying takes place as if the n bytes from the object pointed to
by s2 are first copied into a temporary of n bytes that does not overlap the objects pointed
to by s1 and s2, and then the n bytes from the temporary array are copied into the object
pointed to by s1. The memmove() function returns s1; no value is reserved to indicate an
error.
The memset() function shall copy c (converted to an unsigned char) into each of the first
n bytes of the object pointed to by s. The memset() function returns s; no value is
reserved to indicate an error.
The strcat() function shall append a copy of the string pointed to by s2 (including the
terminating null byte) to the end of the string pointed to by s1. The initial byte of s2
overwrites the null byte at the end of s1. If copying takes place between objects that
overlap, the behavior is undefined. The strcat() function shall return s1; no return value is
reserved to indicate an error.
The strchr() function shall locate the first occurrence of c (converted to a char) in the
string pointed to by s. The terminating null byte is considered to be part of the string.
Upon completion, strchr() shall return a pointer to the byte, or a null pointer if the byte
was not found.
The strcmp() function shall compare the string pointed to by s1 to the string pointed to
by s2. The sign of a non-zero return value shall be determined by the sign of the
difference between the values of the first pair of bytes (both interpreted as type unsigned
char) that differ in the strings being compared. Upon completion, strcmp() shall return an
integer greater than, equal to, or less than 0, if the string pointed to by s1 is greater than,
equal to, or less than the string pointed to by s2, respectively.
The strcpy() function shall copy the string pointed to by s2 (including the terminating
null byte) into the array pointed to by s1. If copying takes place between objects that
overlap, the behavior is undefined. The strcpy() function returns s1; no value is reserved
to indicate an error.
The strcspn() function shall compute the length (in bytes) of the maximum initial
segment of the string pointed to by s1 which consists entirely of bytes not from the string
pointed to by s2. The strcspn() function shall return the length of the computed segment
of the string pointed to by s1; no return value is reserved to indicate an error.
The strdup() function shall return a pointer to a new string, which is a duplicate of the
string pointed to by s1, if memory can be successfully allocated for the new string. The
returned pointer can be passed to free(). A null pointer is returned if the new string cannot
be created. The function may set errno to ENOMEM if the allocation failed.
The strlen() function shall compute the number of bytes in the string to which s points,
not including the terminating null byte. The strlen() function shall return the length of s;
no return value shall be reserved to indicate an error.
The strncat() function shall append not more than n bytes (a null byte and bytes that
follow it are not appended) from the array pointed to by s2 to the end of the string pointed
to by s1. The initial byte of s2 overwrites the null byte at the end of s1. A terminating null
byte is always appended to the result. If copying takes place between objects that overlap,
the behavior is undefined. The strncat() function shall return s1; no return value shall be
reserved to indicate an error.
The strncmp() function shall compare not more than n bytes (bytes that follow a null
byte are not compared) from the array pointed to by s1 to the array pointed to by s2. The
sign of a non-zero return value is determined by the sign of the difference between the
values of the first pair of bytes (both interpreted as type unsigned char) that differ in the
strings being compared. Upon successful completion, strncmp() shall return an integer
greater than, equal to, or less than 0, if the possibly null-terminated array pointed to by s1
is greater than, equal to, or less than the possibly null-terminated array pointed to by s2
respectively.
The strncpy() function shall copy not more than n bytes (bytes that follow a null byte are
not copied) from the array pointed to by s2 to the array pointed to by s1. If copying takes
place between objects that overlap, the behavior is undefined. If the array pointed to by
s2 is a string that is shorter than n bytes, null bytes shall be appended to the copy in the
array pointed to by s1, until n bytes in all are written. The strncpy() function shall return
s1; no return value is reserved to indicate an error.
The strpbrk() function shall locate the first occurrence in the string pointed to by s1 of
any byte from the string pointed to by s2. Upon successful completion, strpbrk() shall
return a pointer to the byte or a null pointer if no byte from s2 occurs in s1.
The strrchr() function shall locate the last occurrence of c (converted to a char) in the
string pointed to by s. The terminating null byte is considered to be part of the string.
Upon successful completion, strrchr() shall return a pointer to the byte or a null pointer if
c does not occur in the string.
The strspn() function shall compute the length (in bytes) of the maximum initial segment
of the string pointed to by s1 which consists entirely of bytes from the string pointed to
by s2. The strspn() function shall return the computed length; no return value is reserved
to indicate an error.
The strstr() function shall locate the first occurrence in the string pointed to by s1 of the
sequence of bytes (excluding the terminating null byte) in the string pointed to by s2.
Upon successful completion, strstr() shall return a pointer to the located string or a null
pointer if the string is not found. If s2 points to a string with zero length, the function
shall return s1.
A sequence of calls to strtok() breaks the string pointed to by s1 into a sequence of
tokens, each of which is delimited by a byte from the string pointed to by s2. The first
call in the sequence has s1 as its first argument, and is followed by calls with a null
pointer as their first argument. The separator string pointed to by s2 may be different
from call to call. The first call in the sequence searches the string pointed to by s1 for the
first byte that is not contained in the current separator string pointed to by s2. If no such
byte is found, then there are no tokens in the string pointed to by s1 and strtok() shall
return a null pointer. If such a byte is found, it is the start of the first token. The strtok()
function then searches from there for a byte that is contained in the current separator
string. If no such byte is found, the current token extends to the end of the string pointed
to by s1, and subsequent searches for a token shall return a null pointer. If such a byte is
found, it is overwritten by a null byte, which terminates the current token. The strtok()
function saves a pointer to the following byte, from which the next search for a token
shall start. Each subsequent call, with a null pointer as the value of the first argument,
starts searching from the saved pointer and behaves as described above. Upon successful
completion, strtok() shall return a pointer to the first byte of a token. Otherwise, if there is
no token, strtok() shall return a null pointer.
224.What does alloca() do?
alloca() allocates memory which is automatically freed when the function which called
alloca() returns. However, note that alloca() is not portable and its usage is not
recommended.
227.What do setjmp() and longjump() functions do?
It is not possible to jump from one function to another by means of a goto and a label,
since labels have only function scope. However, the macro setjmp and function longjmp
provide an alternative, known as a non-local goto, or a non-local jump. The header file
<setjmp.h> declares something called a jmp_buf, which is used by the cooperating macro
and function to store the information necessary to make the jump. The declarations are as
follows:
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
The setjmp macro is used to initialise the jmp_buf and returns zero on its initial call.
Then, it returns again, later, with a non-zero value, when the corresponding longjmp call
is made! The non-zero value is whatever value was supplied to the call of longjmp.
This is best explained by way of an example:
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

void func(void);
jmp_buf place;
main()
{
int retval;
/*
* First call returns 0,
* a later longjmp will return non-zero.
*/
if(setjmp(place)) != 0)
{
printf("Returned using longjmp\n");
exit(EXIT_SUCCESS);
}
/*
* This call will never return - it
* 'jumps' back above.
*/
func();
printf("What! func returned!\n");
}
void func(void)
{
/*
* Return to main.
* Looks like a second return from setjmp,
* returning 4!
*/
longjmp(place, 4);
printf("What! longjmp returned!\n");
}
The val argument to longjmp is the value seen in the second and subsequent ?returns?
from setjmp. It should normally be something other than 0; if you attempt to return 0 via
longjmp, it will be changed to 1. It is therefore possible to tell whether the setjmp was
called directly, or whether it was reached by calling longjmp. If there has been no call to
setjmp before calling longjmp, the effect of longjmp is undefined, almost certainly
causing the program to crash. The longjmp function is never expected to return, in the
normal sense, to the instructions immediately following the call. All accessible objects on
?return? from setjmp have the values that they had when longjmp was called, except for
objects of automatic storage class that do not have volatile type; if they have been
changed between the setjmp and longjmp calls, their values are indeterminate.
The longjmp function executes correctly in the contexts of interrupts, signals and any of
their associated functions. If longjmp is invoked from a function called as a result of a
signal arriving while handling another signal, the behaviour is undefined.
It's a serious error to longjmp to a function which is no longer active (i.e. it has already
returned or another longjump call has transferred to a setjmp occurring earlier in a set of
nested calls).
The Standard insists that, apart from appearing as the only expression in an expression
statement, setjmp may only be used as the entire controlling expression in an if, switch,
do, while, or for statement. A slight extension to that rule is that as long as it is the whole
controlling expression (as above) the setjmp call may be the subject of the ! operator, or
may be directly compared with an integral constant expression using one of the relational
or equality operators. No more complex expressions may be employed.
Examples are:
setjmp(place); /* expression statement */
if(setjmp(place)) ... /* whole controlling expression */
if(!setjmp(place)) ... /* whole controlling expression */
if(setjmp(place) < 4) ... /* whole controlling expression */
if(setjmp(place)<;4 && 1!=2) ... /* forbidden */

232.What do the system calls fork(), vfork(), exec(), wait(), waitpid() do? Whats a
Zombie process? Whats the difference between fork() and vfork()?
The system call fork() is used to create new processes. It does not take any arguments and
returns a process ID. The purpose of fork() is to create a new process, which becomes the
child process of the caller (which is called the parent). After a new child process is
created, both processes will execute the next instruction following the fork() system call.
We can distinguish the parent from the child by testing the returned value of fork():
If fork() returns a negative value, the creation of a child process was unsuccessful. A call
to fork() returns a zero to the newly created child process and the same call to fork()
returns a positive value (the process ID of the child process) to the parent. The returned
process ID is of type pid_t defined in sys/types.h. Normally, the process ID is an integer.
Moreover, a process can use function getpid() to retrieve the process ID assigned to this
process. Unix will make an exact copy of the parent's address space and give it to the
child. Therefore, the parent and child processes will have separate address spaces. Both
processes start their execution right after the system call fork(). Since both processes have
identical but separate address spaces, those variables initialized before the fork() call
have the same values in both address spaces. Since every process has its own address
space, any modifications will be independent of the others. In other words, if the parent
changes the value of its variable, the modification will only affect the variable in the
parent process's address space. Other address spaces created by fork() calls will not be
affected even though they have identical variable names.
Trick question!
The UID (numeric user identity)
The GID (numeric group identity)
A process ID number used to identify the process
A parent process ID
The execution status, e.g. active, runnable, waiting for input etc.
Environment variables and values.
The current directory.
Where the process currently resides in memory
The relative process priority see nice(1)
Where it gets standard input from
Where it sends standard output to
Any other files currently open
Certain process resources are unique to the individual process. A few among these are:
* Stack Space: which is where local variables, function calls, etc. are stored.
* Environment Space: which is used for storage of specific environment variables.
* Program Pointer (counter) : PC.
* File Descriptors
* Variables
Undex unix, each sub directory under /proc corresponds to a running process (PID #). A
ps provide detailed information about processes running
A typical output of ps looks as follows:
PID TTY STAT TIME COMMAND
--------------------------------------------------------------------
8811 3 SW 0:00 (login)
3466 3 SW 0:00 (bash)
8777 3 SW 0:00 (startx)
. . . . .
1262 p7 R 0:00 ps
The columns refer to the following:
PID - The process id's (PID).
TTY - The terminal the process was started from.
STAT - The current status of all the processes. Info about the process status
can be broken into more than 1 field. The first of these fields can
contain the following entries:
R - Runnable.
S - Sleeping.
D - Un-interuptable sleep.
T - Stopped or Traced.
Z - Zombie Process.
The second field can contain the following entry:
W - If the process has no residual pages.
And the third field:
N - If the process has a positive nice value.
TIME - The CPU time used by the process so far.
COMMAND - The actual command.
The init process is the very first process run upon startup. It starts additional processes.
When it runs it reads a file called /etc/inittab which specifies init how to set up the
system, what processes it should start with respect to specific runlevels. One crucial
process which it starts is the getty program. A getty process is usually started for each
terminal upon which a user can log into the system. The getty program produces the
login: prompt on each terminal and then waits for activity. Once a getty process detects
activity (at a user attempts to log in to the system), the getty program passes control over
to the login program.
There are two command to set a process's priority nice and renice.
One can start a process using the system() function call
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Running ls.....\n");
system("ls -lrt");
printf("Done.\n");
exit(0);
}
The exec() system call
The exec() functions replace a current process with another created according to the
arguments given.
The syntax of these functions is as follows:
#include <unistd.h>
char *env[];
int execl(const char *path, const char *arg0, ..., (char *)0);
int execv(const char *path, const char *argv[]);
int execlp(const char *path, const char *arg0, ..., (char *)0);
int execvp(const char *path, const char *argv[]);
int execle(const char *path, const char *arg0, ... , (char *)0, const char *env[]);
int execve(const char *path, const char *argv[], const char *env[]);
The program given by the path argument is used as the program to execute in place of
what is currently running. In the case of the execl() the new program is passed arguments
arg0, arg1, arg2,... up to a null pointer. By convention, the first argument supplied (i.e.
arg0) should point to the file name of the file being executed. In the case of the execv()
programs the arguments can be given in the form of a pointer to an array of strings, i.e.
the argv array. The new program starts with the given arguments appearing in the argv
array passed to main. Again, by convention, the first argument listed should point to the
file name of the file being executed. The function name suffixed with a p (execlp() and
execvp())differ in that they will search the PATH environment variable to find the new
program executable file. If the executable is not on the path, and absolute file name,
including directories, will need to be passed to the function as a parameter. The global
variable environ is available to pass a value for the new program environment. In
addition, an additional argument to the exec() functions execle() and execve() is available
for passing an array of strings to be used as the new program environment.
Examples to run the ls command using exec are:
const char *argv[] = ("ls", "-lrt", 0);
const char *env[] = {"PATH=/bin:/usr/bin", "TERM=console", 0};
execl("/bin/ls", "ls", "-lrt", 0);
execv("/bin/ls", argv);
execlp("ls", "ls", "-lrt", 0);
execle("/bin/ls", "ls", "-lrt", 0, env);
execvp("ls", argv);
execve("/bin/ls", argv, env);
A simple call to fork() would be something like this
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid=fork();
switch(pid)
{
case -1:
exit(1); // fork() error.
case 0: // Child process, can call exec here.
break;
default: // Parent.
break;
}
exit(0);
}
The call wait() can be used to determine when a child process has completed it's job and
finished. We can arrange for the parent process to wait untill the child finishes before
continuing by calling wait(). wait() causes a parent process to pause untill one of the child
processes dies or is stopped. The call returns the PID of the child process for which status
information is available. This will usually be a child process which has terminated. The
status information allows the parent process to determine the exit status of the child
process, the value returned from main or passed to exit. If it is not a null pointer the status
information will be written to the location pointed to by stat_loc. We can interrogate the
status information using macros defined in sys/wait.h.
Macro Definition
-----------------------------------------------------------------------------------
WIFEXITED(stat_val); Nonzero if the child is terminated normally
WEXITSTATUS(stat_val); If WIFEXITED is nonzero, this returns child exit code.
WIFSIGNALLED(stat_val); Nonzero if the child is terminated on an uncaught signal.
WTERMSIG(stat_val); If WIFSIGNALLED is nonzero, this returns a signal number.
WIFSTOPPED(stat_val); Nonzero if the child stopped on a signal.
WSTOPSIG(stat_val); If WIFSTOPPED is nonzero, this returns a signal number.
An example code which used wait() is shown below
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void){
pid_t child_pid;
int *status=NULL;
if( fork ( ) )
{
/* wait for child, getting PID */
child_pid=wait(status);
printf("I'm the parent.\n");
printf("My child's PID was: %d\n",child_pid);
}
else
{
printf("I'm the child.\n");
}
return 0;
}
Or a more detailed program
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
int exit_code;
pid = fork();
switch(pid)
{
case -1:
exit(1);
case 0:
exit_code = 11; //Set the child exit process
break;
default:
exit_code = 0;
break;
}
if (pid)
{
// This is the parent process
int status;
pid_t child_pid;
child_pid = wait(&status);
printf("Child process finished with PID [%d]\n", child_pid);
if (WIFEXITED(status))
{
printf("Child exited with code [%d]\n", WEXITSTATUS(status));
}
else
{
printf("Child terminated abnormally.\n");
}
}
exit(exit_code);
}

So whats the difference between fork() and vfork()?


The system call vfork(), is a low overhead version of fork(), as fork() involves copying
the entire address space of the process and is therefore quite expensive. The basic
difference between the two is that when a new process is created with vfork(), the parent
process is temporarily suspended, and the child process might borrow the parent's address
space. This strange state of affairs continues until the child process either exits, or calls
execve(), at which point the parent process continues. This means that the child process
of a vfork() must be careful to avoid unexpectedly modifying variables of the parent
process. In particular, the child process must not return from the function containing the
vfork() call, and it must not call exit() (if it needs to exit, it should use _exit(); actually,
this is also true for the child of a normal fork()).
However, since vfork() was created, the implementation of fork() has improved , most
notably with the introduction of `copy-on-write', where the copying of the process
address space is transparently faked by allowing both processes to refer to the same
physical memory until either of them modify it. This largely removes the justification for
vfork(); indeed, a large proportion of systems now lack the original functionality of
vfork() completely. For compatibility, though, there may still be a vfork() call present,
that simply calls fork() without attempting to emulate all of the vfork() semantics

Here you are


Binary search : O(logn)
Finding max & min for a given set of numbers : O(3n/2-2)
Merge Sort : O(nlogn)
Insertion Sort : O(n*n)
Quick Sort : O(nlogn)
Selection Sort : O(n*n)

276.What are the general steps in compilation?


1. Lexical analysis.
2. Syntactic analysis.
3. Sematic analysis.
4. Pre-optimization of internal representation.
5. Code generation.
6. Post optimization.

You might also like