Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Question Bank

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 173

Computer Science Technical

Interview Preparatory Material

Number of Questions in C & Data Structures => 181


Number of Questions in C++ & OOPS => 64
Number of Questions in Databases => 38
Number of Questions in Java, Networking
& Other areas => 23
Number of Questions in General Topic (HR) => 13

Total => 319 Questions


Areas of concentration ( Based on Feedback )

30 C & Data
Structures
25 C++ & OOP
Concepts
20 Databases
15
Operating
10 Systems
Java
5
Networking
0
Order of Importance
Other Topics
C & Data Structures

1. Why do you put #include <stdio.h> at the top of your C program


?
We use standard library functions such as printf and scanf in our
code. The prototypes and related declarations are found in the
header files. So stdio.h header files contains all the prototypes
for Input/Output. So since we use the standard library functions
we need to include the corresponding headers. These get linked
to the proper library when we compile the program. For C
standard library functions the libc.a is the archive to which the
code will be linked.

2. What is a linked list ? Give an example.

A linked list is a list of items that are not contiguous in memory.


Each node in a linked list contains a pointer to the next node. The
advantage of a linked list is that these are created dynamically ( at
run time ). This means that they can grow and shrink as required at
run-time. This is in contrast to Arrays where the size is fixed at
compile-time.

20 0x100

35 0x780

60 NULL

The example above shows a linear linked list with 3 nodes. Each node
in the linked list contains a data member and a pointer member. As we
can see from the diagram the pointer member of the first node
contains the address of the second (next) node. Similarly the pointer
member of the second node contains the address of the third (next)
node. There are no more nodes and hence the pointer member of the
third (last) node in the list is NULL. All you need to know is the starting
address of the first node in the linked list. You can traverse all the
other nodes easily by following the pointer links.

3. Create the structure for a node in the linked list ?


struct node
{
Int node;
struct node *next;
};

struct node node1; /* node1 is variable of the struct node data


type */
struct node *nodeptr /* nodeptr is a pointer to an object of
struct node */

4. What are the differences between Stack and Queue data


structures ?

The main difference between the Stack and Queue data


structures is that the stack is a LIFO ( Last In First Out ) data
structure where as the Queue is a FIFO ( First In First Out ) data
structure. Because of this difference the Stack implementation
needs only one pointer namely the top for manipulation where as
the Queue needs 2 pointers the front to keep track of the first
element in the Queue and the Rear to keep track of the last
element in the Queue.

5. List all the sorting algorithms

Sorting algorithms can be classified as


• Simple sorting algorithms
o Bubble Sort
o Insertion Sort
o Selection Sort
• Complex sorting algorithms
o Quick Sort
o Merge Sort
o Heap Sort
While Quick Sort, Merge Sort and Heap Sort are complex
algorithms they are more efficient compared to the simple
sorting algorithms.
6. What is a pointer to a pointer ?

A pointer is variable that contains the address of another


variable.
A pointer to a pointer is a variable that contains the address of a
pointer variable.

The following example will illustrate the pointer to a pointer


concept

int *p; /* p is a pointer variable */


int **q; /* q is a pointer to a pointer variable */
int number = 100;

p = &number;
q = &p;

The diagram below illustrates the pointer to pointer concept

number p q

0x500 100 0x1000 0x500 0x2500 0x1000

number is an integer variable with value 100 located at


memory address 0x500

p is a pointer variable with value 0x500 ( address of


number ) located at memory address 0x1000

q is a pointer variable with value 0x1000 ( address of p )


located at memory address 0x2500

printf ( “\n The number de-referenced through the pointer is %d”,


*p );

printf ( “\n The number de-referenced through the pointer to


pointer is %d”, **q );
7. What are the steps in the compilation of a C program ?

The compilation of a C program is a simple process. Just to


compile a single file with a C program execute

$ cc program.c /* program.c is the name of


the file */

Normally the compilation is a 3 step process. First the C program


is converted into assembly language code. Then the assembly
code is converted to object code ( machine language ). The
object code is linked to the libraries by the linker and the
executable by name a.out is produced.

The C compiler does all of this when we execute the following


command :
$ cc program.c
$ ./a.out /* We are now running the
executable produced by
the compiler */
But if you wish you can do it in steps
$ cc –c program.c /* This produces the object file program.o */

You can now create the executable with the following command
$ cc –o result program.o /* This creates the executable result */
$ ./result /* We are now running the executable result */

8. Write a C program to print *’s in the following pattern


*
* *
* * *
* * * *
All you need is a sequence of printf statements to
print the specified pattern.

#include <stdio.h>

int main( )
{
printf ( “\n *\n”);
printf ( “ * *\n”);
printf ( “ * * *\n”);
printf ( “ * * * *\n”);
printf ( “ * * * * *\n”);
}
9. Compare and contrast iteration Vs recursion

TYPE ITERATION RECURSION


Speed Faster Slower because of
many recursive
function calls
Memory Less More because the
Usage stack grows in size
with each recursive
call
Nature of Most algorithms can be Some problems such
the solved iteratively. For all as tree algorithms are
problem such cases we will go recursive in nature.
through the iterative They are best solved
method. For a few where by Recursion. The
the nature of the problem algorithm can be
is recursive it is best to coded in just a few
solve it recursively. lines making it
compact and hence
less error prone
Examples Calculating the factorial of Tree traversing
a number algorithms, Generating
Fibonacci series,
Calculating the
factorial of a number

10. Things to keep in mind when you are posed with a coding
question

For code questions you will be given sufficient time to think and
write the code. Don’t be in a hurry to immediately start righting
the code. Think for sometime as to how you are going to
implement. First list out the steps of the algorithm that you are
going to implement. Then think about the boundary conditions
that you need to take care. This will let the interviewer know that
you are working methodically. Once you are clear with the steps
for implementing the algorithm writing the code is straight
forward task. Also documentation is an important process when
you write code. Even in your interview ensure that you place
some comment statements explaining the code statements. If
there is paucity of time then you may ask the interviewer if you
can skip the comment statements. Sometimes they themselves
may advice you that you can just explain and there is no need
for the comment statements. Follow your interviewer’s
instructions carefully in any case.

When you are asked to write code the interviewer is interested in


assessing you on the following :

• Thought process ( whether you are able to think about the


problem and the solution and come out with the steps for
the solution )
• approach ( whether it is methodical or not )
• grasp of the implementation language ( the way you code
will let him know your skills in the language )
• presentation skills ( the way you have written and your
explanation of steps to solve the problem )

11. Compare and contrast Arrays with Linked Lists

Let us answer this question with the help of a table. Again the
question can come in different forms so you need to have a
proper understanding of the table to answer the question.

TYPE ARRAYS LINKED LISTS


Speed of Faster because the array Slower because each
access memory locations are link has a pointer that
(say to contiguous needs to be accessed
search an to get the location of
element ) the next link and then
only can the next link
be accessed
Memory Less More because there is
Usage a pointer overhead
with each node in a
linked list
Flexibility Poor. Arrays are statically Very flexible. Linked
( say you allocated and hence are lists can grow and
want to fixed in size. They cannot shrink as required
add or grow or shrink during dynamically
delete execution time
elements )
Size Size is fixed at compile Size can grow as
time required dynamically.
Insertion & Complicated Easy
Deletion
12. Provide the implementation of the strlen standard library
function

Steps

1. Check if the pointer parameter passed is not null. If the


pointer parameter is null then print a statement informing
the condition and return 0. In literature it is mentioned that
passing a null string results in a segmentation fault
( memory violation ) when you use the strlen function from
the standard library.
2. Traverse the string character by character in a loop till you
encounter the null character ( \0 ). Keep updating the
count as you encounter each character. Finally on
encountering null exit the loop and return the count which
is actually the number of characters in the string.

int strlen ( char *str )


{
int count = 0;

/* Check for boundary condition */

if ( str == NULL )
{
printf ( “The string parameter is null\n” );
return 0;
}
/* Traverse the string in a loop */

while ( *str != ‘\0’ )


{
str++;
count++;
}
return count;
}
13. Write a program to find out if a given number is prime

Let us now write a program to check if a given number is a prime


number or not. First we define the problem:

Input the number n to be checked


Check if it is a prime or not
Output the result.

Now we have to elaborate the step-2, which is the method of


solution. It can be done by clearly understanding the problem
and then analyzing it to yield a method of solution.. For the
present problem a prime number is defined as a number that
cannot be divided by any other number than 1 and itself. That
means we should check if it is divisible by 2 to n-1. So what it
means is if we have a number like 10000 we have to check by
dividing with 2 to 9999. But the first factor for any number being
2 there is no point in checking beyond n/2 i.e. in this case
beyond 5000. Then you realize that if it can have 5000 as a
factor there will already be a factor 2 and for 2500 there is 4 and
so on and on reaching 100 the factors are equal and 100 is the
square root of 10000. So for any given number we need to
check only up to the root of the number because if there is no
factor below the root of the number there cannot be a factor,
which is above the root of the number. That saves us a lot of
calculation. In this case instead of checking 9999 times we need
to check only 99 times. So the real job of programming is to
analyze the problem and get the best method of solution and
then the algorithm can easily be developed.

To check if a number is divisible, we find the remainder of a


division. If the remainder is zero it is divisible otherwise it is not
divisible. So we check for 2 onwards; if found not divisible we go
on checking up to the root of the number. If it is found divisible
by any number then we stop checking and output is printed
stating that the given number is not a prime and that number is
the first factor. Otherwise after checking up to the root of the
number we say it is a prime number.
#include <stdio.h>
#include <math.h>
int main()
{
int i,k,l,irt;
system(“clear”);
printf("enter the number : ");
scanf("%d",&i);
system(“clear”);
irt=sqrt(i)+1;
for(l=2;l<irt;l++)
{
k=i%l;
if(k==0)
{
printf("\n%d is not a prime",i);
printf("\n\n%d is the first factor",l);
break;
}
}
if (k!=0)printf("\n %d is a prime",i);
}

Since this includes the math functions we have to specifically link


the math library while doing the compilation for this file

$ gcc <filename> -lm ( It is not 1m (one m) but lm (el m)

14. Can you improvise upon the basic algorithm (where you will
be checking from 2 upto square root of the number) for
finding a prime number ?

A careful study of the basic algorithm (previous program)


shows that once we check with 2 and if 2 is not a factor
there is no point in checking for any other even number.
Hence we can modify the algorithm and the number of
checks will reduce by half the earlier case. And to avoid
having to compile the program every time we will use the
do-while loop which will terminate only after all the data is
checked. This algorithm will check for 2 and if not divisible
then check only for all odd numbers up to the root of the
number.

int main()
{
int i,k,l,irt;
char chk;
do
{
system(“clear”);
printf("enter the number : ");
scanf("%d",&i);
system(“clear”);
irt=sqrt(i)+1;
k=i%2;
if (k==0)
{
printf("\n%d is not a prime",i);
printf("\n\n 2 is the first factor");
}
else
for(l=3;l<irt;l+=2)
{
k=i%l;
if(k==0)
{
printf("\n%d is not a prime",i);
printf("\n\n%d is the firstfactor",l);
break;
}
}

if (k!=0) printf("\n %d is a prime",i);


if (getchar() == '\n');
printf("\n Do you have anymore data y/n: ");
scanf(“%c”,&chk);
} while(chk=='y');
return 0;
}
15. List all the prime numbers from 1 to n where the value of n
will be provided by the user

#include <stdio.h>
#include <math.h>
int main()
{
int i,k,l,irt,m,count;
system("clear");
printf("Determine prime numbers upto : ");
scanf("%d",&m);
system("clear");
count=0;
for(i=2;i<m;i++)
{
k=i%2;
if (k!=0)
{
irt=sqrt(i)+1;
for(l=3;l<irt;l+=2)
{
k=i%l;
if(k==0)break;
}
}
if (k!=0)
{
printf("%d\t",i);
count++;
if ((count%100)==0)printf("\n\n");
}
}
printf("\n total number of prime numbers : %d ",count);
}

16. List all the factors of a given number n

#include <stdio.h>
#include <math.h>
int main()
{
int i,k,l,irt,fact;
system("clear");
printf("enter the number : ");
scanf("%d",&i);
system("clear");
printf(" The factors of %d are: \n", i);
irt=sqrt(i)+1;
for(l=1;l<irt;l++)
{
k=i%l;
if(k==0)
{
fact=i/l;
printf("\n%d \t%d ",l,fact);
}
}
return 0;
}
17. Implement the recursive version of the Fibonacci series

static int FibonacciRecursive(int n)


{
if (n == 0)
return 0;
if (n == 1)
return 1;
return FibonacciRecursive(n - 1) +
FibonacciRecursive(n - 2);
}

18. Implement the iterative version of the Fibonacci series


static int FibonacciIterative(int n)
{
int prevPrev = 0;
int prev = 1;
int result = 0;

if (n == 0)
return 0;
if (n == 1)
return 1;

for (int i = 2; i <= n; i++)


{
result = prev + prevPrev;
prevPrev = prev;
prev = result;
}
return result;
}
19. Implement the recursive version of finding the factorial of a
number

static int FactorialRecursive(int n)


{
if (n <= 1) return 1;
return n * FactorialRecursive(n - 1);
}

20. Implement the iterative version of finding the factorial of a


number
static int FactorialIterative(int n)
{
int sum = 1;
if (n <= 1)
return sum;
while (n > 1)
{
sum *= n; n--;
}
return sum;
}

21. Provide the output for the following code snippet

#include <stdio.h>
int main( )
{
int x,y, z;
x=2;
y=5;
z= x+++y;
printf("%d %d %d", x, y z);
return 0;
}

3 5 7

22. What is the output of the following code snippet ? Show the stack
contents during the execution.

#include <stdio.h>

int giValue = 5;
void fnReverse()
{
if (giValue > 0) {
giValue--;
fnReverse();
}
printf("%d\t", giValue);
}

int main()
{
fnReverse();
return 0;
}
Since there are no local variables and function parameters there will
be nothing in the stack except the return address. giValue is a
global variables and hence it will be defined in the data segment
and not in the stack. Since each time we call fnReverse we are
decrementing the global variable giValue when we finally print the
value of giValue the output will be :

0 0 0 0 0 0 ( 0 printed 6 six times )

Here we have to remember that had giValue been a local variable of


fnReverse then the output will be totally different since it will be
stored in the stack and only that value will be printed.

23. Which case statement will be executed in the following code ?


#include <stdio.h>
int main()
{
int i =1;
switch(i)
{
i++;
case 1 : printf ("One");
break;
case 2 : printf("Two");
break;
default : printf("Default");
break;
}
return 0;
}

Since the value of i is 1 the statements in case 1 will be


executed. The i++ inside the switch will have no effect. It will not
be executed at all. So the output of this program is :

One
24. The char has 1 byte boundary , short has 2 byte boundary,
int has 4 byte boundary. What is the total no. of bytes consumed
by the following structure:

struct st {
char a;
char b;
short c;
int z[2];
char d;
short f;
int q;
};

If you add all the bytes as per the data types in the structure
then the total number of bytes consumed by the structure will be
1 + 1 + 2 + 2 * 4 + 1 + 2 + 4= 19 bytes

But alignments are preserved with padding. This means that a


short int can only start at an even address and an int can only
start at an address that is a multiple of 4. Thus the above
structure will be allocated as shown in the figure below and the
total number of bytes = 20

a b c

z[0]

z[1]

d f

25. Print the output from the following code snippet

#include <stdio.h>
#define swap(a,b) temp=a; a=b; b=temp;

int main( )
{
int i, j, temp;
i=5;
j=10;
temp=0;
if( i & j)
swap( i, j );
printf( "%d %d %d", i, j, temp);
}

The output is : 10 0 0

26. How many times is the loop executed ?

#include <stdio.h>
int main()
{
int i=3;
while(i>=0)
printf("%d",i--);
return(0);
}

The loop will be executed 4 times ( for values i=3, 2, 1, 0 )

27. Give the output for the following program

int main()
{
int s[]={1,2,3,4,5,6};
printf("%d",&s[5]-&s[0]);
return 0;
}

Since it is an integer array the output will be : 20

8 &s[5] = 20
&s[0] = 0
12
&s[5] - &s[0] = 20 – 0 = 20
16

20
28. What is the task of the C preprocessor ?

Pre-processing is the phase prior to the actual compilation.


The pre-processor does the following tasks :

• Macro Substitution ( #define statements )


• Conditional Compilation using #if statements
• File inclusion

29. How can I convert integers to Binary or Hexadecimal ?

For Decimal to Binary conversion we divide by 2 and for


Decimal to Hexadecimal conversion we divide by 16

Convert 10 to Binary

2 10

2 5 0

2 2 1

0
1

From the figure it is clear that 1010 is the binary


representation for 10.

Convert 50 to hexadecimal

16 50

3 2
0x32 is the hexadecimal equivalent of decimal 50

30. How will you convert binary and hexadecimal numbers


back to decimal notation ?

It is much more simpler than conversion from decimal to binary


and hexadecimal.

For e.g., to convert 1010 to decimal start from the least


significant bit (LSB)

0*2^0+1*2^1+0*2^2+1*2^3=0+2+0+8=
10

Similarly to convery 0x32 into decimal start with the least


significant bit

2 * 16 ^ 0 + 3 * 16 ^ 1 = 2 + 48 = 50

31. What is a volatile variable ?

A volatile variable is one whose value changes unexpectedly


without any statements being executed involving the variable.
Basically these variables let the compiler know that their values
cannot be predicted based on code execution alone and hence
they are not candidates for optimization.

32. Give a fast way to multiply a number by 7

We have to use the shift operators to achieve this. Left shift by a


bit is equivalent to multiplication by 2. To multiply a number by 7
left shift by 3 bits which is equivalent to multiplication by 8 and
then subtract the number once.

For e.g., to multiply 10 * 7 left shift 10 by 3 bits.

10 ( 0000 1010 ) => 80 ( 0101 0000 )

Since you are multiplying by 8 subtract the number once which


will actually mean multiplication by 7

 80 – 10 = 70 which is what we want.


33. What is a function pointer ? How do you declare it ? How would
you use it ? Where would they be useful ?

A function pointer as the name suggests is a pointer to a


function.

int (*funcptr) ( ); /* function pointer declaration */

funcptr is a pointer to a function that takes no arguments


and returns an int

Suppose we have a function with the prototype


int f1 ( );

Then we can assign the address of f1 to the function


pointer.
funcptr = &f1;

If we want to call the function using the function pointer


then
(*funcptr) ();

or simply

funcptr ();

If we want to execute different functions based on a


certain condition then we could use function pointers.

34. Specify the output of the following program

#include <stdio.h>

void fnReverse(int iValue)


{
(iValue > 0) {
Reverse(iValue-1);
}
printf("%d\t",iValue);
}

int main()
{
int ivalue = 5;
fnReverse(ivalue);
return 0;
}
35. What is a sparse file ?

Sparse file is concept where the disk space is utilized more


efficiently by storing only the blocks which have real data.
The empty blocks are not actually stored but only the
information on where they appear in the file ( offset ) is
stored. This is required because during a read or a write
operation all the blocks need to be reproduced in the
required order whether they contain real data or not.

$ ls -l sparse.file

-rw-r--r-- 1 hgo staff 102400 Jan 13 15:52 sparse.file

$ du -h sparse.file

8K sparse.file

The ls command shows a file size of 102400 bytes, but the


du command shows only of 8 KB of allocated disk space.

36. In the Linked list shown below how can I delete node C
while I provide only the starting address of node C ?

A B C D

Though it looks like it is not possible to do that given only


the starting address of Node C there is another way of
doing what we want. For deleting Node C we need to know
the address of Node B ( prev node ). Then only can we
make the link of Node B point to Node D. But there is no
way of knowing that. Here is a trick to do it.

Since we have the address of Node C we can easily


traverse to Node D. Copy the contents of Node D to Node C
and copy the pointer field of Node D to Node C and delete
Node D. Have we not accomplished what we want ?

( Be prepared to write code for doing this in case they ask


you to )
37. Draw the memory organization of a C program in execution
( process ) ?

Command Line Arguments & Environment Variables

STACK
( Function parameters & Local Variable)

HEAP ( Dynamic Memory )

DATA ( Global Variables )

TEXT
( Contains the program code )

38. Where do we use the extern qualifier ?

Global variables can be used in files other than where they


are defined by using an extern qualifier meaning that they
are defined externally.

/* file1.c */

int token; /* token is defined in file1.c */

/* file2.c */

extern int token; /* this means that we


will be accessing
and/or modifying
token which has
been defined in
another file */

39. Difference between break and continue statements ?

Break is used to terminate a case within the switch


statement. It is also used to break out of loops when we
encounter an exit condition inside a loop.

Continue statement is used to start a new iteration of the


loop. When we encounter a continue statement in the
middle of the loop we skip the remaining statements within
the loop and start the next iteration.

40. When do we use static variables ?

Static variables defined inside a function retain their values


even after the execution exits the function. Static variables
defined outside the function have file scope. In situations
where we do not wish to use global variables but we want
to have the flexibility of global variables we would go for
static variables.

41. What is the difference between const char *p, char const
*p, const char * const p ?

const char *p (or) char const *p

This is the declaration of a pointer to a character constant.


This means that while the pointer can be modified to point
to some other variable the pointed to cannot be modified.

char * const p

This is the declaration of a constant pointer to a character.


This means that the pointer cannot be modified to point to
some other variable while the variable itself could be
modified.

const char * const p


This is a declaration of a constant pointer to a constant
character. It means that neither the pointer can be
changed nor the pointer to variable.

42. How would you implement variable argument functions ?

Variable arguments functions take variable arguments. For


e.g., the standard library function printf can take as many
arguments that need to be printed. This is only possible by
scanning the argument list containing the type of the
argument. The variable argument functions such as va_list,
va_start, va_args and va_end help us in scanning the
assigning the variable arguments to print them out.

43. What is the most efficient way to count the bits that are set
in a value ?

The following function counts the number of bits that are


set in a particular number x that is passed as a parameter

int number_of_bits_set(unsigned int x)


{
int count=0;
while(x)
{
count++;
x = x&(x-1);
}
return count;
}

44. We have a list of names separated by commas as one


string. Is there any way we can separate the names from the list.

This can be done in several ways namely by character


manipulation, using the string library functions etc. Here we have
provided one such implementation using the strtok library
function. Strtok is a very useful function for splitting strings
based on delimiters. In this case we are splitting a string based
on the delimiter comma(,).

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
FILE *fp;
char c, *p;
int count = 0;
char buffer[1000];

fp = fopen("file1", "r");

if ( fp == NULL )
{
printf("\n File could not be opened in read mode");
exit(1);
}

c = fgetc(fp);
while ( c != EOF )
{
buffer[count++] = c;
c = fgetc(fp);
}
buffer[count] = '\0';

p = strtok(buffer, ",");
while ( p != NULL )
{
printf("\n The string is %s", p);
p = strtok(NULL, ",");
}
return 0;
}

45. Write a C program to multiple a ( 3 X 3 ) matrix with a ( 3


X 3 ) matrix to produce a ( 3 X 3 ) matrix

A (3 X 3) matrix multiplied with a (3 X 3) matrix will produce a (3


X 3) matrix as result.
#include <stdio.h>
#define NUM_ROWS 3
#define NUM_COLS 3

void matrix_multiply(int A[][NUM_COLS], int B[][NUM_COLS], int


C[][NUM_COLS])
{
int i, j, k;
for ( i = 0; i < NUM_ROWS; i++ )
{
for ( j = 0; j < NUM_COLS; j++ )
{
for ( k = 0; k < NUM_ROWS; k++ )
{
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
}
}
}

int main()
{
int A[NUM_ROWS][NUM_COLS] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int B[NUM_ROWS][NUM_COLS] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int C[NUM_ROWS][NUM_COLS] = { 0 };
int i, j;

printf("\n");

matrix_multiply(A,B,C);
for ( i = 0; i < NUM_ROWS; i++ )
{
for ( j = 0; j < NUM_COLS; j++ )
{
printf("A[%d][%d] = %d\t", i, j, C[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}

46. What is the difference between library functions and


system calls ?

Library functions are provided to us in the form of libraries so


that we can use them instead of writing our own code. We do not
want to reinvent the wheel. Also library functions have been
implemented efficiently and they are devoid of bugs. So it is
safer and prudent on our part to use them. Library functions may
internally call system calls to achieve what we want. To illustrate
this we can consider the fopen library function which is built on
top of the open system call. So in this case the library function
acts as a wrapper over the system call to interface with the
operating system. Also the library function hides certain details
and only provides the necessary interface and thus is user
friendly.

LIBRARY FUNCTION (fopen)


SYSTEM CALL (open)
OPERATING SYSTEM
(Linux)HARDWAR
E (PC)

For e.g., strlen, strcpy, strcmp, toupper, fopen etc. are library
functions

System calls on the other hand are the means available for the
programmer to interact with the operating system which in turn
talks to the hardware and get things done. The open system call
is a good example. It helps in opening an existing file and can
even create one if there is no such file. Thus we can specify
various attributes in the open system call for various
functionality. Ultimately it opens a file stored in the disk by
interacting with the hardware through the operating system.

For e.g., open, read, write, fork etc. are system calls

47. Suppose I am using a system call. How will I know the


following details ?

a) Whether the system call was successful or


not ?
b) If it was not successful then what is the reason
System calls are supposed to return -1 on failure and 0 on
success. Just by examining the return value we will know
whether the system call was successful or not.

Also there is global variable called errno which gets set to a pre-
defined number (depending on the failure). After the system call
is executed we can examine this global variable errno and also
print the string corresponding to the value contained in errno
variable. To illustrate the mechanism of how to use errno to
know if the system call is successful (or) not we provide a small
program below.

#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno;
int main()
{
FILE *fp;
char c, *p;
int count = 0;
char buffer[1000];

printf("\n Value of errno before fopen = %d", errno);


fp = fopen("file1", "r");
printf("\n Value of errno after fopen = %d", errno);
printf("\n %s", strerror(errno));
if ( fp == NULL )
{
printf("\n File could not be opened in read mode");
exit(1);
}
return 0;
}

We are using the library function which in turn uses the system
call open. When we did not have a file by name “file1” in the
current directory this is the output from the program.

********************************************************
$ ./a.out

Value of errno before fopen = 0


Value of errno after fopen = 2
No such file or directory
File could not be opened in read mode
********************************************************
As we can clearly see from the output the value of the global
variable was initially 0. But the fopen library function and
ultimately the open system call failed because the file was not
available. Then at that point the value of errno got set to the
value 2. And the actual error string can be printed by the strerror
function by passing the value of the errno variable. And the
string printed by the strerror function corresponding to the value
2 is “No such file or directory”. Then subsequently we print
another error message “File could not be opened in read mode”.

48. Suppose you have a doubly linked list in which a singly linked list
is embedded what will be the issues ?

A B C D

Here the problem is the doubly linked list is broken in the reverse
direction. We can traverse all the way to the last node in the
forward direction but not in the reverse. Again insertion between
Nodes B & C means that we have to have a pointer save the
previous node address. Deletion of nodes B, C have to be handled in
a special manner.

49. What are the storage classes in C ?

There are 4 different storage classes in C. They are


1. Auto : These are local to functions. They become out of scope as
we exit the functions where they are defined.
2. Extern : These are global variables which can be accessed from
files other than where they are defined. They have external
linkage unlike static variables whose linkage is internal. They can
be accessed and modified in files other than where they are
defined.
3. Static : Static variables can be defined within a function(local) or
outside of the function(global). Local static variables are invisible
outside the function but they tend to retain their previous values
on re-entry to the same function. On the other hand global static
variables have file scope (internal linkage). They can be
accessed/modified by any function in that file. The advantage of
using global static over global is that their use is restricted to the
file where they are defined and other files cannot attempt to
use/modify them. So tracking their usage becomes a lot easier
compared to global variables whose linkage is external.
4. Register : These are supposed to assigned to CPU registers
instead of memory. Hence access is very fast and code that uses
register variables for loop control variables can significantly
speed up the operations. But we cannot be sure that register
variables are assigned to CPU registers as the availability of CPU
registers is subject to many other factors. The only way we can
determine if they are allocated to the CPU registers is by
profiling. Then we can know the execution time. If there is a
significant difference in the execution times between using
register Vs auto variables then we can conclude that they have
indeed been allocated to the CPU registers. Since register
variables are supposed to be available in CPU registers we
cannot use the address operator(&) on those variables.

50. How will you find if a number is even or odd in just one
statement ( without using if statement )

We can use the ternary operator to determine if a number is


even (or) odd.

return ( (number%2)? 1:0);

If we return 1 then the number is odd else it is even

51. Provide the output for the following C program. In case of


errors clearly state which statement causes the error.

#include <stdio.h>

int main()
{
int a, b, temp;
b = ( a = 20, a + 10 );
printf(“a = %d and b = %d (before)\n”, a ,b );
temp = a, a = b, b = temp;
printf(“a = %d and b = %d (after)\n”, a ,b );
return 0;
}

This example illustrates the use of the comma operator. When a


comma operator is used the value of the last expression is
assigned to the variable on the left. The output is :
a = 20 and b = 30 (before)
b = 30 and a = 20 (after)

52. Provide the output for the following program ?

#include <stdio.h>

int main()
{
int a= 10, b = 2, c = 15;
a = a && b || c;
b = a ||b && c;
c = a && b && c;
printf(“%d %d %d”, a, b, c );
}

In a logical expression everything bolis down to either true (1) or


false (0). In this case since && and || both have the same priority
we have to evaluate the expression from L to R.

a && b = 10 && 2 => True (1)


a && b || c = 1 || 15 => True (1)

Similarly we can evaluate the other expressions. The final output


is :

1 1 1

53. Convert the following infix expression into postfix. Show


the stack after each operation.

Infix Expression : (a+b)*c/d-e+f/(g-h)*k

While converting from infix to postfix we proceed from the left


most character of the infix expression. Initially the stack is
empty.

Examination of character (

 Push it onto stack


(

Examination of character a

 Output the character


 Output Postfix Expression : a

Examination of character +

 Push it into the stack

Till we encounter the matching right parenthesis we will push all


the operators onto stack following the rules for operators and all
operands will be pushed on the output ( postfix expression )

Examination of character b

 Output the character


 Output Postfix Expression = ab

Examination of character )

=> When we encounter matching right parenthesis we pop out


all the operators from the stack till the left parenthesis and add it
to the output postfix expression. Then we pop out the left
parenthesis and discard it. So after this operation the stack is
empty again

 Output postfix Expression : ab+

Examination of character *
 It is an operator and stack is empty. So push it into the stack
*

Examination of character c
 Output the character
 Output Postfix Expression = ab+c
There is no change in the stack contents

Examination of character /
 Now there is already an operator * at the top of the stack.
Since / has equal priority to * we have to pop out * on to the
output expression and then push / into the stack
 Now the output postfix expression = ab+c*
 And the stack status is shown below

Examination of character d
 Output the character
 Output Postfix Expression = ab+c*d
There is no change in the stack contents

Examination of character -
 Now there is already an operator / at the top of the stack.
Since – has lower priority to / we have to pop out / on to the
output expression and then push - into the stack
 Now the output postfix expression = ab+c*d/
 And the stack status is shown below

__

Examination of character e
 Output the character
 Output Postfix Expression = ab+c*d/e
There is no change in the stack contents

Examination of character +
 Now there is already an operator - at the top of the stack.
Since – has equal priority to + we have to pop out - on to the
output expression and then push + into the stack
 Now the output postfix expression = ab+c*d/e-
 And the stack status is shown below

Examination of character f
 Output the character
 Output Postfix Expression = ab+c*d/e-f
There is no change in the stack contents

Examination of character /
 Now there is already an operator + at the top of the stack.
Since / has greater priority than + we have to push / onto the
stack
 Now the output postfix expression = ab+c*d/e-f
And the stack status is shown below

Examination of character (
 Push it into stack
 And the stack status is shown below

Examination of character g
 Output the character
 Output Postfix Expression = ab+c*d/e-fg
There is no change in the stack contents

Examination of character -
 Push it into the stack. All operators till we come across the
right parenthesis will be pushed into the stack
 Output Postfix Expression = ab+c*d/e-fg
 And the stack status is shown below
_

Examination of character h
 Output the character
 Output Postfix Expression = ab+c*d/e-fgh
There is no change in the stack contents

Examination of character )

 When we encounter matching right parenthesis we pop out


all the operators from the stack till the left parenthesis and
add it to the output postfix expression. Then we pop out the
left parenthesis and discard it.
 Output postfix Expression : ab+c*d/e-fgh-
 And the stack status is shown below

Examination of character *
 Now there is already an operator / at the top of the stack.
Since * has equal priority to / we have to pop out / on to the
output expression and then push * into the stack
 Output postfix expression = ab+c*d/e-fgh-/
 And the stack status is shown below

+
Examination of character k
 Output the character
 Output Postfix Expression = ab+c*d/e-fgh-/k
There is no change in the stack contents

Now there are no more characters in the infix expression. We


have to now pop out characters from the stack and add them to
the output expression.

Hence the ultimate postfix expression


= ab+c*d/e-fgh-/k*+

One of the important applications of stack is the infix to postfix


conversion. From this example it is evident how the LIFO data
structure helps in the conversion. Summing up we can
summarize the algorithm as follows :

1. If it is an operand just output the operand to the output


postfix expression
2. If it is a left parenthesis keep pushing all the operators into
the stack obeying the rules for the operators listed in rule 4.
3. If it is a right parenthesis keep popping the stack contents and
add them in the pop order to the output postfix expression till
you reach the left parenthesis. Pop out and discard the left
parenthesis
4. If it is an operator check the top of the stack.
o If it is empty push it into the stack
o If the top of the stack has an operator that is of lower
priority than the current operator then push the current
operator in on top of the existing operator
o If the top of the stack has an operator that is of equal or
higher priority than the current operator then pop out
the operator from the top of the stack and add it to the
output postfix expression. Then push the current
operator into the stack
5. If there are no more characters in the input infix expression
then pop out the stack and add the contents to the output
expression in the pop order.

54. Convert the following infix expressions into postfix : ((a+b)*c)/d-


((e+f)/(g-h))*k. Show the contents of the stack during the
conversion

55. What is the output for the following program ?


#include <stdio.h>
struct node
{
char c;
int i;
float f;
double d;
};

union unode
{
char c;
int i;
};

int main()
{
struct node node1;
union unode u;
printf("\n %d \t %d", sizeof(struct node), sizeof(node1));
printf("\n %d \t %d", sizeof(union unode), sizeof(u));
u.c = 'A';
printf("\n %c \t %d", u.c, u.i);
u.i = 65;
printf("\n %d \t %c\n", u.i, u.c);

return 0;
}

The output is :
20 20
4 4
A <undefined value>
65 A
Since the fields of the union are int and char the size will be
allocated
to hold the biggest (int) and hence the size of the union is 4 bytes.

When we assign the value ‘A’ to u.c only the LSB will be assigned
with the ascii value for A (65). We don’t know what will be there in
the other 3 bytes. Hence we have specified as undefined value. On
the other hand when we assign the value 65 to u.i the entire 4 bytes
gets initialized as follows : Hex (values) => 00 00 00 41 => 65
(Decimal). When we read it as a character it reads only the LSB byte
which is 65. This should explain why we get a proper value when we
assign an integer but not when we assign a character.

56. How would you figure out if your machine is Big Endian or
Little Endian ?

When we have some bytes in memory as shown in the figure the


values are interpreted differently for Little Endian and Big Endian

0 0x01

1 0x02

2 0x03

3 0x04

From the memory map we can figure out how the bytes will be
interpreted for Little Endian and Big Endian.

For little endian the LSB will correspond to the lowest address and it
will proceed in that order. So we interpret the value of the integer in
hex as 0x04030201

For big endian the lowest address will correspond to the MSB and so
on. Hence the value will be interpreted as 0x01020304

A small program ( in C ) can help us determine if our machine is Big


Endian or Little Endian. This program was executed in a Linux
machine and it came up with the result as Little Endian

int main()
{
int *p;
char buffer[4] = { 0x01, 0x02, 0x03, 0x04 };
p = (int *) buffer;

printf("\n p = %x \t *p = %d", p, *p);


printf("\n p in hex = %x", *p);
return 0;
}

The output from the program was :


p = bfae2c7c *p = 67305985
p in hex = 4030201

As we can see when we print the value of p in hex the LSB is the
littlest. Had our computer been Big Endian then p in hex will be
1020304

57. Write a program to reverse a linked list

void reverse_ll(DLLPTR *start)


{
DLLPTR temp, temp1;
if ( *start == NULL )
{
printf("\n There are no nodes in the list.\n");
}
temp = (*start)->next;
temp1 = *start;
temp1->next = NULL;

while ( temp != NULL )


{
temp1 = temp;
temp = temp->next;
temp1->next = *start;
*start = temp1;
}
}

58. What is the output for the following program ?


#include <stdio.h>
typedef struct {
char *a;
char *b;
char *c;
} colors;

void funct(colors sample)


{
sample.a = “cyan”;
sample.b = “magenta”;
sample.c = “yellow”;
printf(“%s %s %s\n”, sample.a, sample.b, sample.c );
}
int main()
{
static colors sample = { “red”, “green”, “blue” };
printf(“%s %s %s\n”, sample.a, sample.b, sample.c );
funct(sample);
printf(“%s %s %s\n”, sample.a, sample.b, sample.c );
return 0;
}
The output for the program will be :
red green blue
red green blue

59. Write a program to compare 2 strings without using the


strcmp function

#include <stdio.h>
#include <string.h>
#define SIZE 80

int strcmp(const char *string1, const char *string2)


{
int i, len1, len2, len;

len1 = strlen(string1);
len2 = strlen(string2);
len = (len1<len2)?len1:len2;
for ( i=0; i<len; i++ )
{
if ( string1[i] > string2[i] )
return 1;
else if ( string1[i] < string2[i] )
return -1;
else
continue;
}
if ( len1 == len2 )
return 0;
else if ( len1 > len2 )
return 1;
else
return -1;
}

int main()
{
int result;
char string1[SIZE];
char string2[SIZE];
printf("\n Enter string 1 :");
scanf("%s", string1);
printf("\n Enter string 2 :");
scanf("%s", string2);
result = strcmp(string1, string2);
if ( result == 0 )
printf("\nBoth the strings are equal.");
else if ( result == 1 )
printf("\n String1 %s is greater than String2 %s",
string1, string2);
else
printf("\n String1 %s is lesser than String2 %s",
string1, string2);
return 0;
}

60. How do you insert elements into a binary search tree ?

In a Binary search tree each node can have only 2 children


the left child and the right child. At first we create the root
node with the user input. Then for each value provided we
check if that value is lesser than the root. If yes then we
insert the node into the left sub tree. Else we insert it into
the right sub tree. We follow this process recursively. The
following example will clearly illustrate the procedure.

Suppose the user provides the following numbers to be


inserted into the Binary Search Tree (BST) :

25, 90, 28, 12, 100, 11, 15

Step 1

Since the tree is empty insert 25 as the root node as shown


below
25

Null Null

Step 2

The next element to be inserted is 90. Since 90 > 25 it will


be inserted as the right child of the root node as shown
below.

25
25

Null 90
Null 90

Null Null
Null Null
Step 3

The next element to be inserted is 28. Since 28 > 25 it will


be inserted on the right sub tree. But there is already a
node (with value 90) on the right subtree. So we compare
28 with 90. Since 28 < 90 it will inserted in the left sub tree
of 90.

25

Null 90

28 Null
Step 4

The next element 12 will be inserted into the left subtree of


root as 12 < 25

25

90
12

28 Null

Step 5

25, 90, 28, 12, 100, 11, 15

25
The final shape of the tree after all the insertions will be

90
12

10
11 15 28 0
61. Write a program that accepts user input and creates the
nodes in a binary search tree

The function insert node behaves according to the algorithm


mentioned in previous question. The data structures, main
function and the inorder traversal algorithms are also provided
so that it can be tested.

struct bsearchtreenode
{
int data;
struct bsearchtreenode *left;
struct bsearchtreenode *right;
};

typedef struct bsearchtreenode BSTNode;


typedef BSTNode *BSTNodeptr;

void insert(BSTNodeptr *root, int value)


{
BSTNodeptr temp, temp1, temp2;
temp = (BSTNodeptr) malloc(sizeof(BSTNode));
temp->data = value;
temp->left = NULL;
temp->right = NULL;
if ( *root == NULL )
{
*root = temp;
}
else
{
temp1 = *root;
while ( temp1 != NULL )
{
temp2 = temp1;
if ( value < temp1->data )
{
temp1 = temp1->left;
}
else
{
temp1 = temp1->right;
}
} /* end while */
if ( temp1 == NULL )
{
if ( value < temp2->data )
{
temp2->left = temp;
}
else
{
temp2->right = temp;
}
} /* end if */
} /* end else */
} /* end insert function */

void inorder_traversal(BSTNodeptr root)


{
if ( root != NULL )
{
inorder_traversal(root->left);
printf("\n Value = %d", root->data);
inorder_traversal(root->right);
}
}

int main()
{
int value;
BSTNodeptr root = NULL;
printf("\n Enter value of node to insert in BST (-1 to end) :
");
scanf("%d", &value);
while ( value != -1 )
{
insert(&root, value);
printf("\n Enter value of node to insert in BST (-1 to
end) : ");
scanf("%d", &value);
}
inorder_traversal(root);
return 0;
}

62. I am getting a segmentation fault. How can find out where


the problem is ?

Segmentation fault occurs when there is a memory


violation. Usual reasons are null pointer access. For e.g.,
you will be accessing data through a pointer when it
actually points to NULL. For e.g., let us take a linked list
structure

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

Assuming we are in a while loop where we move the


pointer from one node to the next. When the ptr becomes
null we have actually reached the end of the list. But if we
forget to do this check we end up accessing data through a
null pointer.

Assuming temp is a pointer to struct node if we have a


statement

If ( temp-> data < 10 ) when temp is null

This will cause segmentation fault.

Now that we have a segmentation fault how do we correct


it ?
We have 2 options.

1. Use the debugger


2. Generously use the printf statement all over the code to
figure out which statement is causing the segmentation
fault.
Here we shall see the steps on how to use GDB to debug
our program

1. Before we use GDB we have to compile out code with


the –g option so that debugging information will be
available when we invoke the debugger. When we
compile with the debugger option the executable is
bigger. So compile with –g option only when you need to
use the debugger

2. $gcc –g <samp56.c> /* samp56.c is the file I am


compiling */

3. Step 2 creates the default executable file a.out

4. To invoke the debugger type gdb a.out. This invokes the


debugger and comes up with the GDB prompt (gdb).
Now we know that we can issue the GDB commands

$ gdb ./a.out
GNU gdb Red Hat Linux (6.5-16.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General
Public License, and you are
welcome to change it and/or distribute copies of it under
certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show
warranty" for details.
This GDB was configured as "i386-redhat-linux-
gnu"...Using host libthread_db library
"/lib/libthread_db.so.1".

(gdb)

5. Now we want to place a breakpoint in main ( entry to


the program ). It comes up with a response telling us
that the breakpoint has been placed in the main
function.

(gdb) break main


Breakpoint 1 at 0x80484e9: file samp56.c, line 72.
(gdb)

6. Now run the program. It stops at the first executable


statement inside main since we have placed a
breakpoint in main. You can get to any of your functions
from main. But you can also specifically insert
breakpoints in particular functions that you have
written.

(gdb)run
Starting program:
/home/staff/aitec/cir/v_bhaskaran/cprgms/a.out

Breakpoint 1, main () at samp56.c:72


72 BSTNodeptr root = NULL;
(gdb)

7. Now you can use either n ( for next ) or s ( for step ) to


execute each statement. The difference between them
is that using s will step into functions that you call from
main and also other functions called within functions. If I
know that I have to examine a particular function then I
would use s when I encounter the call to that function,
Else I would use n. n will execute the entire function as
if it is a single statement. Using n is faster but we have
to use s in the function that we know is the culprit so
that we can step into each and every line in that
function.

8. To print values we can use the p (for print) followed by


the variable we would like to print

(gdb) p root
( We are trying to see if root has been assigned the null
value )

9. If you want to examine the stack at any point of time


you can use the backtrace command. That lists the
stack contents for you to trace where you are. When I
am in the insert function I check to see the stack’s
content with a backtrace command. The command and
the response are shown below.

(gdb) backtrace
#0 insert (root=0xbfc5ddac, value=25) at samp56.c:17
#1 0x08048523 in main () at samp56.c:77
(gdb)
10. Once you are done you can quit the debugger by
typing quit at the gdb prompt

(gdb) quit
The program is running. Exit anyway? (y or n) y
$

63. Write a macro for swapping 2 integers

#define swap(a,b) a=a+b;b=a-b;a=a-b;

We can also do the same thing in a function. There is


another way to do the same thing. We can use the XOR
operator to swap 2 variables without using a 3rd variable.

a = a ^ b;
b = b ^ a;
a = a ^ b;

64. Show the memory layout of the structure variable

static struct {
unsigned a:5;
unsigned b:5;
unsigned c:5;
unsigned d:5;
unsigned e:5;
unsigned f:5;
unsigned g:5;
unsigned h:5;
unsigned i:5;
} v = { 1, 2, 3, 4, 5, 6, 7, 63, 9 };

65. Show the memory layout of the following structure variable

static struct {
unsigned a:5;
unsigned b:5;
unsigned c:5;
unsigned d:5;
unsigned e:5;
unsigned f:5;
unsigned g:5;
unsigned :0;
unsigned i:5;
} v = { 1, 2, 3, 4, 5, 6, 7, 8 };

66. Do the following for the user-entered number of students.


Find the average marks for a student of his marks in 3 subjects.
Print whether he passed or failed. A student will fail if his average
is less than 50. Use for loop

67. Do the following for an unknown number of students. (User


will explicitly indicate when to terminate). Find the average
marks for a student of his marks in 3 subjects.Print whether he
passed or failed. A student will fail if his average is less than 50.
Use While loop.

68. Write a program, that accepts a integer from the user and
print the integer with reverse digits. For eg: rev(1234) = 4321

69. Develop a calculator program which will use functions to


add/subtract/divide/multiply 2 numbers. Code the functions as
different source files and link them.

70. Write a function, which checks whether one string is a sub-


string of another string.

71. Write a program, which checks for duplicate string in an


array of strings.

72. Write a program, which checks for duplicate string in an


array of strings.

73. Write a program that will accept a string and character to


search. The program will call a function, which will search for the
occurrence position of the character in the string and return its
position. Function should return –1 if the character is not found in
the input string.

74. Write a program to convert a number in decimal system to


binary system. Hint: use recursion.

75. The librarian in a library wants an application that will


calculate the due date for a book given the issue date. The no. of
days in which the book is due can be decided by the librarian at
the time of issuing a book. For e.g. If the librarian enters the
current date as 14-01-99 and the no of days in which the book is
due as 15, then your program should calculate the due date and
give the output as 29-01-99.

76. Write a program that accepts input of a number of


seconds, validates it and outputs the equivalent number of
hours, minutes and seconds.

77. Write a program to count the number of words in a text file

78. Write a program to check print the highest scorer. Student


details are stored in file in the format as below: -
StudNo 4 chars
StudName 20 chars
Marks 2 digits

79. Write a program to count the number of vowels in a given


string.

80. Write a program that accepts up to 10 words and outputs


them in dictionary order. (Hint: sort an array of numbers that
represent the words; don’t directly sort the words.) Do NOT use
the sort functions provided in the standard library. Here is a
typical user session:

Enter words: Damn Cold Bothers All Animals


Sorted words: All Animals Bothers Cold Damn
More? (Y/N) N

81. Write a program to obtain the transpose of a 4*4 array.


The transpose is obtained by exchanging the elements of each
row with the elements of the corresponding column

82. What are the 3 Binary tree traversal algorithms ?

In-order, Pre-order and Post-order are the 3 tree traversal


algorithms

Traverse the left sub tree


Visit the root
Traverse the right sub tree

void inorder(struct node *r)


{
if(r!=NULL)
{
inorder(r->left);
printf("\t %d",r->data);
inorder(r->right);
}
}

Visit the root


Traverse the left sub tree
Traverse the right sub tree

void preorder(struct node *r)


{
if(r!=NULL)
{
printf("\t %d",r->data);
preorder(r->left);
preorder(r->right);
}
}

Traverse the left sub tree


Traverse the right sub tree
Visit the root

void postorder(struct node *r)


{
if(r!=NULL)
{
postorder(r->left);
postorder(r->right);
printf("\t %d",r->data);
}
}

Example
A

B D

C
E F

Tree Order of walking of the nodes during


Traversal traversal
algorithm
Inorder CBAEDF
Preorder ABCDEF
Postorder CBEFDA

83. Assume I have a linked list containing all of the alphabets from
“A” to “Z”. I want to find the letter “Q” in the list. How do you
perform the search to find “Q” ?

84. Given two strings like x=”hello” and y=”open”, remove any
character from string x which is also used in string y, thus
making the result x=”hll”.

85. Suppose I want to write a function that takes a generic


pointer as an argument and I want to simulate passing it by
reference. Can I give the formal parameter type void **, and do
something like this? void f(void **); double *dp; f((void **)&dp);

86. What is the difference between malloc and calloc ?


87. What is structure packing ? How is it different from
structure padding ?

88. What is the memory allocated by the following definition ?

int (*x)[10];

89. What is the difference between a Declaration and Definition ?

90. Write a program to interchange 2 variables without using the


3rd variable

91. What is the difference between NULL and NUL keywords in


C?

92. Compare the 3 simple sorting algorithms. Which is more


preferable to use ?

The 3 simple sorting algorithms are :

• Bubble Sort
• Selection Sort
• Insertion Sort

93. Explain the Bubble Sort algorithm

94. What is Binary Search ? How is it faster compared to Linear


Search ? For an unordered list can we use Binary Search ?
If yes how ? If not why ?

95. What is a far pointer ?

96. Explain the working of printf ?

97. Evaluate the output for fn(7) :

int fn (int v)
{
if(v==1 || v==0) return 1;
if(v%2==0) return fn(v/2)+2;
else return fn(v-1)+3;
}

98. What will be printed as the result of the operation below ?


main()
{
int x=20,y=35;
x=y++ + x++;
y= ++y + ++x;
printf(“%d %d\n”,x,y);
}

99. What will be printed as the result of the operation below ?

void main()
{
int x=5;
printf(“%d,%d,%dn”,x,x< <2,x>>2);
}

100. What will be printed as the result of the operation below:

#define swap(a,b) a=a+b;b=a-b;a=a-b;

void main()
{
int x=5, y=10;
swap (x,y);
printf(“%d %dn”,x,y);
swap2(x,y);
printf(“%d %dn”,x,y);
}

int swap2(int a, int b)


{
int temp;
temp=a;
b=a;
a=temp;
return 0;
}

101. What will be printed as the result of the operation below ?

main()
{
char *ptr = ” Cisco Systems”;
*ptr++; printf(“%s\n”,ptr);
ptr++;
printf(“%s\n”,ptr);
}

102. What will be the output ?

main()
{
char *p1=“name”;
char *p2;
p2=(char*)malloc(20);
memset (p2, 0, 20);
while(*p2++ = *p1++);
printf(“%s\n”,p2);
}

103. What will be printed as the result of the operation below ?

int x;
int modifyvalue()
{
return(x+=10);
}

int changevalue(int x)
{
return(x+=1);
}

void main()
{
int x=10;
x++;
changevalue(x);
x++;
modifyvalue( );
printf("First output : %d\n",x);

x++;
changevalue(x);
printf("Second output : %d\n",x);
modifyvalue( );
printf("Third output: %d\n",x);
}
104. Which uses less memory ? and why ?

a) struct astruct { int x; float y; int v; };


b) union aunion { int x; float v; };
c) char array[10];

105. What are the techniques you will be using for debugging ?

106. Explain what do you understand by profiling ?

107. What is code optimization ? How is it done ?

108. What is the difference between ++(*p) and (*p)++ ?

109. Write a C program to check if a particular bit is set or not

110. How will find out if a given number is even or odd without
using the conditional operator ?

111. What is the difference between memcpy and memset ?

112. What are the differences between realloc and free ?

113. Which statement will execute faster : n++ or n = n + 1

It is preferable to use n++ rather than n= n + 1. The


reason is that ultimately the C program gets converted into
assembly language and then machine code. In assembly
language the statement n++ can translate to a INCR
instruction ( in implied addressing mode ) where as n= n +
1 involves moving the 2 operands to registers from
memory and then performing the operation and storing the
result back in the memory. What we mean here is that the
statement n++ will translate into fewer assembly language
statements than the statement n = n + 1.

But the present day optimizing compilers are smart enough


to translate instructions such as n = n + 1 as n++.

114. Consider the following 2 programs :

void main()
{
float a= 0.7;
if (a < 0.7)
printf("c");
else
printf("c++");
}

void main()
{
float a= 0.8;
if (a < 0.8)
printf("c");
else
printf("c++");
}

For the first program it prints “c” as the output but for the
second program it prints “c++” as the output. Why is it
so ?

115. How can we prevent multiple inclusion of the same header


files ?

116. What is the output of the following program ?

#include <stdio.h>
#define SQR(X) X * X

int main()
{
float y;

y = 225.0/SQR(15);
printf(“\n The value of y = %f”, y );
}

117. Compare strcpy Vs memcpy. When would you prefer to use

memcpy ?

strcpy can be used only with character arrays(strings). The


source string should be null terminated.

Usage : strcpy ( string1, string2 );

Here we have to ensure that string1 is large enough hold


string2 including the terminating the null character.
memcpy can be used to copy any type of data including
strings. But when we copy strings using memcpy we have
to ensure that we null terminate the destination string
after the copy.

Usage : memcpy(dest address, src address, 10);

Here we are copying 10 bytes of data from the specified


source address to the destination address. We have to
ensure that memory is allocated at the destination address
before we attempt to copy.

118. What is the prototype of printf function ? How is it able to


accept any number of arguments ?

The prototype of printf is


void printf ( const char *fmt, … );

printf is one function that can accept variable number of


arguments. As we have used printf statements extensively
in our C programs we know that we can print any number
of variables. Actually we do have a mechanism in the case
of printf to know the actual number of parameters that we
are going to print. We have the format specifiers to help us
know the exact number of arguments to be printed. Thus
we parse the format specifier and depending on the type
we print the variable in appropriate fashion.

The variable arguments functions that help us achieve are


va_start, va_list, va_args and va_end

119. How would you detect a loop in a linked list ?

a) One way to detect a loop in a linked list is to store the


pointers as we traverse the list. As we know all the
nodes in a linear linked list will have unique addresses.
If there is a loop we will encounter that address again
( the node where it forms a loop ). But here we have to
store the addresses for comparison. Every time we
traverse a node we have to compare the node address
with all the previous node addresses stored.
b) Just simple traverse the linked list in a while loop. While
executing if it goes into infinite loop then it means that
there is a loop. This detects a loop but will not be able
to pinpoint where we have the loop. For that we have to
store addresses as mentioned in a)
c) A more efficient solution is to add a flag field ( it can
even be a single bit if you want to conserve memory ) to
the structure. Then when you traverse the node set the
field to some pre-determined value ( say -1 ). When you
come across a node with -1 as the flag field you know
that there is a loop in the linked list. This is one of the
fastest way to determine if there is a loop in a linked
list.

120. What is the output of the following program ?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s=(char *) malloc (100);
s="hello";
free(s);
printf("Program to illustrate memory allocation and
deallocation\n");
return 0;
}

Segmentation fault

We are trying to free memory that was not allocated. We


actually allocated memory for s. But then the statement s
= “hello”; made s point to a string constant in read only
memory. Contrary to our belief the string “hello” was not
copied to the memory allocated for s in the malloc
statement.
Instead the string constant “hello” was created in the
string constant table ( usually in read only memory ) and
it’s address was assigned to s. So by the statement free(s)
we are actually trying to free the memory in the string
constant table which is a memory violation and hence the
segmentation fault.

We would be Ok if we had the statement


strcpy(s, “hello”); instead of s = “hello”;

121. Why do structures get padded ?


Structures get padded to preserve the alignment. For e.g.,
an integer occupies 4 bytes. Hence it can be aligned only
at memory addresses that are multiples of 4 ( say 0, 4, 8
etc ).
Characters since they occupy only 1 byte they can be
aligned at any address. Short integers which occupy only 2
bytes can be aligned at even addresses ( say 0, 2, 4, 6, 8,
10 etc. )

Please also refer Problem 130 for more information on


padding and how to avoid padding.

122. What is the difference between a static variable and a


global
variable ? On what basis will you choose between a static
variable and global variable ?

static variables can be defined within functions or it can be


global ( outside of the functions ). If it is defined within the
function it’s scope is limited to the function but retains it’s
value between calls to the function. If it is defined outside
(global) then they can be accessed/modified by all the
functions but still their scope is limited to that file only.
They cannot be accessed from other files. That is what we
mean when we say internal linkage.

Global variables on the other hand have to be defined


outside the functions and their scope is global. They have
external linkage and hence they can be accessed/modified
not only by functions in the current file where they are
defined but also by all other files by using the extern
qualifier. So global variables are hard to track as their
scope is vast. They should be limited to only the extreme
cases where there is no other alternative.

123. What is the output of the following program ?

#include <stdio.h>
enum {false,true};

int main()
{
int i=1;
do
{
printf("%d\n",i);
i++;
if(i < 15)
continue;
}while(false);
return 0;
}

The output is 1 ( as it goes through the do-while loop only


once – the very first time )

124. What is the logic behind the following code segment ?

int findlogic(unsigned int x)


{
int count=0;
while(x)
{
count++;
x = x&(x-1);
}
return count;
}

It counts the number of bits that are set in a number ( or )


the number of 1’s in the binary notation of a number

For 12 ( 1100 ) => 2 ( Since 2 bits are set ( have value


1))
For 100 ( 1100100 ) => 3

125. What is the difference between memcpy and memmove ?

As long as there is no overlap between the source and


destination memcpy and memmove are going to provide
the same end result. Only in situations where there is an
overlap they behave differently. In that case memmove
behaves like what we want and memcpy does not. Problem
No 63 has an example for us to illustrate the differences
between memcpy and memmove

int u[6] = {1, 2, 3, 4, 5};


memcpy(u + 1, u, 5*sizeof(int));
output
111111
int u[6] = {1, 2, 3, 4, 5};
memmove(u + 1, u, 5*sizeof(int));
output
112345

126. What is the output of the following program ?

#include <stdio.h>
int main()
{
int cnt = 5, a = 100;
do
{
printf ("a = %d count = %d\n", a, cnt);
a = a/cnt;
} while (cnt --);
return 0;
}

a = 100 count = 5
a = 20 count = 4
a = 5 count = 3
a = 1 count = 2
a = 0 count = 1
a = 0 count = 0
Floating point exception
( Floating point exception is due to division by 0 error )

127. With an example illustrate the difference between strcpy


and
strdup

The usage of strcpy is as follows : strcpy(string1, string2);


where string1 and string2 are null terminated strings and
string 2 is of type const char *

Here string2 is copied to string1. We have to ensure that


the destination string (string1) is big enough to hold the
source string(string2). Also we need to ensure that enough
memory is allocated for the destination string. If it is
allocated dynamically it is our duty to free it when it is no
longer required.

In strdup the case is different. The usage of strdup is as


follows :
char *string1 = strdup(string2);

Here string2 is of type const char * and string1 is just a


character pointer. We do not have to bother about
allocating memory for string1 to hold string2. The strdup
library function takes care of allocating enough memory to
hold string2. But after usage we need to free the memory
allocated by strdup to string1

The following program is designed to illustrate the


differences between strdup and strcpy :

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

int main()
{
char *string1;
const char string2[20] = "Amrita University";

/* Usage of strcpy */

string1 = (char *)malloc(strlen(string2) + 1);


strcpy(string1, string2);
printf("\nstring1 = %s", string1);
printf("\nstring2 = %s\n", string2);

free(string1);

/* Usage of strdup */

string1 = strdup(string2);
printf("\nstring1 = %s", string1);
printf("\nstring2 = %s\n", string2);

free(string1);

return 0;
}

128. Write a C program to delete a node from a doubly linked


list. The node could be anywhere in the list. Just to make
things simple we will consider that the data in the nodes
will be unique ( No 2 nodes will have the same data
void delete_node(DLLPTR *start, int data)
{
DLLPTR temp, temp1;
int count;
if ( *start == NULL )
{
printf("\n There are no nodes in the dll");
}
else if ( (*start)->data == data )
{
temp = *start;
*start = (*start)->next;
(*start)->prev = NULL;
free(temp);
}
else
{
temp = *start;
count = 0;
while ( (temp->data != data) && (temp->next !
= NULL) )
{
count++;
printf("\n temp = %u", temp);
printf("\n The [%d] node data = %d",
count, temp->data);
temp1 = temp;
temp = temp->next;
}
if ( (temp->next == NULL) && (temp->data !=
data) )
{
printf("\n The node to be deleted is not to
be found.");
}
else if ((temp->next != NULL) && (temp->data
== data))
{
temp1->next = temp->next;
(temp->next)->prev = temp->prev;
free(temp);
}
}
}
129. Consider the following structure :

struct sample
{
char a;
int b;
short c;
char d;
};

How many bytes of memory does the structure need ? Is


there any way we can minimize the memory requirement
for the structure ?

Assuming char needs 1 byte, short 2 bytes and int 4 bytes


the structure will need 12 bytes of which 4 bytes are
padding bytes. The memory representation of the structure
is shown below.

a
b
c d

If we re-arrange the structure as follows we need only 8


bytes ( we save 4 bytes in the process ). This is because
the structure variables are aligned properly as such and we
won’t need any padding bytes
struct sample
{
char a;
char d;
short c;
int b;
};

a d c
b
130. I have the following situation. I need to compile code
depending on the environment. if it is Unix environment I
will
compile some code. If it is Windows then I would like to
compile some other piece of code. How can we achieve this
?

If we want to compile code depending on the platform we


have to resort to #if conditional compilation statements.
For e.g., we can have something as shown below :

#define Unix_Platform
#ifdef ( Unix_Platform )
/* statements to be compiled for Unix */
#else
/* statements to be compiled for WINDOWS */
#endif

131. What will be the output of the following program ?

int main()
{
int i = 3;
int *j;
int **k;

j = &i;
k = &j;

printf("%u %u %d ", k, *k, **k);


}

a) Address, 3, 3
b) Address, Address, 3
c) 3, 3, 3
d) Compiler Error
e) None of the above

Address, Address, 3

132. What will be the output of the following program ?

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

int main()
{
int a,b,c,d;
char *p=0;
int *q=0;
float *r=0;
double *s=0;
a=(int)(p+1);
b=(int)(q+1);
c=(int)(r+1);
d=(int)(s+1);
printf("%d %d %d %d",a,b,c,d);
return 0;
}

a) Compiler Error
b) 1, 1, 1, 1
c) 1, 2, 2, 4
d) 1, 4, 4, 8
e) None of the above

1448

( Because when we do pointer arithmetic the increment


happens according to the pointer type. Hence for char
pointer the increment is 1 byte, for int and float pointers
the increment is 4 bytes, for double pointer the increment
is 8 bytes )

133. What is the output for the following program ?

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

int main()
{
char *ptr1=NULL;
char *ptr2=0;

strcpy(ptr1,"c");
strcpy(ptr2,"questions");

printf("\n%s %s",ptr1,ptr2);
return 0;
}

a)c questions
b)c (null)
c)(null) (null)
d)Compiler Error
e)None of the above

None of the above ( Actually we are using strcpy without


allocating memory to the pointer that is supposed to hold
the destination string. So it should be segmentation fault.
But since it is not given as an option we are selecting
“None of the above” )

134. What is the output for the following program ?

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

int main()
{
register int a=25;
int *p;
p=&a;
printf("%d ",*p);
return 0;
}

a) Segmentation Fault
b) Linker Error
c) Compiler Error
d) 25
e) None of the above

Compiler Error ( Since we are declaring a to be of type


register int such variables are supposed to be stored in the
CPU registers instead of memory. Since they are not
supposed to be stored in memory we cannot use the
address operator (&) on such variables

135. What is the output for the following program ?

#include <stdio.h>
#define x 5+2

int main()
{
int i;
i=x*x*x;
printf("%d",i);
return 0;
}

a) Compiler Error
b) 27
c) 343
d) 133
e) None of the above

27 (Actually when we evaluate i = x * x * x by substituting


the macro it becomes
i = 5+2 * 5+2 * 5+2
i = 5 + 10 + 10 + 2 ( Since * has priority over + )
i = 27

But this is not what we actually wanted. What we actually


wanted was (5+2)*(5+2)*(5+2) = 343

So to avoid these type of errors while using a macro


surround by parenthesis as shown below

#define x (5+2)

136. What is the output for the following program ?

#include <stdio.h>
int main()
{
int i=4,x;
x=i++ + i++ + i++;

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


return 0;
}
a) 18 8
b) 18 7
c) 12 7
d) Undefined
e) None of the above

12 7 ( Actually i is incremented 3 times. But since the


post increment operator is used the change does not take
effect immediately. So the i value used in the expression at
all the 3 places is 4. Subsequently because of the post
increments the value of I when it is printed is 7

137. What is the output for the following program ?

#include <stdio.h>
int main()
{
int i=5,j=2;

if(++i>j++||i++>j++)
printf("%d",i+j);

return 0;
}

a) 7
b) 11
c) 8
d) 9
e) Compiler Error

9 ( Self explanatory )

138. What is the output from the following program ?

#include <stdio.h>

int main()
{
char str[250];

scanf("%[^\n]",str);
printf("%s",str);
return 0;
}

a) Segmentation Fault
b) Compiler Error
c) It accepts only the new line character
d) It accepts all characters except the newline
e) It accepts all characters except blanks, tabs and newline

It accepts all characters including blanks and tabs except


the new line. When it encounters the new line character
scanf terminates. It is worth remembering that scanf stops
when it encounters the first whitespace character though it
does not return unless the user hits the return key(new
line). To understand the difference executing the simple
program below will help

#include <stdio.h>

int main()
{
char str[250];

scanf("%s",str);
printf("%s",str);
return 0;
}

139. What is the output from the following program ?

#include <stdio.h>
void main()
{
int a[2][4]={3,6,9,12,15,18,21,24};
printf("%d %d %d",*(a[1]+2),*(*(a+1)+2),2[1[a]]);
return 0;
}

21 21 21

The pointers in the program make it look scary. Also it is a bit more
complicated since it involves 2 dimensional arrays. The memory order
for 2 dimensional arrays looks like
A[0][0]
A[0][1]

A[0][2]

A[0][3]

A[1][0]

A[1][1]

A[1][2]

A[1][3]

For our convenience we can imagine a matrix structure like

A[0][1] A[0][2] A[0][3]


A[0][0]
A[1][0] A[1][1] A[1][2] A[1][3]

When we say A[1] in a 1-dimensional array it is a value


where as in a 2-dimensinal array A[1] is nothing but the
starting address of the row A[1] which is nothing but the
address of the first element in row1 i.e., &A[1][0]

A[1] + 2 => 2 elements from A[1][0] => Address of A[1]


[2]
*(A[1] + 2) => Value of A[1][2] = 21

A => the starting address of the 2-dimensional array, i.e.,


address of the element A[0][0]
*(A + 1) => A[1] which is &A[1][0]. Hence
*(*(A + 1)+2) => *(A[1] + 2) => Value of A[1][2] = 21

140. What is the output from the following program ?

#include <stdio.h>
void main()
{
enum color{
RED,GREEN=-20,BLUE,YELLOW
};
enum color x;
x=YELLOW;

printf("%d",x);
x=RED;

printf("\t%d",x);
return 0;
}

-18 0
( Enumeration constants normally start from 0. But once
we provide a default all subsequent values will be based on
the default )

141. What is the output from the following program ? ( 2 min )

int main()
{
const int x=25;
int * const p=&x;

*p=2*x;
printf("%d",x);
}
a) 25
b) 0
c) Compiler Error
d) 50
e) None of the above

Only the pointer is constant and the integer variable is not


a constant. Hence output is 50.

142. What is the output from the following program ?

void main()
{
int i=11;
int const * p=&i;
p++;
printf("%d",*p);
}

a) 11
b) 12
c) Compiler Error
d) Garbage Value
e) None of the above

Garbage value ( p points to the variable i but when we


execute the statement p++ we move the pointer to
uninitialized memory. So when we dereference that
location it should print garbage as shown in the figure )

200 11

204 Garbage ( Uninitialized

143. What is the output from the following program ?

int main()
{
int a=15,b=10,c=0;

if( a>b>c )
printf("True");
else
printf("False");
}

True ( The expression inside the if statement a > b > c


becomes
15 > 10 > 0 => (15 > 10 ) > 0 => True > 0 => 1 > 0 =>
True. Hence the condition inside the if statement is true
and hence it prints “True”
144. What is the output from the following program ?

#include <stdio.h>
struct marks
{
int p:3;
int c:3;
int m:2;
};

int main()
{
struct marks s={2,-6,5};
printf("%d %d %d",s.p,s.c,s.m);
return 0;
}

a) 2 -6 1
b) Compiler Error
c) Segmentation Fault
d) 2 2 1
e) None of the above

2 2 1 ( Here it looks complicated as we are using the bit


notation. But if we represent the numbers in their binary
we can figure out the result )
We are assigning 2 to p, -6 to c and 5 to m. But we have
the constraint that we have to represent p in 3 bits, c in 3
bits and m in 2 bits because that is the way the structure is
defined

In 3 bits 2 can be represented as ( 0 1 0 ) => 2


In 3 bits -6 can be represented as ( 0 1 0 ) => 2

To represent -6 in binary notation we first take the binary


for 6 take the 1’s complement and then add 1 to it. So 6
can be represented in 3 bits as 110. The 1’s complement is
001. Adding 1 to it becomes 010. Thus -6 can be
represented in 3 bits as 010.

In 2 bits 5 can be represented as ( 0 1 ) => 1

The leading 1 gets truncated as we want only 2 bits. Thus


we are now ready to represent the fields of the structure
( together they occupy 1 byte only )
145. What is the output from the following program ?

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

int main()
{
printf("%d %d",sizeof("string"),strlen("string"));
return 0;
}

7 6

sizeof will also take into account the null character (‘\0’)
where as strlen will only account for the actual number of
characters in the string

146. What is the output from the following program ?

#include <stdio.h>
int main()
{
int a = -12;
a = a >> 3;
printf("%d", a);
return 0;
}

-2

( a is defined as an integer. Assuming that it is 4 bytes the


memory representation of the 4 bytes for a will be

12 (binary)=> 00000000 00000000 00000000


00001100
1’s complement
of 12 => 11111111 11111111 11111111
11110011
2’s complement
of 12 => 11111111 11111111 11111111
11110100
-12 ( 11111111 11111111 11111111 11110100
Nothing but 2’s complement of 12 )
-12 >> 3 11111111 11111111 11111111
11111110
(Right shift by 3 bits)
1’s complement 00000000 00000000 00000000
00000001

2’s complement 00000000 00000000 00000000


00000010

Which is nothing but the number 2. So -12 >>> 3 gives


-2 )

147. What is the difference in using typedef Vs #define in the


following declarations ?

#include <stdio.h>
#define aaa char *
typedef char * bbb;

int main()
{
bbb a, b;
aaa c, d;
return 0;
}

The difference is also one of the important advantage of


the typedef over #define
When we say
bbb a, b then both a and b automatically become char *
When we say
aaa c, d then it only c is char * and d is plain char

We have to understand macros ( #define ) just do plain


substitution. So

aaa c, d becomes char *c, d => c is char pointer and d is


plain char

148. What is the output for the following program ?

#include <stdio.h>

int main()
{
int x, y, z;

x = 5;
y = 10;

z = x > y ? x : y;
printf("\n %d", z);
return 0;
}

10 ( This question has been added to illustrate the


operation of the ternary operator – Self explanatory )

149. Assuming start is the pointer to the first node in a sorted


linked list we make the following calls.

insert_node ( &start, 10 ); /* 10 is the data value */


delete_node( &start, 5 );
traverse_node( start )

Why do we pass the address of start for the insert & delete
functions and just the start for the traverse_node function ?

While traversing we just go from one node to another. So


there is no reason why the starting address of the linked
list should change. So there is no need to pass the address
of the start node.

While we insert (or) delete there could be a possibility that


we have to insert at the beginning of the list (or) delete the
starting node of the list. So in these scenarios the address
of the start node is likely to change. Hence we pass the
&start to these 2 functions.

150. What is the output of the following program ?

#include <stdio.h>
int main()
{
int a, b, c;
a = 2;
b = 3;
c = a+++++b;
printf("\n The value of c = %d", c);
return 0;
}
a) 6
b) 5
c) 7
d) Compiler Error
e) None of the above

Compiler Error

151. Study the following program carefully. The program


calculates the average of numbers. It is supposed to
continue as long as the user inputs ‘y’ for any more
numbers. If the user inputs ‘n’ then it will terminate. There
is
a problem with this program ? Can you identify the problem

? There are several solutions to this problem. Can you


come
up with at least one solution ?

#include <stdio.h>

int main()
{
int number;
char c;
int total = 0;
do
{
printf("\n Enter the number :");
scanf("%d", &number);
total = total + number;
printf("Do you have any more numbers ( y or n )?
:");
scanf("%c", &c);
} while ( c == 'y' );
return 0;
}

The problem with that program is scanf does not consume


the new line character(\n) that terminates input. Thus that
character lies in the input buffer waiting to be consumed
by subsequent calls. So the next scanf does not wait for
user input at all. It readily has the ‘\n’ character waiting in
the input buffer ready to be picked up. As mentioned there
are several solutions to this problem
1. One solution is to consume the newline character before
the next scanf using functions like getchar().
2. Yet another solution will be flush out the input buffer

Solution 1 is simple enough and implemented below.

#include <stdio.h>

int main()
{
int number;
char c;
int total = 0;
do
{
printf("\n Enter the number :");
scanf("%d", &number);
total = total + number;
if ( (c = getchar())== ‘\n’); /* empty statement
*/
printf("Do you have any more numbers ( y or n )?
:");
scanf("%c", &c);
} while ( c == 'y' );
return 0;
}

152. What is the output of the following program ?

#include <stdio.h>

int main()
{
static char *p = malloc(10);
strcpy(p, "Hello World");
printf("\n p = %s", p);
return 0;
}

a) p = “Hello World”
b) p = “Hello Wor”
c) p = “Hello Worl”
d) Segmentation Fault
e) Compilation Error
Compiler error

Static variables can only be initialized with constants.


For e.g., we can have

static char *p = “Hello World”;

But we cannot initialize them with return values from


functions

153. What is the output of the following program ?

#include <stdio.h>

int main()
{
int i;
char a[] = "string constant";
char *p = "string literals";

for ( i = 0; i < strlen(a); i++ )


{
p[i] = a[i];
}
printf("\n p = %s", p);
}

a) p = string constant
b) p = string literals
c) compilation error
d) segmentation fault
e) None of the above

Segmentation Fault

The string constant “string literals” is pointing to read only


memory. We cannot modify the contents in read only
memory. When we attempt to write it causes segmentation
fault.

154. What is the output of the following program ?

#include <stdio.h>
#include <stddef.h>

struct node
{
char a;
short int b;
char c;
int d;
float e;
char g;
double h;
};

int main()
{
struct node node1;
printf("\n size of struct node = %d", sizeof(struct
node));
printf("\n size of node1 = %d", sizeof(node1));

printf("\n Offset of c = %d", offsetof(struct node, c));


printf("\n Offset of e = %d", offsetof(struct node, e));
printf("\n Offset of h = %d", offsetof(struct node, h));

return 0;
}

The output from the program is :

size of struct node = 28


size of node1 = 28
Offset of c = 4
Offset of e = 12
Offset of h = 20

155. If s1 is a string defined as char s1[25] = “Hello World”;


*s1++ means

a) Increment s1 and return the


character pointed by s1
b) Increment the character pointed to
by s1
c) Increment s1 but return the
character pointed by s1 before the
increment
d) Increment s1 as well as the
character pointed by s1
e) None of the above
Increment s1 but return the character pointed by s1 before
the increment

156. What is the output of the following program ? Assume that


dummy has the address 0x100

#include <stdio.h>

void f(int *ip)


{
static int dummy = 5;
ip = &dummy;
}

int main()
{
int *ip;
printf("\n Before the function call : %p", ip);
f(ip);
printf("\n After the function call : %p", ip);
return 0;
}

157. What is the difference between a null pointer and


uninitialized pointer ?

There is a difference between a null pointer and unitialized


pointer. Basically an unitialized pointer could point to any
memory. There could be surprises when we use an
uninitialized pointer. It could even point to writeable
memory at times. For e.g., char *p where p is an
uninitialized pointer.

A null pointer is a pointer that does not point to any object.


For e.g., char *p = NULL;

158. What is the difference between NULL and NUL in C


language ?
NUL is the termination character for any string. It has the
value ‘\0’ where as NULL is the pointer assignment where it
means that the pointer is not pointing to any object.

159. What is the output of the following program ?


#include <stdio.h>

int main()
{
char *s1 = "Hello, ";
char *s2 = "world!";
char *s3 = strcat(s1, s2);
printf("\n s3 = %s", s3);
return 0;
}

a) s3 = Hello, world!
b) s3 = Hello,
c) s3 = world!
d) Compiler error
e) Segmentation fault

Segmentation fault

s1 does have enough memory to concatenate s2. Also s1


may not be writeable at all. These are 2 problems causing
segmentation fault in this program

160. Do you notice any problem with the following program ? If


yes what is it ? Is there any simple fix ? If no what will be
the output ?

#include <stdio.h>

char *itoa(int n)
{
char retbuf[20];
sprintf(retbuf, "%d", n);
return retbuf;
}

int main()
{
int n = 100;
char *p;
p = itoa(n);
printf("\n p = %s", p);
printf("\n p = %p", p);

return 0;
}
There is a problem with the program. In the function itoa
we define character array retbuf. That being local to
function it will go out of scope when the function exits.
There is a simple fix though. We can make the character
array as static so that will make it remain in scope. The
redefined function itoa is shown below :

char *itoa(int n)
{
static char retbuf[20];
sprintf(retbuf, "%d", n);
return retbuf;
}

Here we have to remember that static variables retain


their values between calls to the same function. Hence
when we pass the address of the static array it can be
accessed from the main function and it works as expected.
The other way ( though not as simple as this ) is to allocate
dynamic memory. Then that memory will be from the heap
and hence the calling function can access that memory.

161. Write a function to free the nodes in the linked list. Assume

that you are only provided with the head pointer for the
list

struct node
{
int data;
struct node *next;
};
typedef struct node NODE;
typedef NODE *NODEPTR;

void free_node ( NODEPTR *head )


{
NODEPTR temp;
while ( *head != NULL )
{
temp = *head;
*head = (*head)->next;
free (temp);
}
}

162. Provide the output of the following program :

#include <stdio.h>

int main()
{
char c = 'a';
printf("\n Size of a = %d", sizeof('a'));
printf("\n Size of c = %d", sizeof(c));
return 0;
}

The character constant always gets allocated memory


equal to that of an integer. This is contrary to what we
believe. But don’t know why it is like that. So the output for
the program is :
Size of a = 4
Size of c = 1

163. What is the output of the following program ? Assume that


we are entering “c23” for the value of x

#include <stdio.h>

int main()
{
int x, y;
do
{
printf("\n Enter a value for x : ");
y = scanf("%d", &x);
printf(“\n Number of items scanned : %d”, y);
} while ( x != -1 );
return 0;
}

This is a tricky program. As we know scanf will look at the


specifier %d and expects a number as input. But the user
is actually typing a string “c23”. So scanf does not accept
that for an integer input. Since x value is not -1 either. So
the do-while loop runs into an infinite loop each time scanf
refusing to accept c23 for a number. So the input buffer
characters do not get consumed by scanf. It does not exit
either as each time there are characters in the input buffer
to satisfy scanf.

164. What is the output of the following program ?

#include <stdio.h>

int main()
{
char *answer;
printf("Type something:\n");
gets(answer);
printf("You typed \"%s\"\n", answer);

return 0;
}

a) compilation error
b) You typed “Type something”
c) <empty> /* No output */
d) Segmentation fault
e) None of the above

Segmentation fault is the answer

We have not allocated memory for buffer. Without


allocating memory we are inputting a string to character
pointer answer. Either we have to declare answer as a
character array or we have to dynamically allocate
memory through malloc. There could be another problem
as well here. Even if we allocate memory if we type some
sentence that is larger than the allocation that could also
result in segmentation fault.

165. Compare and contrast gets Vs fgets

gets fgets
There can be a buffer Here we specify the buffer
overflow since we do not size and hence there cannot
specify the characters that be a overflow
are to be written to the
buffer
The new line character The newline character also is
does not form part of the part of the string. We need to
string explicitly remove the new
line character
For e.g., gets(char *buffer) fgets(char *buffer, MAX, fp)
where buffer is a character where buffer is a character
array or dynamic data array or dynamic data
structure allocated by structure allocated by
malloc malloc, MAX is the size of
buffer and fp is the file
pointer

166. Compare and contrast getchar Vs getc(stdin)

getchar() and getc(stdin) are one and the same. We can


use either when we want to read characters from standard
input

167. I want to read a sentence using scanf in just one


statement.
As usual the new line character(\n) should terminate input.
How will you do this ?

We know that by default scanf terminates when it sees the


first whitespace character. So normally if we type a
sentence it will read only the first word. But we can make it
read an entire sentence by providing the set of characters
within [ ] and in that we can also include the space
character. The characters in the square bracket basically
means that accept characters that are in the [ ]. The
characters can be repeated and they need not be in the
same order. Such a scanf statement along with the entire
program is shown below :

#include <stdio.h>

int main()
{
char buffer[80];
printf("\n Enter a sentence :");
scanf("%[
\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
123456789]", buffer);
printf("\n The sentence entered by you is %s",
buffer);

return 0;
}
From the program it is clear that scanf will accept all
lowercase alphabets, uppercase alphabets, digits, spaces
and tabs.

168. We know that r+ mode is used for opening a file in


read/write mode. How do you read and write to the same
file
with the same file pointer ? Will you not need 2 file
pointers
one to position for read and another to position for write ?

We do not need 2 file pointers when we open a file in r+


mode. When we are reading the contents of a file and we
would like to switch to the write mode we need to reset the
file pointer using fseek and then start writing. Similarly
when we are writing to a file we need to reset the pointer
using fseek before we start reading. This means that we
cannot just switch over from read to write without an
intermediate call to fseek

169. Write a program to reverse a linked list ?

void reverse_ll(DLLPTR *start)


{
DLLPTR temp, temp1;
if ( *start == NULL )
{
printf("\n There are no nodes in the list.\n");
}
temp = (*start)->next;
temp1 = *start;
temp1->next = NULL;

while ( temp != NULL )


{
temp1 = temp;
temp = temp->next;
temp1->next = *start;
*start = temp1;
}
}
170. Write a program to count the number of words in a text file

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100

int main()
{
FILE *fp;
char buffer[MAX_SIZE];
int count = 0;
char *p;

if ( (fp = fopen("input", "r")) == NULL )


{
printf("\n File could not be opened in input
mode");
exit(1);
}
while(fgets(buffer, MAX_SIZE, fp) != NULL)
{
buffer[strlen(buffer) -1] = '\0';
p = strtok(buffer, " ");
while (p != NULL)
{
count++;
p = strtok(NULL, " ");
}
}
printf("\n The number of words in the input file =
%d", count);
return 0;
}

171. Provide the output for the following program ?

#include <stdio.h>
#include <string.h>
char message1[60] = "Four score and seven years ago ...";
char message2[60] = "abcdefghijklmnopqrstuvwxyz";
char temp[60];
main()
{
printf("\nmessage1[] before memset():\t%s",
message1);
memset(message1 + 5, `@', 10);
printf("\nmessage1[] after memset():\t%s", message1);
strcpy(temp, message2);
printf("\n\nOriginal message: %s", temp);
memcpy(temp + 4, temp + 16, 10);
printf("\nAfter memcpy() without overlap:\t%s", temp);
strcpy(temp, message2);
memcpy(temp + 6, temp + 4, 10);
printf("\nAfter memcpy() with overlap:\t%s", temp);
strcpy(temp, message2);
printf("\n\nOriginal message: %s", temp);
memmove(temp + 4, temp + 16, 10);
printf("\nAfter memmove() without overlap:\t%s",
temp);
strcpy(temp, message2);
memmove(temp + 6, temp + 4, 10);
printf("\nAfter memmove() with overlap:\t%s\n", temp);
}

message1[] before memset(): Four score and seven


years
ago ...
message1[] after memset(): Four
@@@@@@@@@@seven
years ago ...

Original message: abcdefghijklmnopqrstuvwxyz


After memcpy() without overlap:
abcdqrstuvwxyzopqrstuvwxyz
After memcpy() with overlap:
abcdefefghghklklqrstuvwxyz

Original message: abcdefghijklmnopqrstuvwxyz


After memmove() without overlap:
abcdqrstuvwxyzopqrstuvwxyz
After memmove() with overlap:
abcdefefghijklmnqrstuvwxyz

172. Which one would you prefer and why ?

#define NUMBER 10 (or)


const int number = 10;
Declaring it as a constant is preferable for the following
reasons
1. Type checking can be done as it known that it is of type
int
2. The compiler can come up with optimizations as it
knows that it is an integer constant

173. What is the output of the following program ?

#include <stdio.h>
#define SQR(X) X * X

int main()
{
float y;

y = 225.0/SQR(15);
printf(“\n The value of y = %f”, y );
}

This is a typical MACRO problem. Whenever we use macros


it will simply substitute the values. In this case

Y = 225.0/SQR(15) becomes
Y = 225.0/15*15
Y = 225.0 ( Since /and * have equal priority they are
evaluated from left to right )

What we actually want can be done by enclosing the macro


arguments in parenthesis like

#define SQR(X) ((X) * (X))

Now when we perform

Y = 225.0/SQR(15) becomes
Y = 225.0/((15)*(15))
Y = 225.0/225 = 1.0

174. What is the difference between a Declaration and


Definition ?

Whenever memory is allocated it is definition. Otherwise it


is a declaration. For functions where the body of the
function exists it is the definition. Where only the prototype
is mentioned it is a declaration.

Variable Declaration

extern int x;

Variable Definition

int b;
float f = 2.0

Function Declaration

int add( int x, int y );

Function Definition

int add ( int x, int y )


{
int z;
z = x + y;
return z;
}

175. What is the difference between malloc and calloc ?

malloc is used for allocation of memory dynamically.


malloc returns a pointer to the allocated memory.
malloc needs just one parameter i.e., the number of bytes
to be allocated

For e.g.,
int * p;
p = (int *)malloc(5*sizeof(int)) /* If sizeof(int) = 4 then
5 * sizeof(int) = 20 */

calloc is also used for allocation of memory dynamically


calloc returns a pointer to the allocated memory.
But calloc requires 2 arguments the number of items of a
datatype and the size of the datatype.

For e.g.,
int * p;
p = (int *)calloc(5, 4) /* allocation for 5 integers each
occupying 4 bytes. So totally
5 * 4 = 20 bytes allocated */

calloc also initializes the allocated memory to 0. With


malloc we need to do this explicitly

176. Write a function that checks if one string is a substring of


another string

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

#define MAX_BUFFER 100

int main()
{
char *p;
char buffer[MAX_BUFFER];
char substring[50];
int count = 0;

printf("\n Enter the string which you want to search


for substring : ");
gets(buffer);
puts(buffer);

printf("\nEnter the substring that you want to search


in the string : ");
gets(substring);
puts(substring);

printf("\n Buffer = %s Substring = %s", buffer,


substring);

p = strstr(buffer, substring);
while ( p != NULL )
{
count++;
printf("\n Substring is located at position %d", p
- buffer);
p++;
p = strstr(p, substring);
}
printf("\n The number of occurences = %d\n", count);
return 0;
}

177. What is the output of the following program ?

#include <stdio.h>

int x;
int modifyvalue()
{
return(x+=10);
}

int changevalue(int x)
{
return(x+=1);
}

void main()
{
int x=10;
x++;
changevalue(x);
x++;
modifyvalue( );
printf("First output : %d\n",x);

x++;
changevalue(x);
printf("Second output : %d\n",x);
modifyvalue( );
printf("Third output: %d\n",x);
}

First output : 12
Second output : 13
Third output: 13

178. What is a dangling pointer ?

A dangling pointer is a pointer that is pointing to freed


memory. The concept can be explained with the following
example.

char *p, *q;


p = (char *)malloc(20); /* allocate 20 bytes */
q = p; /* p and q now point to the same memory
*/


free(p);

q is a dangling pointer as it points to memory that is freed.

179. What is a memory leak ? What are the implications of a


memory leak ?

A memory leak is memory allocated by the dynamic


allocation system that has not been freed. This can be
illustrated with an example.

int main()
{
fn();
}

void fn()
{
char *p;
p = (char *)malloc(20); /* allocate 20 bytes */

}

Here memory was allocated in the function but it was not


released after use. This is a single memory leak. In large
programs running into several thousand lines of code it is
tedious to trace all the possible memory leaks. The good
news is that there is software such as the Rational purify to
assist us with memory leaks. The bad news is that in C/C+
+ the onus lies on the programmer to ensure that memory
allocated is freed when it is no longer needed.

When we have too many memory leaks it damages the


dynamic allocation system and ultimately our system could
crash.

180. What are the main functions of a C pre-processor ?

The main functions of the C pre-processor are :


a) Macro substitution
b) File Inclusion
c) Conditional Compilation

181. What are main advantages of writing functions ?

The advantages and disadvantages of functions are listed


in the table below

Advantages Disadvantages

Repeatable tasks can be Function call is overhead for


written as functions and the system. When a call to a
can be called whenever function is made the control
they are required from the is transferred from the main
main function. For e.g., we program to the function.
can have a function called The return address is stored
average that computes the in the stack. So also are the
average marks of a student arguments. The Program
in a subject. It can be counter(PC) is now set to
called for computing the the starting address of the
average marks of each and function and execution of
every student. the function begins. Again
after the execution the
program returns to the main
program. Because of this
overhead a function call
slows down the execution
thereby increasing the
execution time. Hence it is
advisable to use functions
only where it is absolutely
necessary.
Functions make the
program modular. We split
the task into sub-tasks and
then write a function for
performing each of the
sub-task. By this approach
not only is it modular in
approach it also helps in
reducing the complexity,
debugging for errors etc.
182. What is hashing ? What are the advantages of hashing ?
How is hashing implemented ?

C++ & OOPS

1. How is C++ better than C ?

C++ is an object oriented language while C is a procedure


oriented language. The following table summarizes why C++ is
better than C not only conceptually but also language wise.
S.No C C++

1 Procedure oriented Object oriented language


language and hence and hence provides more
modular. It becomes very flexibility, code reuse and
difficult to manage when less of a nightmare to
the code reaches certain maintain code. Also data in
size. The data could get the objects are maintained
modified easily and in a consistent state leaving
keeping track of the so less room for errors and
many variables in the instability
program becomes a
nightmare
2 For data types to be The overloaded extraction
printed you need to specify operator cout eliminates the
the type of data. This is need to specify the type of
cumbersome especially if data. For e.g.,
you have to print a number
of variables of different
types. For e.g.,
cout << number << endl;
printf ( “\n %d %f %s”,
number1, number2,
address );

3 Not applicable in C Operator overloading allows


complex data types to be
used in arithmetic
operations. For e.g., we can
add 2 complex number
objects just like we add 2
integers with operator
overloading

Complex A, B, C;
A.real = 2
A.img = 3
B.real = 1
B.img = 5

C=A+B

4 Not applicable Functions can have the


same name provided they
differ in the type and/or the
number of arguments.
Function overloading allows
us to name the functions
with the same name if they
perform the same task.`
5 Not applicable Templates are available to
create generic
functions/classes which can
operate on different data
types
6 Dynamic memory can be Apart from malloc dynamic
created using malloc and memory can also be created
freed using free functions with the new operator. The
advantage of using the new
operator is that it allocates
memory based on the type
of the object. There is no
need to calculate the size of
the chunk to be allocated by
using the sizeof operator.
7 Not applicable Inheritance allows generic
functions to be defined in
the base class and only
specific functions need to be
defined in the derived
classes. This allows for code
to be reused and provides
flexibility.
8 Here data could be global Here the class encapsulates
and all functions can data and methods in such a
modify that data. Thus way that private data can
global data is vulnerable to only be accessed/modified
change. In a program with through public methods.
several thousand lines of Thus we do not face the
code it is very difficult to problems and the chaotic
figure out which function situation faced in procedural
modified the data. language.

9 Not applicable By using OOP we can hide


the complexity by
abstraction. We need to
provide only the interface
and hide the
implementation. This is akin
to saying we need to only
provide the steering wheel
to users of a car to drive the
vehicle. They do not need to
know about the mechanics
and what goes on behind
the scenes when they drive
the car.
10 C’s exception handling C++ provides better
mechanism is primitive exception handling with the
with the setjmp and throw and catch mechanism
longjmp functions

2. What are the differences between Object oriented


language and Procedure oriented language ?

In a procedure oriented language we understand the problem


and arrive at a solution by following a sequence of orderly steps.
If we follow the steps in the given order we can arrive at the
solution. As the name indicates procedure oriented languages
split the task into various functions or procedures. Each of these
procedures is a well defined unit which solves a specific task.

For e.g., For sorting array elements we can break the task into
the following procedures :

1. Get array elements (input)


2. Sort array elements (operation)
3. Print the sorted array elements (output)

C and Pascal are typical examples of Procedure oriented


languages.

In an object oriented language the emphasis is on the objects


that are part of the problem domain. Here the task is solved by
interactions of the objects with each other. Though more difficult
to design an object oriented solution to a problem they provide a
lot of advantages such as flexibility, code reuse, easy
maintenance.

C++, Java and Smalltalk are typical examples of object oriented


languages

The following table summarizes the difference between


procedure oriented and object oriented languages
S.N Procedure Oriented Object Oriented Languages
o Languages
1 It is a top down approach It is a bottom up approach
where we break down the where we start from the
problem into smaller and solution and arrive at the
more manageable parts problem domain
2 Modification is difficult and Because of the design,
tedious. A small change in the modification is easier and it
requirement could lead to a can be done without effecting
large rework major updates to the existing
software
3 As the code size grows the Due to object oriented
complexity grows and it could concepts such as abstraction
turn convoluted and difficult and encapsulation only the
to understand interface is exposed hiding the
implementation. This leads to
simplicity in design
4 Here more importance is Here more importance is given
given to the algorithms that to data. And the class design
act on the data. Data is just encapsulates the data (state)
used as a means to supply and the methods (behavior)
inputs to the algorithms and that can act on the data.
store outputs from the
algorithm
5 Due to the complexity there Code duplication is avoided
could be a lot of duplication of
code
6 Not applicable Here the object can behave
differently depending on the
context in which the object is
invoked. This is referred as
polymorphic behavior
7 Here we look at the verbs in Here we look at the nouns in
the problem domain. By the problem domain. Then we
knowing the verbs we know try to figure out the objects
what actions are required to that constitute the problem
be performed to arrive at the domain. Then we study the
solution. The problem is relationships between those
solved by divide and conquer objects. The objects use the
method. Basically the problem message passing mechanism
is split into parts and we to communicate between
create functions for each part. themselves to solve the
This method is also called as problem.
algorithmic decomposition
8 C, Pascal, Fortran and Cobol C++, Java, C# and Smalltalk
are examples of procedure are examples of object
oriented languages oriented languages

3. What do you understand by the term abstraction ?

Abstraction is basically a concept where the complexities are


hidden and the task is simplified. One good example is driving a
car. It is very simple to learn driving a car. The entire complex
mechanical system of the car is hidden from the user. All he
needs to know is how to use the steering wheel and switch
gears. Another example is the switch. All we need to know is
switch ON, switch OFF. We do not need to know the complex
electrical system behind the switch. Abstraction is the tool that
helps the OO programmer to manage complexity.

4. What is encapsulation ?
Encapsulation is the mechanism that binds code and data
together and guarantees the integrity of the data. In C++ the
basis of encapsulation is the class.

From the below diagram it is clear that the private data is


protected by the public member functions. The public member
functions provide an interface to the clients of the class. Since
we can access/manipulate data through the member functions
we cannot corrupt or misuse the data.

MEMBER FUNCTIONS
DATA

The date class provided below will clearly illustrate the concept.

class date
{
private :
int day;
int month;
int year;

public :
void getdate () const;
void setdate ( int x, int y, int z );
};

void date::getdate()
{
// return date
}
void date::setdate ( int x, int y, int z )
{
// check if x in proper range for day. For
// certain months it can be between 1 – 30 // only. For some
others it can be
// between 1 – 31. For Feb month it can be // 28 only if it is
// not a leap year and 29 if it is a leap year. // All these
// checks need to be done here. If it is not a // proper value
do not set the object. Print
// out an error message and exit.

// check if y is proper range for month 1 – 12 // only

// similarly check if z is within the proper


// range for year
}

The date class illustrates that an object data can be updated only
through its member functions. The implementation of these
member functions ensures that object data is always kept in a
consistent state. Clients of a class can access/modify data only
through the member functions (interface).

5. Explain Inheritance

The concept of inheritance is a very useful feature of object


oriented paradigm. This helps in organizing information
hierarchically and have the common traits defined in the base
class and specific information defined in the derived classes. This
also helps in code re-use.

Inheritance is characterized by “is-a” relationship. For e.g., in the


below mentioned example a car is a vehicle. Inheritance is also
known as generalization.
VEHICLE

BICYCLE CAR

The 3 main advantages of inheritance can be summed up as follows :


• Reusing the existing attributes and methods. When we inherit
from a Base Class we actually are reusing some of the
attributes and methods defined in the Base Class. For e.g.,
every vehicle can have some common attributes such as
color, weight, number_of_wheels, number_of_passengers the
vehicle can accommodate. Similarly drive() is a method that is
common to all the vehicles. All vehicles will stop when we
apply the brakes. So we can study the common attributes and
actions and define them in the base class.
• Extending the base class. Not only can we re-use the
attributes and methods of the base class but we can also
define new attributes and new methods in the derived class.
For e.g.,
Number_of_doors is an attribute that only applies vehicles
such as cars and they do not apply to vehicles such as bi-
cycles, scooters etc. Setting the vehicle to Cruise control is a
method that only applies to cars and not to bi-cycles. By
defining the special attributes of each vehicle we are basically
extending the base class to accommodate newer features and
functionality.
• Modifying the existing methods of the base class. For e.g.,
starting the vehicle is different for each case. We have to turn
on the key to start the ignition and press the brake to start
the car. We can have a method start() in the base class and
override that method in every derived class accordingly.

6. Provide the output for the following program :

#include <iostream>
class samp {
int i;
public:
samp ( int n )
{
i = n;
cout << “Constructing\n”;
}
~samp ( ) { cout << “Destructing\n”; }
int get_i ( ) { return i; }
};

int sqr_it ( samp o }


{
return o.get_i() * o.get_i();
}

int main( )
{
samp a(10);
cout << sqr_it(a) << “\n”;
return 0;
}

7. Provide the output for the following program ?

class samp {
char *s;
public:
samp() { s = ‘\0’; }
~samp() { if (s) free(s); cout << Freeing s\n”; }
void show() { cout << s << “\n”; }
void set (char *str);
};

void samp::set(char *str)


{
s = (char *)malloc(strlen(str)+1);
if ( !s ) {
cout << “Allocation error\n”;
exit(1);
}
strcpy(s, str);
}

samp input( ) int main()


{ {
char s[80]; samp ob;
samp str; ob = input();
ob.show();
cout << “Enter a string: “; return 0;
cin >> s; }

str.set(s);
return str;
}

8. What is a copy constructor ? What are the situations which


warrant the use of a copy constructor ?

A copy constructor is an overloaded constructor used for the


following situations where the value of one object is given to
another.

• When an object is used to initialize another in a declaration


statement
• When an object is passed as a parameter to a function
• When a temporary object is created for use as a return
value from the function.

It does not apply for assignments. The copy constructor is used


to solve the problems during the above situations when the
object has a pointer variable.

9. What is the output from the following program ?

class strtype {
char *p;
int len;
public:
strtype(char *ptr);
~strtype( );
void show( );
};

strtype::strtype(char *ptr)
{
len = strlen(ptr);
p = (char *)malloc(len+1);
if (!p) {
cout << “Allocation error\n”;
exit(1);
}
strcpy(p, ptr);
}

strtype::~strtype()
{
cout << “Freeing p\n”;
free(p);
}

void strtype::show()
{
cout << p << “ – length: “ << len;
cout << “\n”;
}

int main()
{
strtype s1("test");
strtype s2 = s1;
s1.show();
s2.show();
}

The output is segmentation fault. First the object s1 is created.


Then a bitwise copy of s1 is assigned to s2. So s1 and s2 have the
same value for p and they will be pointing to the same memory.
Then when main function terminates the object s2 will go out of
scope and hence its destructor will be called which will free the
memory pointed by p. Then s1 will go out of scope and the
destructor will attempt to free the same memory again which
causes the segmentation fault.

10. How does the copy constructor solve the above problem ?

First the copy constructor declaration should be added inside the


class declaration.

class strtype {
char *p;
int len;
public:
strtype(char *ptr);
strtype(const strtype &o);
~strtype( );
void show( );
};

strtype::strtype(const strtype &o)


{
int k;

len = strlen(o.p);
k = strlen(o.p) + 1;
p = new char[k];
if ( !p )
{
cout << “Allocation Failure\n”;
exit(1);
}
strcpy(p, o.p);
}

Now since we have defined the copy constructor our copy


constructor will be called instead of the default copy constructor.
In our copy constructor we ensure the memory is allocated for p
and the contents of the memory of the object used in the RHS of
the initialization statement is copied to the allocated memory. So
now s1 and s2 have different values for p and hence they point
to different areas in memory. When we free the objects when the
main function goes out of scope we free the different memory
and the program terminates without any run time errors this
time.

11. Provide the output for the following code segment

#include <iostream>

class base {
int x;
public:
void setx(int n) { x = n; }
void showx() { cout << x << ‘\n’; }
};

Class derived : private base {


int y;
public:
void sety(int n) { y = n; }
void showy() { cout << y << ‘\n’; }
};
int main ( )
{
derived ob;

ob.setx(10);
ob.sety(20);

ob.showx();
ob.showy();

return 0;
}

In this case since base is inherited privately the public members


of the base class become the private members of the derived
class. Thus they cannot be accessed directly through an object.
The statements ob.setx() and ob.showx() will lead to compilation
errors.

12. What happens when a public member is inherited as public


? What happens when a public member is inherited as private ?

When a public member is inherited as public they become public


members of the derived class. When they are inherited as
private they become the private members of the derived class

13. What happens when a protected member is inherited as


a. public ?
b. private ?
c. protected ?

When a protected member is inherited as public they become


the protected members of the derived class. When they are
inherited as private they become the private members of the
derived class. When they are inherited as protected they become
the protected members of the derived class.

All these types of the questions can be answered if we remember


the following table.

Inheritance Private Protected Public

Base Class
Member
Private Inaccessible Inaccessible Inaccessible

Protected Private Protected Protected

Public Private Protected Public

14. Provide the output for the following program

#include <iostream>

class samp {
int a;
protected:
int b;
public:
int c;

samp(int n, int m) { a = n; b = m; }
int geta() { return a; }
int getb() { return b; }
};

int main ( )
{
samp ob(10, 20);

ob.c = 10;
ob.b = 99;

cout << ob.getb() << ‘\n’;

return 0;

This program will not compile as we are accessing the protected


member in the statement ob.b = 99. b is protected member and
hence private and it can be accessed only by member functions
of the class.

15. How do you differentiate an object from a class ?


Class defines a specific datatype while an object is a
specific instance of a class. There can be several objects
that can be instantiated for that class. This is quite similar
to int being a datatype and int number defines a specific
variable of type int. We can define as many variables as we
need of type int.

16. When is an object created and what is it’s lifetime ?

An object is created or instantiated when we declare the


type. For e.g., when the following statement is executed

complex c1(2, 3);

The object c1 of the class complex gets instantiated and


will remain as long as the scope permits. For an object
instantiated inside a function it will be destroyed when we
exit the function. The constructor function will be called
during creation and the destructor will be called during the
exit of the object.

17. Explain operator overloading with an example

Operator overloading allows us to use the operators on


class objects ( user defined datatypes ) just as we would on
standard data types such as int.

For e.g., the + object is overloaded relative to the complex


class as shown below.

class complex {
int real;
int img;
public:
complex () { real = 0; img = 0; }
complex ( int x, int y ) { real = x; img = y; }
complex operator+ ( complex ob2 );
};

complex complex::operator+( complex ob2 )


{
complex temp;

temp.real = real + ob2.real;


temp.img = img + ob2.img;
return temp;
}

int main ()
{
complex A(10, 2), B(5, 3), C;

C = A + B; // Here operator overloading


// has provided
// the mechanism to add 2
// complex
// numbers ( user defined
// data objects or
// class objects ) just like
// we add 2 integers
}

18. What is polymorphism ? What are the different types of


polymorphism ?

Polymorphism illustrates the concept of “One interface, Multiple


methods”. Basically what we have is a generic interface for a set
of related methods. Which method will be called is determined
( at compile time ) for compile time polymorphism and at run
time for run time polymorphism. Polymorphism is a great
concept that actually reduces complexity by having a generic
interface and letting the correct method to be selected
appropriately at compile time or run time.

Polymorphism can be either at Compile time or Run time.


Function Overloading and Operator Overloading are examples of
Compile time polymorphism. Run time polymorphism is achieved
with the help of virtual functions.

For compile time polymorphism the example provided with the


complex class for overloading the + operator ( Question 12
under C++ ) can be used.

Following is a good example of how run-time polymorphism is


achieved with the help of virtual functions.

Class Base {
int i;
Base(int x) { i = x; }

virtual void func ( )


{
cout << “Using base version of func() :“;
cout << i << ‘\n’;
}

};

Class Derived1 : public Base {


Derived1(int x) : Base(x) { }

void func ( )
{
cout << “Using derived1’s version of func() :”;
cout << i * i << ‘\n’;

}
};

Class Derived2 : public Base {

void func ( )
{
cout << “Using derived2’s version of func() :”;
cout << i + i << ‘\n’;
}

};

int main ( )
{
Base *p;
Derived1 d_ob1(10);
Derived2 d_ob2(10);
int i, j;

for ( i= 0; i< 10; i++ )


{
j = rand();
if (( j % 2 )) p = &d_ob1;
else p = &d_ob2;
p->func();
}
return 0;
}

19. What are virtual functions ?

Virtual functions are member functions that are declared within a


base class and redefined by the derived classes. Virtual functions
are the means through which run time polymorphism is
achieved.

20. What are pure virtual functions ?

A pure virtual function which will not be defined in the base


class. For e.g., no objects can be instantiated for abstract base
classes. “Vehicle” is a generic base class. “Car”, “Cycle”,
“Scooter”, “Jeep” are all vehicles and they form the specific
derived classes. There can be no objects of type vehicle as it is
abstract. But we can have car objects, cycle objects etc. There
can be a method “drive” which will then be made a pure virtual
function in the base class and they can have the proper
implementations in the derived classes. How do we identify from
code if it is a pure virtual function. We can do so as they are
equated to zero in the base class declaration as shown in the
code below. When a virtual function is made pure then the
derived classes must provide the definition.

class Vehicle
{

public :
virtual void drive() = 0 // This means that it
// is a pure virtual
// function and hence
// the class is
// abstract and no
// objects can be
// instantiated for the
// class. It can
// only be a base
// class providing
// pure virtual
// functions
};

class Car
{

public :
void drive ()
{
// Provide the implementation specific to car
}

};

class jeep
{
public :
void drive ()
{
// Provide the implementation specific to jeep
}
};

21. Is the following code fragment correct ? If you say “yes” or


“no” then justify

Class base {
public :
virtual int f ( int a ) = 0;

};

Class derived : public base {


int f ( int a, int b )
{
return a * b;
}
};
The code fragment is not correct. The reason being that
Virtual functions must have the exact prototype specified
by the base class. In this case they differ in the number of
arguments. The compiler will signal error in this case.

22. What is the main difference between structures and


classes
? Can a structure include member functions like a class ?
The main difference between structures and classes is that
all members are public by default in a structure and private
by default in a class.

We can have member functions in a structure similar to a


class but we do no not prefer to h to do that to maintain
upward compatibility with C. Since encapsulation is an
object oriented paradigm we would rather use a class when
we have to combine both data and member functions.

23. What is an anonymous union ? What are its applications ?

An anonymous union is a special type of union that does


not have a type name and hence no variables can be
declared fpr this type of union.

For e.g.,

union {
int i;
char ch[4];
}

The variables i and ch can be accessed directly. As in the


case of any other union they share the same memory. The
memory is allocated based on the largest data type. In this
case however both i ( an integer ) and ch[4] require equal
memory ( 4 bytes ). So 4 bytes is allocated for this union as
both the variables share this space.

24. When would you declare a class member to be mutable ?

When we want a constant member function to modify a


private data member then we declare that data member as
mutable. This mutable declaration overrides the constant
nature of the function and allows it to modify the variable.
However only the mutable member can be modified by the
const member function. Other variables cannot be
modified.

25. Give a good application for having a static data member in


a
class
A very good example for using static data member is for
counting the number of objects instantiated for a class. We
can initialize the static data member to 0 even before any
object gets created for the class. And whenever any new
object gets created we can increment the static data
member.

26. Provide at least one good use for static member functions

A static member function can be used to pre-initialize a


static data member. This can be done even before any
object of the class gets instantiated. A class has just one
copy of a static data member unlike other variables which
are available one per object.

27. What are friend functions ? What are their applications ?

There will be situations in which we would like non member


functions to have access to the private members of a class.
This is achieved with the help of friend functions. We do
that that by declaring the friend function inside the class
definition.

// An example for the usage of a friend


// function

class {
int n, d;
public:
myclass(int i, int j) { n = i; d = j; }
// friend function declared inside the
// class definition
friend int isfactor(myclass ob);
}

// Friend function definition


int isfactor (myclass ob)
{
if( !(ob.n % ob.d) ) return 1;
else return 0;
}

// Call to the friend function passing an


// object of the class for which it is a friend
int main()
{
myclass ob1(10,2), ob2(13,3);

if(isfactor(ob1))
cout << “2 is a factor of 10\n”;
else
cout << “2 is not a factor of 10\n”;

if(isfactor(ob2))
cout << “3 is a factor of 13\n”;
else
cout << “3 is not a factor of 13\n”;
}
Note :

The usage of friend functions should be restricted as much


as possible as they violate the concept of encapsulation by
allowing access to private data by non member functions.
Nevertheless there could be a situation where we may
need to do exactly that and we do not have any other way
around. We should restrict the usage of friend functions to
such situations.

28. What are references ? How do they differ from pointers ?

References are another way of passing parameters to


functions. A reference is nothing but an alias for a variable.
Internally references are implemented as constant
pointers.

There are 3 ways of parameter passing in C++


1. Passing by value
2. Passing by pointer
3. Passing by reference

We accomplish the same objective by passing a pointer or


reference. References are easier to use compared to
pointers. The main advantages of using references are :

1. A function call can be used in the left side of an


assignment statement if that functions returns a
reference.
2. References to objects are returned by operator
overloaded functions
3. References are easier to use syntactically than pointers
and they achieve the same end result that we would
like to have with pointers

29. Explain the terms : Passing by value, Passing by reference,

Passing by pointer

When we pass objects to a function by value a bit wise


copy of the object is made and it is this object that is used
by the function. Any changes to this object does not have
any effect on the actual object passed to the function as a
parameter.

When we pass objects to a function by reference implicitly


the compiler passes the address of the object. Thus any
changes made to the passed object in the function will
actually modify the actual object passed to the function as
a parameter.

When we pass objects to a function by pointer we are


explicitly passing the address of the object. Thus any
updates to the object in the function will change the
original object passed to the function as a parameter.

All the 3 types of parameter passing mechanism are


illustrated in the following program :

int main ()
{
int a = 5, b = 10;
printf(“\na = %d\tb=%d\n”);
swap_by_value(a,b);
printf(“\na = %d\tb=%d\n”);
swap_by_reference(a,b);
a = 5; b = 10;
printf(“\na = %d\tb=%d\n”);
swap_by_pointer(&a,&b);
}

void swap_by_value(int a, int b)


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

void swap_by_pointer ( int *a, int *b )


{
int temp;
temp = *a; *a = *b; *b = temp;
}

30. What is a this pointer ? Do all member functions have


the this pointer ? Which functions do not have the this
pointer ?

When a member function is called through an object the


compiler implicitly passes the address of the object through
which that call was made. For e.g.,

Form I ( Direct access of data members )

class date { void main( )


int day; {
int month; date d(5, 12, 2009);
int year; d.get_day();
public: }
date(int x, int y, int z)
{
day = x;
month = y;
year = z;
}
void get_day { cout << day << “\n”; }
void get_month { cout << month << “\n”; }
void get_year { cout << year << “\n” }
};

As illustrated in the date class member functions have the privilege


to access/modify private data members just by referring to their name.
But in reality the member functions are passed the implicit pointer to
the object called “this” and they access the members through the
“this” pointer as shown below.

Form II ( Data member access through the this pointer )


class date { void main( )
int day; {
int month; date d(5, 12, 2009);
int year; d.get_day();
public: }
date(int x, int y, int z)
{
this->day = x;
this->month = y;
this->year = z;
}
void get_day { cout << this->day << “\n”; }
void get_month { cout << this->month << “\n”; }
void get_year { cout << this->year << “\n” }
};

Forms I and II are equivalent. In fact Form I is just a shortcut to Form II.
We tend to use Form I all the time because of the ease of use.

Note : Only members functions are passed the this pointer. Friend
functions are not passed with the this pointer.

31. What are the differences between Overloading &


Overriding ?

Overloading and Overriding look like similar terms but they are
vastly different. The following table summarizes the difference
between the 2 terms.

Overloading OVERRIDING
Compile time phenomenon Run time phenomenon
Achieved through Achieved through Virtual
1. Functions Functions (Run time
2. Operators polymorphism)
(Compile time
polymorphism)
Called so because functions Called so because when the
can have the same name if base class declares a member
they perform the same function to be virtual then the
function and the actual derived classes can redefine
function to be called is known the function according to their
at compile time by requirements. Thus the derived
determining the number and classes override the definition
type of arguments passed to set by the base class.
the function. In the case of
operators the overloading
actually helps to use the
operators for user defined
data types just as we do for
the standard data types

32. What is the difference between initialization &


assignment ?

There is a subtle difference between initialization and


assignment. The following example will illustrate the concept.

We know that constructors are used to initialize objects when


they are created. After creation we can assign that object to
another object. For e.g.,

complex c1(5,3), c3(1,2);


complex c2 = c1; /* initialization */
c3 = c1; /* assignment */

Initialization can occur in one of the 3 ways :


1. When when one object is initialized to another in a
declaration statement
2. When an object is passed to function as a parameter
3. When a temporary object is created for passing the return
value from a function

33. What will happen if I allocate memory using new and free
it using free. (or) allocate memory using calloc and free it using
delete ?

Though malloc and new are used for memory allocation they
operate in different ways. For e.g., when we use new, memory is
automatically allocated by determining the size of the data type.
With malloc we have to explicitly use the sizeof operator to
determine the number of bytes that are to be allocated. When
we allocate memory using malloc we have to use free function to
free the memory. Similarly if we use new we have to use the
corresponding function delete to free the memory. If we allocate
memory with new and free it using free we are basically
destroying the dynamic memory allocation system. The program
could crash because of this.

34. Explain the need for virtual destructor


Consider the following program :

#include <iostream>
using namespace std;
class Base
{
public:
Base(){ cout<<"Constructor : Base"<<endl;}
~Base(){ cout<<"Destructor : Base"<<endl;}
};
class Derived: public Base
{
//Doing a lot of jobs by extending the
// functionality
public:
Derived(){ cout<<"Constructor : Derived"<<endl;}
~Derived(){ cout<<"Destructor : Derived"<<endl;}
};
int main()
{
Base *Var = new Derived();
delete Var;
return 0;
}

When we create a Derived class object dynamically the base class part
of the object is created first followed by the derived class object. But
since the object is assigned to a base class pointer when the call to
delete the pointer “delete Var” is made only the base class destructor
is called. This is because the decision is made based on the type of the
pointer rather than the object pointed to. So the output for this
program is :

Constructor : Base
Constructor : Derived
Destructor : Base

To rectify the problem we make the destructor virtual to ensure that


the Derived class destructors are called before calling the Base class
destructor. Hence the Base class destructor should be defined as

virtual ~Base(){ cout<<"Destructor : Base"<<endl;}

35. What is the difference between a Copy constructor and an


overloaded assignment operator ?
The copy constructor and the situations that warrant a copy
constructor have been discussed in detail in Questions 8, 9 & 10.
We have also seen the difference between initialization and
assignment in Question 32.

But the copy constructor is restricted to initializations only. It


cannot solve the problem of an object that allocates dynamic
memory during an assignment. This is where the overloaded
assignment operator comes to our rescue

To understand the problem that the overloaded assignment


operator is required to solve let us say that we have a class with
a pointer member. When we instantiate an object of that class
memory is allocated by the constructor function and initialized as
desired. When we assign that object to another object a bit wise
copy of the object is made from the RHS object to the LHS object.
This means that the pointer member of the LHS object points to
the same address as the RHS object. If say one of the object
goes out of scope the destructor is called which releases the
memory pointed by the pointer member. This in turn makes the
other object useless as its pointer member also points to the
same memory.

The following example illustrates the usage of the overloaded


assignment operator.

class strtype {
char *p;
int len;
public:
strtype(char *s);
~strtype( ) {
cout << “Freeing “ << “\n”;
delete [] p;
}
char *get( ) { return p; }
strtype &operator=(strtype &ob);
};

strtype::strtype(char *s)
{
int k;
k = strlen(s)+1;
p = new char[k];
if (!p)
{
cout << “Allocation error\n”;
exit(1);
}
len = k;
strcpy(p,s);
}

// Overloaded assignment operator


strtype &strtype::operator=(strtype &ob)
{
if ( len < ob.len ) {
delete [] p;
p = new char[ob.len];
if (!p)
{
cout << “Allocation error\n”;
exit(1);
}
}
len = ob.len;
strcpy(p, ob.p);
return *this;
}

int main( )
{
strtype a(“Hello”), b(“There”);
cout << a.get() << “\n”;
cout << b.get() << “\n”;

a = b; // invokes the overloaded assignment


// operator function
cout << a,get() << “\n”;
cout << b.get() << “\n”;
}

36. What is multiple inheritance ? How is it different from multi


level inheritance ? How can we avoid the diamond lattice
problem associated with multiple inheritance ?

Multi-level inheritance is a hierarchy extending to several levels


where each derived class inherits from just one base class.
Classifications that are hierarchical in nature can fit into multi-
level inheritance.
VEHICLE

CAR JEEP

MARUTI TATA

Multiple inheritance happens when a class inherits from more


than one base class. For e.g., there are duck tours organized for
tourists in the city of London. These vehicles shaped like a duck
can travel on road as well as water ( river thames ) for taking the
tourists to the various sight seeing spots. These amphibious
vehicles inherit functions from both the land moving vehicles and
water moving vehicles.
LAND VEHICLE WATER VEHICLE

AMPHIBIOUS VEHICLE

The diamond lattice problem happens when 2 classes inherit from


the same base class and these 2 classes happen to be the base
classes for another class. This inheritance graph depicted below
looks like a diamond and hence the name.

BASE

DERIVED1 DERIVED2

DERIVED3

Derived3 objects will have 2 copies of Base one inherited via


Derived1 and the other inherited via Derived2. So when we try to
access/modify Base data which one are we trying to access/modify ?

There is ambiguity here. So to ensure that Derived3 inherits just


once copy of Base we make the inheritance virtual as shown below.
Class Base { // Base data & methods };
Class Derived1 : virtual public Base
{
// Derived1 data & methods
}
Class Derived2 : virtual public Base
{
// Derived2 data & methods
}
Class Derived3 : public derived1, public derived2
{
// Derived3 data & methods
}

37. What do you think is wrong with the following program ? Is


there a simple fix ?

class strtype {
char *p;
public:
strtype(char *s);
~strtype() { delete [] p; }
char *get() { return p; }
};
strtype::strtype(char *s)
{
int k;
k = strlen(s) + 1;
p = new char [k];
If(!p)
{
cout << “Allocation error\n”;
exit(1);
}
strcpy(p, s);
}
void show( strtype x )
{
char *s;
s = x.get();
cout << s << “\n”;
}
int main( )
{
strtype a(“Hello”), b(“There”);
show(a);
show(b);
}

We need to understand this program to see what happens. 2


objects of strtype a and b are instantiated. The constructor
allocates memory for p and copies the strings passed as
parameters. The objects are represented below for reference.

Hello There

a 0x1000 0x2000
b
When the strtype object a is passed as parameter to the show
function a bit wise copy of the object is made. The strtype
parameter in the show function is the bit wise copy of a. Then it
gets the p value and prints it. The status of object x is shown
below

Hello

x 0x1000

When we exit the function the object x goes out of scope. So the
memory allocated for p is freed as well. But the original object a
is also pointing to the same memory. So after we get back to the
main function the original object becomes useless. The same
happens when we call the show function with the parameter b.

What then is the solution ? The most simple fix is to pass the
parameter by reference to the show function. This involves only
one change in the code. The change is shown below for clarity.
void show( strtype &x )
{
char *s;
s = x.get();
cout << s << “\n”;
}

The change is only in the header. We are passing the strtype


parameter by reference. When we pass objects by reference the
same object is passed. So when we exit the function the
destructor is not called. So we do not have the unpleasant side
effects that we had experienced earlier.

38. What are the differences between shallow copy and deep
copy ?

The differences between shallow copy and deep copy can


be explained with the following program :

#include <iostream>
#include <string>
using namespace std;

class myclass
{
char *p;
public:
myclass(char *str);
myclass(const myclass &obj);
~myclass() { cout << "Destructor Invoked\n"; delete
p; }
void show() const { cout << p << endl; }
};

myclass::myclass(char *str)
{
cout << "Normal Constructor invoked\n";
int len = strlen(str);
p = new char[len+1];
if ( !p )
{
cout << "Allocation Error\n" << endl;
exit(1);
}
strcpy(p, str);
}

myclass::myclass(const myclass &obj)


{
cout << "Copy constructor invoked\n";
int len = strlen(obj.p);
p = new char[len+1];
if ( !p )
{
cout << "Allocation Error\n" << endl;
exit(1);
}
strcpy(p, obj.p);
}

void print(const myclass obj)


{
obj.show();
}

int main()
{
myclass obj1("Hello");
print(obj1);
cout << "Fine until here\n";
return 0;
}

In the above program the class has a pointer member p.


First an object obj1 is created. It calls the normal
constructor which allocates memory and copies the string
“Hello” into the allocated memory. Then we pass the
object obj1 to the print function as a parameter. Normally
when we pass objects to functions a bitwise copy of the
object is made by the default copy constructor. But since a
bit wise copy is not desirable since the copy will also be
pointing to the same memory as the original object we
write our own copy constructor. When we try executing
this program by commenting the code for the copy
constructor we will get a run time error as we are trying to
free the memory which was already freed. The solution is
to write our own copy constructor which will allocate new
memory and copy the contents.
Example for Shallow Copy

OBJECT1

PTR = 0x100

COPY OF
OBJECT1 When the function is called with object1 a
bitwise copy is made by the default copy
PTR = 0x100 constructor and now both the original object
and the copy point to the same memory

OBJECT1

PTR = 0x100
When the function goes out of scope the
copy also goes out of scope and calls its
destructor to free the memory. This the
memory is deleted but the original object is
still pointing to that memory

When the main function terminates the


original object also goes out of scope. Thus it
calls the destructor which tries to free the
memory. As that memory was already freed
trying to free it a second time results in run-
time error and the program crashes.
Example for Deep Copy

OBJECT1

PTR = 0x100

COPY OF
OBJECT1

PTR = 0x200

When the function is called with object1 it


calls our copy constructor which allocates
new memory and copies the contents.

OBJECT1

PTR = 0x100
When the function goes out of scope the copy
also goes out of scope and calls its destructor
to free the memory. The memory allocated for
the copy is only deleted,. The original object
does not get affected in this case

When the main function ends the original


object also goes out of scope and its memory
is deleted. So there are no issues in this case as
the memory for the copy and the original
object were separate.
39. Try program 38 by commenting out the copy constructor
code and observe what happens

40. Explain the following terms with an example :


• const_cast
• static_cast
• dynamic_cast
• reinterpret_cast

41. Explain Run Time Type Identification

42. What is a Namespace ? How is it implemented in C++ ?

43. What is a template ? What are the different types of


templates ?

44. How is exception handling done in C++ ?

45. How does the V-Table mechanism work ?

The Virtual Table mechanism works as follows :

Whenever there is a virtual function defined in the base


class then a virtual table is created in memory. Each object
of the base class will have a pointer to the V-Table called
the vptr. If there are derived classes for the base class then
the derived objects also will contain a pointer to its own V-
table. So each class will have its own V-Table and each
object of the classes will have a pointer to its V-Table. This
can be explained with the following example :

#include <iostream>
using namespace std;

class Base {
int x;
public:
Base(int a) { x = a; }
virtual void function1();
virtual void function2();
};
class Derived1:public Base
{
int y;
public:
Derived1(int a, int b) : Base(a) { y = b; }
virtual void function1();
};

class Derived2:public Base


{
int z;
public:
Derived2(int a, int b) : Base(a) { z = b; }
void function2();
};

void Base::function1()
{
cout << "\nBase::Function1" << endl;
}

void Base::function2()
{
cout << "\nBase::Function2" << endl;
}

void Derived1::function1()
{
cout << "\nDerived1::Function1" << endl;
}

void Derived2::function2()
{
cout << "\nDerived2::Function2" << endl;
}

typedef void (*Fun)();

int main()
{
Base *bptr;
Base bobj(8);
Derived1 d1obj(2,3);
Derived2 d2obj(4,5);
Fun pfun = NULL;
cout << "\n *** Size of the objects
******************\n";

printf("\nSize of Base object bobj = %d", sizeof(bobj));


printf("\nSize of Derived1 object d1obj = %d",
sizeof(d1obj));
printf("\nSize of Derived2 object d2obj = %d\n",
sizeof(d2obj));

cout << "\n *** Virtual Pointer value for bobj


***************\n";

int *mtr = (int *)&bobj;


printf("\nDerived1 object d1obj address = %p", mtr);
printf("\nVirtual Pointer vptr = %p", *(mtr+0));

cout << "\n *** Virtual Table Entries for Base


****************\n";

int *ntr = (int *)*(mtr+0);


printf("\nVtable entry 1 = %p", *(ntr+0));
printf("\nVtable entry 2 = %p", *(ntr+1));

cout << "\n *** Virtual Pointer value for d1obj


***************\n";

int *ptr = (int *)&d1obj;

printf("\nDerived1 object d1obj address = %p", ptr);


printf("\nVirtual Pointer vptr = %p", *(ptr+0));

cout << "\n *** Virtual Table Entries for Derived1


****************\n";

int *qtr = (int *)*(ptr+0);


printf("\nVtable entry 1 = %p", *(qtr+0));
printf("\nVtable entry 2 = %p", *(qtr+1));

cout << "\n *** Virtual Pointer value for d2obj


***************\n";

int *rtr = (int *)&d2obj;


printf("\nDerived2 object d2obj address = %p", rtr);
printf("\nVirtual Pointer vptr = %p", *(rtr+0));
cout << "\n *** Virtual Table Entries for Derived2
***************\n";

int *str = (int *)*(rtr+0);


printf("\nVtable entry 1 = %p", *(str+0));
printf("\nVtable entry 2 = %p", *(str+1));

cout << "\n Calling Function1 through Base pointer ->


Derived1 obj \n";
bptr = (Base *)&d1obj;
bptr->function1();

cout << "\n Calling Function2 through Base pointer ->


Derived1 obj \n";
bptr->function2();

cout << "\n Calling Function1 through Base pointer ->


Derived2 obj \n";
bptr = (Base *)&d2obj;
bptr->function1();

cout << "\n Calling Function1 through Base pointer ->


Derived2 obj \n";
bptr->function2();

bptr = new Base(3);

cout << "\n Calling Function1 through Base pointer ->


Base obj \n";
bptr->function1();

cout << "\n Calling Function2 through Base pointer ->


Base obj \n";
bptr->function2();

cout << "\n Calling functions through function


pointers \n";

pfun = (Fun)*(ntr+0);
pfun();

pfun = (Fun)*(ntr+1);
pfun();

pfun = (Fun)*(qtr+0);
pfun();
pfun = (Fun)*(qtr+1);
pfun();

pfun = (Fun)*(str+0);
pfun();

pfun = (Fun)*(str+1);
pfun();

return 0;
}

On compilation and execution of this program the output


was

*** Size of the objects ******************

Size of Base object bobj = 8


Size of Derived1 object d1obj = 12
Size of Derived2 object d2obj = 12

*** Virtual Pointer value for bobj ***************

Base object bobj address = 0xbfe5cfc8


Virtual Pointer vptr = 0x80491c0

*** Virtual Table Entries for Base ****************

Vtable entry 1 = 0x804880a


Vtable entry 2 = 0x80487de

*** Virtual Pointer value for d1obj ***************

Derived1 object d1obj address = 0xbfe5cfbc


Virtual Pointer vptr = 0x80491b0

*** Virtual Table Entries for Derived1 ****************

Vtable entry 1 = 0x80487b2


Vtable entry 2 = 0x80487de

*** Virtual Pointer value for d2obj ***************

Derived2 object d2obj address = 0xbfe5cfb0


Virtual Pointer vptr = 0x80491a0
*** Virtual Table Entries for Derived2 ***************

Vtable entry 1 = 0x804880a


Vtable entry 2 = 0x8048786

Calling Function1 through Base pointer -> Derived1 obj

Derived1::Function1

Calling Function2 through Base pointer -> Derived1 obj

Base::Function2

Calling Function1 through Base pointer -> Derived2 obj

Base::Function1

Calling Function1 through Base pointer -> Derived2 obj

Derived2::Function2

Calling Function1 through Base pointer -> Base obj

Base::Function1

Calling Function2 through Base pointer -> Base obj

Base::Function2

Calling functions through function pointers

Base::Function1

Base::Function2

Derived1::Function1

Base::Function2

Base::Function1

Derived2::Function2

From the output we can infer the following. Whenever


there is a virtual function defined in the base class every
object of the base class and all objects of classes derived
from that base class will have a virtual pointer(vptr) data
member. In the program we have printed the values of the
vptr for each of the Base, Derived1 and Derived2 objects.
So the size of the object will be 4 bytes more than
expected because of the addition of the vptr data member.
The virtual pointer vptr is nothing but the address to the
Virtual Table which in turn contains the starting addresses
of the virtual functions.

From the output we can make the following diagram


pictorially.

Base Object ( bobj )


Virtual Table Entry for Base

0x80491c0 (vptr)
0x804880A

Data Member ( x )
0x80487DE

Derived1 Object ( d1obj )


Virtual Table Entry for Derived1

0x80491b0 (vptr)

0x80487B2

Data Member ( x )

0x80487DE
Data Member ( y )

Derived1 Object ( d1obj )


Virtual Table Entry for Derived2

0x80491b0 (vptr)

0x804880A

Data Member ( x )

0x8048786
Data Member ( y )
When we call function1 through the base pointer pointing
to derived1 object it first accesses the vptr of the derived1
object and then accesses the V table for derived1 class.
Then it offsets into the table and gets the starting address
of the function and then executes the function. In cases
where the derived class does not override the base class
implementation of a function the V table will contain the
starting address of the base version of the function.

46. What is an inline function ? What are the advantages of


using an inline function ?

Inline functions are functions where the body of the


function replaces the actual function call. Thus by inlining
functions we eliminate the overhead of a function call.
Usually short functions ( functions whose definition is not
more than a few lines of code ) should be made as inline
functions. To inline a function is just a request made to the
compiler. It is up to the compiler whether to honor the
request or not. The only disadvantage of in-line functions is
that it could increase the code size especially if the inline
function is called repeatedly.

The following functions cannot be inlined :


• Functions that are recursive
• Functions that contain a static variable
• Functions that contain a switch statement or goto
statement
• Functions that contain loops

47. What are virtual classes ?

48. Explain the following relationships :

a. is a
b. has a

The is-a relationship is explained in Question 5


( inheritance ). The has-a relationship is explained in
Question 49 below.
49. Compare and contrast Aggregation Vs Composition

Both Aggregation and Composition signify “has a”


relationship. But in the case of aggregation the part is a
distinct entity which has a life of its own irrespective of the
whole. For e.g., The room “has a” table. The table is a
distinct entity. It can be there even if the room is
destroyed. It has meaning even without the room.

In UML aggregation is represented as shown below.

ROOM TABLE

In the case of composition the part cannot live without the


whole. It has no meaning without the whole. For e.g., the
body “has a” heart. The heart cannot beat without the
body. If you destroy the body so will the heart. The heart
has no meaning outside of the body.

In UML composition is represented as shown below.

BODY HEART

50. What is name mangling ? Why is it done ?

Name mangling is a concept unique to C++. It is not found


in C. In C++ functions can be overloaded and hence they
can have the same names. Also we have the concept of
namespaces which allow variables with the same name as
long as they are in different name spaces.

At the lower level linkers expect functions and variables to


have unique names. So the C++ compiler mangles the
names in such as way that every function name and every
variable name is unique. There are several rules that are
followed for name mangling. For e.g., the class variables
contain the class name along with the variable name in the
mangles form to uniquely identify them.

51. Provide the output for the following program ?

#include <iostream>
using namespace std;

class base
{
public:
int bval;
base(){ bval=0;}
};

class deri:public base


{
public:
int dval;
deri(){ dval=1;}
};

void SomeFunc(base *arr,int size)


{
for(int i=0; i<size; i++,arr++)
cout<<arr->bval << “ “;
cout<<endl;
}

int main()
{
base BaseArr[5];
SomeFunc(BaseArr,5);
deri DeriArr[5];
SomeFunc(DeriArr,5);
return 0;
}
00000
01010

Here an array of objects is defined. When the line


base BaseArr[5];

is executed the array of objects to base class is created


and initialized as shown in the figure

BaseArr[0]
0

BaseArr[1]
0

BaseArr[2]
0

BaseArr[3] 0

BaseArr[4] 0

Now when we pass an array to the function we pass the


address of the first element (pointer to the first element).
So in a for loop we move from one object to another object
and print the value of bval which is initialized to 0 in all the
objects.

When the statement


deri DeriArr[5];

is executed for each of the object the base class


constructor followed by the derived class constructor is
called and the members bval and dval are initialized as
shown in the figure below.

Though we pass the DeriArr to the function which is


actually a pointer of the deri class the function accepts
only a pointer to base class. So inside the function we
increment the pointer using arr++ it increments to what it
thinks is the next base object. The pointer is incremented
by the size of a base object only. Here we have to
remember that a base class pointer has no idea of the size
of derived class object. So we have to be careful when we
pass a derived class pointer when actually the function
expects a base class pointer. Hence in this case it prints

01010

DeriArr[0] 0

DeriArr[1] 0

DeriArr[2] 0

DeriArr[3]
0

DeriArr[4] 0

52. Provide the output of the following program :

#include <iostream>
using namespace std;
int x;

int & f()


{
return x;
}
int main()
{
f() = 100;
cout << x << endl;
return 0;
}

This does not give any compiler error for the statement f() = 100.
The output of this program is 100 ( value of x ). Here we should
understand that when a function returns a reference then that
function can be used on the LHS of an assignment statement. The
value of the expression on the RHS is assigned to the variable
whose reference is returned by the function. The one and only one
possibility where a function call can be made on the LHS of an
assignment statement is when the function returne a reference.
This is also one of the important advantages of reference variables.

53. Provide the output for the following program :

float f(float i)
{
return i/2.0;
}
double f(double i)
{
return i/3.0;
}

int main()
{
float x = 10.09;
double y = 10.09;
cout << f(x);
cout << f(y);
cout << f(10);
return 0;
}
x is float hence f(x) will call float f(float i)
y is double hence f(y) will call double f(double i)
f(10) is ambiguous since it does not know which f() to be called ?

54. Provide the output for the following program :

int f(int a, int b)


{
return a + b;
}

int f(int a, int &b)


{
return a – b;
}

int main()
{
int x = 1, y = 2;
cout << f(x, y)
}

In this case only way to know that a reference parameter is


passed is by looking at the prototype or the function
header. The call to the function will be identical in both the
cases ( where both the parameters are passed by value
and where one of them is passed by value and the other is
passed by reference. So the call f(x, y) in this case is
ambiguous since it does not know which function to call. In
fact to further complicate the matter we can add another
overloaded function that accepts both parameters as
reference.

int f(int &, int &b)


{
return a *b;
}

55. Provide the output for the following program :

int f ( int a )
{
return a * a;
}

int f ( int a, int b = 0 )


{
return a * b;
}

int main()
{
cout << f(10, 2);
cout << f(10);
return 0;
}

There is ambiguity in the call f(10). Should it call f(int, int)


or
f(int) ?

56. One of the major benefits of inheritance is said to be code


reuse ? Can you explain how ?

This can be explained with an example. Let us take the


base class shape and the derived classes triangle, circle.
Here we can define the common characteristics of all
shapes such as area, perimeter etc in the base class
shape. We can define the specifics in the derived classes.
For e.g., for triangle class we can define height, base etc.
For circle it will be radius (or) diameter. So when we want
to add a new derived class say rectangle all we need to do
is just add code for the specifics. The generics are already
available under the shape base class.

Thus we do not reinvent the wheel again and again. We


reuse what we already have. This not only simplifies the
design but makes it less error prone.

57. Encapsulation is said to protect data from the outside


world
? Explain with an example of your choice of how it protects

the data

Encapsulation protects the data as they are not exposed


directly to the outside world. As clients of the class we
have to access the public methods to access/modify data.
But the implementation ensures that the integrity of data
is maintained at any point of time. So if a client attempts to
modify the data through an object of the class he has to
use the interface provided. The implementation is hidden
from the client and they ensure the validity of data always.

For e.g., the implementation of the Date class will ensure


that clients cannot store an invalid date in a date object.

58. If you have to allocate dynamic memory for your program


which library function would you prefer : malloc or new ?
Justify your answer.

I would prefer new for the following reasons :


a) I don’t have to calculate the number of bytes or use the
sizeof operator during the call
b) I don’t have to typecast it to the appropriate pointer
type
on the LHS

59. What are the various types of templates ? Explain what are

the advantages that we derive by using templates ?

There are 2 types of templates :

a) Function templates
b) Class templates

Templates are very useful as they enable us to create just


one generic function for different data types. For e.g., to
create the average of items the functionality is the same
whatever be the data type. Also class templates are the
backbone for the Standard Template Library. A good
example of a class template is a generic class that can
create a linked list of any data type say characters,
integers, floats etc.

60. What is object slicing ? Explain with an example.

61. What do you understand by the term “exception”. Provide


3
situations where it will cause an exception.

As the English meaning of the term indicates exception is


something that is unexpected ( not the rule ). So we have
to handle all the exceptions that our code is likely to
generate. Some situations that cause exceptions are :
1. Call to the new fails ( unable to provide memory )
2. Opening a file for reading fails
3. When we try to access an array beyond the limit ( array
boundary violation )

62. Can you summarize the essential differences between a


reference and a pointer ?

References POINTERS
Implemented internally as
constant pointers
References must be initialized Pointers may or may not be
initialized
Once a reference is initialized A pointer initialized to point to
it cannot be modified. one object at a later point of
time be made to point to
another object of the same
datatype
When a function returns a Not possible with pointers
reference the function can be
used in the LHS of an
assignment statement
Usage of references in easy Usage of pointers is messy
and elegant
Not possible with references Pointers can be incremented,
decremented and can be used
in arithmetic expressions

63. What are accessor and mutator functions ? Why are they
called so ?

Accessor functions as the name indicates are const


member functions which can only access the data. These
are normally the get functions.

Mutator functions ( also called as Modifier functions ) are


used to modify the data. These are normally the set
functions.

Example of a class with accessor and mutator functions :


class Base {
int i;
public:
void geti () { cout << i << endl; } const; // accessor

// function
void seti (int a) { i = a; } // mutator function
;}

64. Can we declare a static function as virtual ? Justify your


answer.

Static functions can be called without an object. Hence


they cannot be made virtual. For e.g., a static function can
be called using the class name and the scope resolution
operator as shown below

<Class name>::<Static function name>(<arguments>);

65. What is the size of an object of the following class ?

class Demo {
int x, y, z;
public:
void set ( int a, int b, int c )
{
x = a;
y = b;
z = c;
}
void get() const
{
cout << x << ‘ ‘ << y << ‘ ‘ << z << endl;
}
};

Given that an integer takes 4 bytes ( 32 bit system ) and


the set and get methods occupy 12 bytes in memory.

We have to remember that member functions are shared


by all objects of the class meaning that there is only one
copy of the member functions present in the memory. It is
not available in the objects. Only data members are
available for each and every object. So an object of the
Demo class will be of size 12 bytes ( 3 integers each of 4
bytes )
66. What is the size of an object of the following class ?

class Test {
public:
void show()
{
cout << “No private data members for this
class” << endl;
}
};
When there are no data members objects can still be
created and can invoke the member functions. Then such
objects are created with the minimal memory unit namely
1 byte. So an object of the Test class will be 1 byte in size.

67. Explain what do you mean by protected inheritance

When a base class is inherited as protected then the public


and protected members of the base class will become
protected members of the derived class.

68. What is the Standard Template Library (STL) ? Have you


used it ?

Relational Database Management Systems ( RDBMS )

1. How do you create a table and update it ?

Table can be created with the CREATE TABLE DDL.


create table employee
(
first varchar(15),
last varchar(20),
age number(3),
address varchar(30),
city varchar(20),
state varchar(20),
doj date
);

Table can be updated with the Update statement.

UPDATE student
SET lname = ‘Sundar’ and fname = ‘Syam’
where STUDENT_ID = 10;

2. What is normalization ? Give an example.

Normalization is the process in the database design where


eliminate redundancy of data thereby improving the integrity of
the database. We know that when data is redundant ( the same
data stored in multiple tables ) updation is difficult and there are
chances where we miss to update at all places. This will in turn
mean that the data stored in the database is inconsistent and
hence unreliable. Normalization ensures the integrity of the
database. We proceed with normalization in 3 steps

First Normal Form

Eliminate repeating groups


Eliminate multi-valued attributes in column

Second Normal Form

It should be in First Normal Form +


All attributes should be wholly dependent on the primary key

Third Normal Form

Transitive dependencies should be eliminated

3. Explain the terms : full dependency, partial dependency and


transitive dependency. Provide an example to illustrate what
transitive dependency means ?
4. What are the pros and cons of normalization ?

Normalization is required to ensure the integrity of the database


and to minimize the redundancy of the data stored in the
database. Contemporary database design requires that we
normalize the database at least to bring it to the 3rd Normal
Form. Though we can normalize beyond that it is not expected as
the benefits are too few for the costs involved.

The only cost associated with normalization is the increase in the


number of tables and thereby the size of the database.

5. What is a trigger ? What are the different types of triggers ?

Triggers are procedures defined by the user that are executed


when INSERT, UPDATE or DELETE statements are executed.
Triggers are executed mainly for the following purposes :

1. To enforce certain rules


2. To prevent invalid transactions

The 2 types of triggers are :

a) Row Triggers
b) Statement Triggers

For e.g., We can have a trigger when we want to check if a


particular value for an attribute is within the valid range and
allow the row to be inserted or updated only if it is within the
valid range.

6. What is a query ? What is a sub query ? Give an example.

A query is used to obtain information from relational


databases. Queries can be constructed in the SQL
( Structured Query Language ). For e.g.,

SELECT NAME from STUDENT


WHERE ROLL_NUMBER = 78;

ROLL_NUMBER STUDENT_NAME
10 Rahul Roy
22 Pankaj Kapoor
78 Deeksha Sharma
56 Ram Narayan
A sub-query is a query within a query. The sub query can
be illustrated with the following 2 tables.

AUTHORS TABLE

AUTHOR_ID LNAME FNAME NUMBER of


BOOKS
PUBLISHED
1 Doe John 12
2 Smith Mary 4
3 Fryer Scott 7

BOOKS TABLE

TITLE AUTHOR_ID PUBLISHER


Antartica 3 Penguin
Understanding 2 Tata McGraw-Hill
C++
Object Oriented 2 Tata McGraw-Hill
Design
DBMS 1 Tata McGraw-Hill
Wild Russia 3 Penguin

SELECT TITLE from BOOKS where


AUTHOR_ID = ( SELECT AUTHOR_ID from
AUTHORS where
LNAME = ‘Scott’ and
FNAME = ‘fryer’ )

7. There is table called LIBRARY with fields NAME, ISSUE_DATE and


RETURN_DATE. Select the names of all the books which are
returned 5 days after their issue ?

8. What are stored procedures ?

9. What do you mean by a relational database ? What are its


properties ?

10. What is indexing ? What are the benefits ? What is the


mechanism behind indexing ?

11. What is a view ?


12. What are the different types of joins ? Explain with an
example.

13. What is a master table ?

14. What is Data Warehousing ? What are its applications ?

15. What is Data Mining ? What are its applications ?

16. How do you connect to your database from a java application


?

17. What is referential integrity ? When is it said to be violated ?

18. What is a cursor ?

19. What is a candidate key ? How is it different from a primary

key ?

20. Explain what is meant by Boyce Codd Normal form ? If a


schema is in 3rd Normal form does it also mean that it is in
Boyce Codd Normal form ?

21. What is a self-referential key ? Provide an example to


illustrate the same.

22. Explain the following relationships between entities with an

example

i. One to One
ii. One to Many
iii. Many to One
iv. Many to Many

23. Explain the significance of the Entity Relationship Model.


Why is it called the top-down approach to database design
?

24. What is meant by transitive dependency ? Illustrate with an

example
25. Classify the SQL statements according to their
functionality.

26. Provide an example to illustrate the use of UNION and


INTERSECT keywords in SQL

27. The following is an SQL statement with a HAVING clause.


Why can’t we replace the HAVING clause with a WHERE
clause ?

SELECT sno, avg(marks) from STUDENT


GROUP BY sno
HAVING avg(marks) > 60

28. Why can’t we use files instead of databases to store our


data
? Which is preferable and why ?

29. What are all the commercial RDBMS systems that are
currently available ? Which is the most popular one ?

30. Explain the differences between inner join and outer join
with an example

31. As a user we are not actually concerned about how data


from the tables is physically stored in the disk. How is this
abstraction achieved ?

32. What is a functional dependency ? What are the different


types of functional dependency ? Explain with an example

33. What are the various types of constraints when you create
a
table. Explain each of them with an example.

34. What is a check constraint ? When would you need to


define
this constraint ?

35. Compare and contrast TRUNCATE Vs DELETE. When you


want to delete a table which one would you prefer to use ?

Why ?

36. In a Employee table I perform the following queries :


i. count(*)
ii. count(emp_id) where emp_id is the primary key
iii. count(email) where email is non-key attribute

Will it return the same values for all the 3 queries or could
it be different ? Justify your answer.

37. Examine the table below and answer the questions

CUSTOMER_LOAN

Cust_ID Loan_No Loan_Amount

1 1012 2000
2 1023 8000
3 1032 3000
1 1054 1000
1 1075 5000
3 1081 4000

SELECT Cust_ID, SUM(Loan_Amount)


FROM CUSTOMER_LOAN
GROUP BY Cust_ID
HAVING Loan_No > 1050

What is the output of the above query ?

38. Study the following tables carefully. Answer the questions


that follow. For STUDENT table Student_No is the primary
key. For COURSE table Course_No is the primary key. For
STUDENT_COURSES Student_No and Course_No together
form the primary key.

STUDENT

Student_N Student_Nam Mobile_Numbe


o e r
1 Vishal 9863454454
2 Vignesh 9734555545
3 Ramesh 9663543543
4 Suresh 9571437474

COURSE

Course_No Course_Name Number_of_


Credits
Cosc1300 C Programming 3
Cosc1400 Operating 2
Systems
Cosc1500 Data Structures 2
Cosc1600 RDBMS 3

STUDENT_COURSES

Student_N Course_No Marks


o
1 Cosc1300 87
1 Cosc1400 75
1 Cosc1500 66
1 Cosc1600 82
2 Cosc1300 45
2 Cosc1400 62
2 Cosc1500 75
2 Cosc1600 54
3 Cosc1300 75
3 Cosc1400 72
3 Cosc1500 78
3 Cosc1600 84
4 Cosc1300 66
4 Cosc1400 55
4 Cosc1500 50
4 Cosc1600 60

A) What happens when you try to add a new row in the


STUDENT_COURSES table as shown below

INSERT INTO STUDENT_COURSES values ( 5,


‘Cosc1300’, 95 )
B) What happens when you try to add a new row in the
STUDENT_COURSES table as shown below

INSERT INTO STUDENT_COURSES values ( 4,


‘Cosc1700’, 35 )
C) What happens when I try to delete the student with
Student_no 1 from the STUDENT table ?

D) I want the name of the students who have scored an


average of 75. Write an SQL query to perform an
operation
E) For each student I want to display his marks in
ascending order. Write an SQL query for this operation

F) Identify the candidate keys in the STUDENT table. Why


was Student_no chosen as the primary key ?

G) Draw the Entity Relationship Diagram for this schema

H) Is this schema in 3rd Normal Form ? If not how can you


bring it to 3rd Normal Form.
JAVA, NETWORKING & OTHER AREAS

1. How is java platform independent ?

When java code is compiled by the java compiler (javac) it


generates a byte code which is platform independent. This code
can be run anywhere. Each of the platforms that support java
such as Unix, Windows etc. have their own Java Virtual
Machine(JVM). The byte code is interpreted by the JVM specific to
the platform where we want to run the java byte code. The
diagram below explains the concept. Hence the adage “Compile
once, Run anywhere” for java programs.

JAVA PROGRAM

JAVA COMPILER ( PLATFORM SPECIFIC )

BYTE CODE ( PLATFORM INDEPENDENT )

JVM (UNIX) JVM (WINDOWS) JVM (MAC)

RESULT (OUTPUT)

2. What is a Web Server ?


A Web Server is a computer that responds to HTTP requests from
Web clients ( browser ) and delivers the information requested
by the Web client. For e.g., Apache Web Server

The underlying communication between the Web Server and the


Web Client happens through TCP/IP protocol

HTTP Request

Web Client
Web Server

HTTP Reply

When we browse the internet behind the scenes this is what


happens. When we type the URL http://www.microsoft.com we
are requesting the Web Server for Microsoft Corporation to
provide us the home page ( landing page ) of their web site.

3. How will you find the ip address of a machine in unix ?

You can find the ipaddress of a machine in unix by giving the


ifconfig command.

$ ifconfig –a ( On solaris )

If you know the machine name and looking for ipaddress you can
use the nslookup command

$ nslookup <machine name>

4. What happens behind the scenes when you send an email ?

When you send an email you use an email clients such as


Eudora or Microsoft Outlook to send your message. It is
transmitted to your email server (SMTP server). The server
uses the SMTP protocol to send the message to the
destination email server. This could be routed through
several routers in the Internet. When it finally reached the
destination email server the person to whom it is
addressed can used the Post Office Protocol (POP) to
download the messages from the email server to his/her
email client.
5. What are the various layers in the OSI model ? Describe the
functionality of each layer.

6. What is TCP/IP protocol ?

TCP/IP stands for Transmission Control Protocol/Internet


Protocol. They are the backbone for the internet. The TCP
protocol is a transport layer protocol where as the Internet
protocol is a Network layer protocol.

APPLICATION LAYER

PRESENTATION LAYER

SESSION LAYER

TRANSPORT TCP

NETWORK IP

DATA LINK

PHYSICAL

TCP is responsible for error detection and correction.

IP is responsible for routing of the packets between the


source and destination.

Some of the typical protocols under the TCP/IP suite are


Telnet, FTP, SMTP, ICMP, POP, IMAP etc.

7. What are the differences between TCP and UDP ?

8. Compare and contrast Virtual Circuits Vs Datagrams

9. What do you understand by the term subnet ?

10. What are the current trends in mobile telephony ?

We are progressing into 3G(UMTS and CDMA 2000) from


2G (GSM) and 2.5G (Edge).
The latest trends are running multimedia applications on
the mobile phone, faster data rates, more number of
supplementary services. The mobile is no longer restricted
to voice calls. There have been many applications
developed on various platforms for the mobile handset.
There is enormous competition from companies providing
mobile devices and services vying for the customer
market.

11. Explain the various network topologies

The various network topologies are :

1. Token Ring
2. Star
3. Bus

12. What is a container ?

13. What are servlets ?

14. What is the main difference between JSP and Servlets ?

15. Have you ever used threads ?

16. How does your Bluetooth device work ?

17. What is satellite communication ?

18. How do you access the contents of a file in C# ?

19. What is ADO ?

20. What is internet ? How does it work ?

21. Explain image processing

22. Explain how the computer works

23. What are fuzzy logic systems ?


General Questions

1. Why do you want to join IBM ?

The company website and the presentation by IBM people should


help you come up with meaningful answers to this question.
That will also show how attentive you were during the
presentation. You have to tailor make your answer to fit the
company’s requirement.

2. Why are you not going for higher studies ?

There could be several reasons such as


• Family commitment
• Take up study part time while you work after a while
• You are more interested in learning through experience in
an industry rather than an academic institution
You need to choose the relevant one for your particular situation.

3. What are your strengths & weaknesses ?

When you talk about your strengths just mentioning that you are
hard-working, dedicated, honest etc. will not do. Everybody can
mention these eye catching words. What you need to do is find
out from your recent past an example to prove at least 1 or 2 of
the strengths that you have mentioned. That will also set you
apart from others. This should be an honest attempt.

When you tell about your weakness ensure that the weakness
that you mention will not affect your performance with the
company. Don’t say something like “I am always late in
submitting assignments”. You may be really honest. But your
weakness will disqualify you then and there. A company needs to
deliver products/services on time. For e.g., you can say that you
have a craving for chocolates and you are trying to control it by
not buying and keeping stock of the same.
4. Which areas do you want to improve ?

Mention an area where you have improved a lot and there is still
scope for improvement. For e.g., you can say that your skill in a
programming language such as C has improved a lot with a lot of
practice and you can admit that there is still scope for
improvement.

5. What is the foolish thing that you have done ?

6. How will you react with a situation where you are being blamed
for no fault of yours ?

For this question you need to be careful with your answers. You
should not complain against the person blaming you
immediately. First talk to the person blaming you and try to find
out why he is blaming you. Sometimes we do things which we
think is all right but it is not so from others perspective. By
talking to the person you will know if you really are at fault. If
both of you do not agree then it would be wise to consult a
neutral person to know his opinion. If it turns out that you are
being blamed unnecessarily then only should you take it up with
your higher-ups.

7. Why do you want to join an IT company ? Why are you not going
for core companies in your area ? ( non IT/CS/MCA students )

Non IT students can mention the interests that they have in the
software field. There is no harm in mentioning that the core
companies do not recruit that many as the IT companies and in
the present day job market you just want to have a job in hand.

8. What is your perception about the software industry ?

9. Choose a topic of your own interest and explain

10. Will you be flexible ?


( When you answer yes for this question justify it with an
good example that shows how flexible you are )

11. Where do you see yourself in the next 5 years ?


( This is a favorite question with interviewers. Basically
they want to find out what your long term goals are.
Prepare well for this question on what you want to become
in 5 years. Those who are interested in leadership can
aspire for Team Lead, Project Manager etc. Those who are
interested in design activities can opt for Sytems Analyst,
Software Architect etc.

12. Do you have any questions for me ?

You should definitely ask 1 or 2 questions. That will speak


about your interest with the company. Saying “I don’t have
any questions” will make the interviewer think that you are
casual and are not showing interest. Going through the
company’s website and understanding the products and
services offered by the company, concentrating on the
presentation slides shown by the company should help you
come up with meaningful questions. Also if you were not
sure about the answer you had given for a particular
question you can request the interviewer that you are
interested in knowing the answer for the same. This will
show the interviewer that you are interested in learning.
This suggestion is provided only if you don’t have other
questions.

13. We have a scale and 7 balls. 1 ball is heavier


than all the rest. How to determine the
heaviest ball with only 3 possible weighing
attempts?

You might also like