This page lists some common interview questions for software engineers.
Click on the question to see its answer.
Man 1:1 minute to cross Man 2: 2 minutes to cross Man 3: 5 minutes to cross Man 4: 10 minutes to cross
(X - A) * (X - B) * (X - C) * ... * (X - Y) * (X - Z)
struct rect { int top, bot, left, right; } r1, r2;
tr -str1 -str2.It reads stdin and prints it out to stdout, replacing every occurance of str1[i] with str2[i]. eg.
tr -abc -xyz to be and not to be <- input to ye xnd not to ye <- output
if (next < max) next++; else next = 0;and the fragment:
next += (next < max)? (1):(-next);
while((d=c=getch(),d)!=EOF&&(c!='\t'&&c!=' '&&c!='\b')) *buff++ = ++c;
delete this;
int __ = 0; main() { int ___ = 2; printf("%d\n", ___ + __); }
The technical interview is perhaps the most intimidating and
mysterious event that job hunters experience in the quest for that
"killer offer." The rigor and format of the technical interview varies
from one company to the next, but there are some fundamental
similarities. An interviewer presents you with a problem to be
solved. The interviewer may leave the room and give you some time to
work the solution out before returning. Or the interviewer may wait
patiently while you study the problem and figure it out. The
interviewer may even start quizzing you right away about aspects of
the problem and approaches to solving it. Some of these problems can
appear quite challenging, especially if you've never been through a
technical interview before. To make matters worse, simply getting the
answer to the problem may not be enough to land the job. On the other
hand, getting the correct answer may not even be necessary. What is
an interviewer looking for in candidates during the technical
interview? Interviewers recognize that this setting is, by its very
nature, stressful. Otherwise competent candidates may be completely
stumped by an interview problem only to discover an elegant, simple
solution later that night. Interviewers may be interested in seeing
how you work under stressful situations or how well you adapt. It is
worth noting that interviewers are more interested in seeing how you
work than seeing whether you can come up with the correct answer. In
this article, I will deal with both how you can better showcase your
skills and experience, and what kinds of problems you can expect to be
asked.
These basic rules are often taught to programmers and are (or at any
rate, should be) drilled into your head in computer-science
classes. For some reason, however, they are easily forgotten during
the technical interview. Being one of the few candidates careful and
experienced enough to remember these important steps can make the
difference between getting an offer and getting the cold shoulder.
Don't be afraid to ask for clarifications of the problem or the
requirements for the solution.
You should never assume that you have been given all the data
necessary to solve the problem to the satisfaction of the
interviewer. This is especially likely to be the case when
interviewing with IT consulting companies. In this environment, the
client may need some prodding in order to provide a complete
specification. So, the reasoning goes, ideal candidates will be
willing to talk to the client to figure out the expected inputs, the
desired outputs, the data ranges and data types, and the special
cases. The ideal candidate will ask these questions rather than spend
all the allotted time coming up with a solution that doesn't meet the
client's needs. The first thing to do, then, is to make sure that you
and the interviewer agree on what the problem is and what an
acceptable solution would be. Make all of your assumptions explicit
and up-front, so the interviewer can correct you if you are mistaken.
If the interviewer stays in the room after presenting the problem, he
or she is interested in seeing how you analyze and approach a
problem. Of interest are how possible solutions are considered and
eliminated. And frankly, watching a candidate sit and stare at a
problem isn't all that entertaining for the interviewer. Always allow
sufficient time for design. The worst thing that you can do while
attempting to solve a technical problem is to dive right into coding a
solution and get about half way through it before realizing that the
approach is all wrong. This is where a little forethought can save a
great deal of effort and embarrassment. Don't worry about running out
of time to answer the question before finishing the code for the
solution. The idea, the algorithm, and the approach are the most
important elements here. If you're having trouble writing the code,
offer to explain the algorithm. Stress and anxiety can make the
technical interview more difficult than it needs to be. If you find
yourself having difficulty with programming syntax or constructs, you
should make sure that the interviewer knows that you understand the
problem and its solution. While it's best to get both the algorithm
and the implementation correct, it's far better to get points for
demonstrating facility with one than fail to demonstrate either. Be
prepared to identify bottlenecks, possible optimizations, and
alternative algorithms. Just because you've found one solution that
produces the correct output, doesn't mean the problem has been solved
to the interviewer's satisfaction. Interviewers, hinting at possible
improvements, may prod you at this point. Occasionally, you may take
an approach that the interviewer didn't anticipate. At this point, an
interviewer may ask you to take a more conventional approach. This
doesn't mean that you've done anything wrong; very often, an
interviewer may be leading you along a particular approach with a
purpose in mind. The interviewer may be intending to ask follow-up
questions or present new problems that build on a particular solution.
Initialize all variables, give variables descriptive names, and always use comments.
Interviewers may be watching your solutions to determine whether you
follow good programming practices. Good programming practices make it
easy to understand other people's code. This means that there aren't
cryptic variables, functions with undocumented side effects,
obfuscated algorithms, and sloppy (read: buggy) code. Just because you
are being interviewed (and therefore, coding on a whiteboard or on a
piece of paper) doesn't give you an excuse to be sloppy or
lazy. Commenting code for an interview may seem like a waste of time,
but some interviewers do look to see that candidates write comments
while coding or before coding, rather than adding them in as an
afterthought.
Candidates forget to do this frighteningly often. In fact, practicing
programmers sometimes forget to do this. That's how bugs get
started. You should verify that your code properly handles cases where
inputs are negative or zero, lists are empty, strings are empty, and
pointers are NULL. This is also a good habit to have after you get the
job. Expect bad input from users. Users rarely do as they are
expected. You should protect your code, and return a descriptive error
back to the user. Display enthusiasm. Don't underestimate the
importance of your appearance and attitude during the interview. While
your skills and experience may be the focus of the technical
interview, looking bored or uninterested may do more to sabotage your
chances than blowing an interview problem.
In addition to these basic rules for the technical interview, there
are some other things worth pointing out. Interviewers don't always
have the chance to examine your résumé in advance. This means that the
interviewer may not be aware of your past work experience. Don't
hesitate to point out experiences working in teams (whether as a part
of a past job, a class programming project, or a hobby), working on
large projects (paying attention to time spent on design,
implementation, and testing), dealing with customers to define
requirements, and managing people and projects. Interviewers are
interested in hearing about successes as well as failures. When these
past experiences weren't successful, you should point out the lessons
learned or wisdom gained as a result of these failures. Interviewers
want to see that candidates who have had negative experiences are not
going to repeat their mistakes.
When preparing for a technical interview, you should review basic structures (linked lists, binary trees, heaps) and algorithms (searching, sorting, hashing). Having a mastery of these topics will likely give you all the necessary knowledge to tackle the problems you will encounter during the technical interview. Also, review the areas for which you're interviewing. If you're interviewing for a systems programming job, review the differences between threads and processes, OS scheduling algorithms, and memory allocation. If you're interviewing for a job that requires experience with an object- oriented language, spend some time brushing up on object-oriented methodology.
Fortunately, some of the same problems come up with surprising
frequency. Even if a given interviewer doesn't use any of the problems
I present here, studying them should give you insight into solving
other problems.
The specific details of your interview will, of course, depend on a
number of factors -- the type of job you are applying for, the needs
and expertise of the technical interviewer, and guidelines set forth
by the organization seeking to hire you. Still, if you generalize and
apply the tips I've presented here, you should be well on your way to
getting the programming job that you want.
The cut (plane) should pass through the center of the two rectangles:
the outer cake and the inner hollow area. Since any plane passing
through the center of the cuboid will divide the volume in two halves,
both the cake and hollow area are divided into two equal halves.
Many solutions: Bit vector, sorting...
The answer is "many points". The set of such points is given as {North pole, special circle}.
From north pole, walking one mile south followed by one mile east still keeps you one mile south of North pole.
The special circle consists of a set of points defined as follows.
Let's say you were to locate a spot near the South Pole
where the circular distance "around" the Earth's North-South axis is 1 mile.
The path of such a journey would create a circle
with a radius of approximately 840.8 feet (because C=2.r.pi). Call this
point X. Now consider another point Y one mile north of X.
The special circle is the circular path around North-South axis
going through Y. If you begin you journey from any point (say Y1) on this
special circle, and travel one mile south, you get to a point (say X1)
on the circle of point X.
Now one mile east will bring you back to X1, because circumference of
circle of X is 1 mile. Then one mile North brings you back to Y1.
(Answer supplied by Kristie Boman)
The answer is that you need to store all possible configurations of
the board and the move that is associated with that. Then it boils
down to just accessing the right element and getting the corresponding
move for it. Do some analysis and do some more optimization in storage
since otherwise it becomes infeasible to get the required storage in a
DOS machine.
All three should move in the same direction - clockwise or anticlockwise.
Probability is 1/4.
1 and 2 cross together. 1 comes back. then 3 and 4 cross. 2 comes
back. then 1 and 2 cross. Total time is 2+1+10+2+2 = 17.
Take one pill from first, two from second, three from third and so
on. Total pills are n(n+1)/2 and should weigh 10n(n+1)/2. If it weighs
x gm less than that then the x'th jar is contaminated, since we took x
pills from that jar which weighed 1 gm less.
If distance is X miles between NY and LA, then it takes X/(15+20)
hours for the trains to collide, and bird will have travelled
25X/(15+20) = 5X/7 miles in that time.
Answer is 0, because (X-X) is present in the product.
Please see this (courtesy: Ivan Yu).
The basic idea is to draw one quadrant and replicate it to other four
quadrants. Assuming the center is given as (x,y) and radius as r
units, then start X from (x+r) down to (x) and start Y from y up to
(y+r). In the iteration, keep comparing is the equation is satisfied
or not within an error of one unit for x and y. If not then re-adjust
X and Y.
void putlong(unsigned long x) { // we know that 32 bits can have 10 digits. 2^32 = 4294967296 for (unsigned long y = 1000000000; y > 0; y /= 10) { putchar( (x / y) + '0'); x = x % y; } }
if (x && !(x & (x-1)) == 0)
Apparently the if then else solution has a jump when written out in assembly.
if (x == 0) y=0 else y =x
There is a logical, arithmetic and a datastructure soln to the above
problem.
Pretty simple if you know some assembly and some fundaes on number
representation.
Multiply by 8 (left shift by 3 bits) and then subtract the number.
(x << 3) - x
This is a typical, can-you-program warm-up question. Example 1 shows
the iterative and recursive solutions. Notice that in both solutions,
I check the input values and boundary conditions. Factorials of
negative numbers are undefined, and the factorial of both 0 and 1 are
1. The functions in Example 1 handle these cases correctly, and they
initialize all variables.
Example 2 contains both the iterative and recursive solutions. The iterative version maintains variables to hold the last two values in the Fibonacci sequence, and uses them to compute the next value. Again, boundary conditions and inputs are checked. The 0th number in the Fibonacci sequence is defined as 0. The first number in the sequence is 1. Return -1 if a negative number is passed.
The recursive version of the Fibonacci function works correctly, but
is considerably more expensive than the iterative version. There are,
however, other ways to write this function recursively in C that are
not as expensive. For instance, you could maintain static variables or
create a struct to hold previously computed results.
Given a char pointer, strlen() determines the number of chars in a
string. The first thing that your strlen() implementation ought to do
is to check your boundary conditions. Don't forget the case where the
pointer you are given is pointing to an empty string. What about the
case where the pointer is equal to NULL? This is a case where you
should state your assumptions. In many implementations, the real
strlen() doesn't check to see if the pointer is NULL, so passing a
NULL pointer to strlen() would result in a segmentation fault. Making
it clear to your interviewer that you are aware of both of these
boundary conditions shows that you understand the problem and that you
have thought about its solution carefully. Example 3 shows the correct
solution.
To swap the values, you can carry out the following instructions:
Reg_1 = Reg_1 + Reg_2; Reg_2 = Reg_1 - Reg_2; Reg_1 = Reg_1 - Reg_2;
Contribute by John Foley:
#include <stdio.h> int main() { //--- constant data const int arr[] = {1, 1, 2, 4, 4, 7, 8, 9, 14, 14, 20}; const size_t arrlen = sizeof(arr)/sizeof(arr[0]); int i; for(i=0; i<arrlen; i++) { //--- if this is the first one, print no matter what // if not, skip if we just printed the same number if(i && arr[i] == arr[i-1]) continue; //--- print this number, update last item printf("%d\n", arr[i]); } return 0; }
It creates a mask over both the trailing zeros of an integer and the first set bit from right. For example if a is 10101100 then result is 00000111.
On the other hand, (a-1) AND a == 0 is different. It tests whether 'a' is a power of 2. Actually, it tests if a has only one instance of 1 bit, which is same as 'a' being power of 2. For example, if a is 00010000 then result is 0, and if a is 01001000 then result is 01000000 which is not 0.
(Thanks to Philip Shirey for correction)
The sum of the numbers 1 to n-1 is (n)(n-1)/2. Add the numbers on the
list, and subtract (n)(n-1)/2. The result is the number that has been
repeated.
You are presented with a linked list, which may have a "loop" in it. That is, an element of the linked list may incorrectly point to a previously encountered element, which can cause an infinite loop when traversing the list. Devise an algorithm to detect whether a loop exists in a linked list. How does your answer change if you cannot change the structure of the list elements?
One possible answer is to add a flag to each element of the list. You could then traverse the list, starting at the head and tagging each element as you encounter it. If you ever encountered an element that was already tagged, you would know that you had already visited it and that there existed a loop in the linked list. What if you are not allowed to alter the structure of the elements of the linked list? The following algorithm will find the loop:
The important realization for this problem is that the hour hand is
always moving. In other words, at 1:30, the hour hand is halfway
between 1 and 2. Once you remember that, this problem is fairly
straightforward. Assuming you don't care whether the function returns
the shorter or larger angle, Example 4 shows a solution to this
problem.
For the sake of this problem, assume that the string has been stripped
of punctuation (including spaces), and has been converted to a single
case. The most efficient way to detect whether a string is a
palindrome is to create two pointers. Set one at the beginning of the
string, and one at the end. Compare the values at those locations. If
the values don't match, the string isn't a palindrome. Otherwise, move
each pointer inward and repeat the comparison. Stop when the pointers
are pointing to the same position in the string (if its length is an
odd-number) or when the pointers have "crossed" (if the string's
length is an even-number). Example 5 shows the correct solution.
Assume that the file format is one byte for every pixel in the file, and that the approximation will produce one ASCII character of output for each pixel. This problem is easier to solve than it sounds. This is one of the tricks used in technical interview questions. Problems may be obscured or made to sound difficult. Don't be fooled! Take the time to think about the core of the problem. In this case, all you want is an algorithm for reading the values in a file and outputting characters based upon those values.
Eight-bit numbers can be in the range from 0 to 255. Two-bit numbers are in the range from 0 to 3. Basically, we want to divide the 256 numbers specified by an eight-bit number into four ranges, which can be indicated by a two-bit number. So, divide the range of 0 to 255 uniformly into four separate ranges: 0 to 63, 64 to 127, 128 to 191, and 192 to 255.
You then have to assign an ASCII character to each of those four ranges of numbers. For example, you could use "_", "~", "+", and "#". Then, the algorithm is as follows:
1. Open the file. 2. For every byte in the file: a. Read in one byte. b. If the value is in the range 0..63, we'll print '_'. c. If the value is in the range 64..127, we'll print '~'. d. If the value is in the range 128..191, we'll print '+'. e. If the value is in the range 192..255, we'll print '#'. 3. Close the file.
(answer : context switches, excessive buffer copying).
How can you optimise the communication? (ans : communicate through shared
memory on same machine, bypassing the kernel _ A Univ. of Wash. thesis)
given a linked list with the following property node2 is left child of node1, if node2 < node1 else, it is the right child.
O P | | O A | | O B | | O C
How do you convert the above linked list to the form without disturbing the property. Write C code for that.
O P | | O B / / / O ? O ?
determine where do A and C go
4, 3 at 20 mts, 50 mts and 80 mts.
Sibling and firstchild ptr.
A Casting is a mechanism built into C that allows the programmer to force the
conversion of data types. This may be needed because most C functions are very
particular about the data types they process. A programmer may wish to override
the default way the C compiler promotes data types.
It will promote it to an integer unless otherwise directed.
A statement is a single C expression terminated with a semicolon. A block is
a series of statements, the group of which is enclosed in curly-braces.
next = next + 1; and next++; and next += 1;
Comments in C begin with a slash followed by an asterisk. Any text may then appear including newlines. The comment is finished with an asterisk followed by a slash. Example:
/* This is a comment */
Not in standard (K&R) C.
If the test is at the bottom, the body of the loop will always be executed at
least once. When the test is at the top, the body of the loop may never be
executed.
next = 0; /* setup */while ( next < max) { /* test */ printf("Hello "); /* body */ next++; /* update */ }
and
for ( next = 0; next < max; next++) /* setup,test */ /* and update */ printf("Hello"); /* body */
next = 0; /* setup */do { printf("Hello"); /* body */ next++; /* update */ } while ( next < max); /* test */
It is C's form of multiway-conditional (a.k.a case statement in Pascal).
The break statement unconditionally ends the execution of the smallest
enclosing while, do, for or switch statement.
The break terminates the loop. The continue branches immediately to the test
portion of the loop.
Outside a function definition (global scope, from the point of definition
downward in the source code). Inside a block before any statements other than
variable declarations (local scope with respect to the block).
A definition tells the compiler to set aside storage for the variable. A
declaration makes the variable known to parts of the program that may wish to
use it. A variable might be defined and declared in the same statement.
A function prototype tells the compiler to expect a given function to be used
in a given way. That is, it tells the compiler the nature of the parameters
passed to the function (the quantity, type and order) and the nature of the
value returned by the function.
The process by which the C compiler ensures that functions and operators use
data of the appropriate type(s). This form of check helps ensure the semantic
correctness of the program.
This is a part of a variable declaration that tells the compiler how to
interpret the variable's symbol. It does not in itself allocate storage, but it
usually tells the compiler how the variable should be stored.
static - Variables are defined in a nonvolatile region of memory such that they retain their contents though out the program's execution.
register - Asks the compiler to devote a processor register to this variable in order to speed the program's execution. The compiler may not comply and the variable looses it contents and identity when the function it which it is defined terminates.
extern - Tells the compiler that the variable is defined in another module.
volatile - Tells the compiler that other programs will be modifying this
variable in addition to the program being compiled. For example, an I/O device
might need write directly into a program or data space. Meanwhile, the program
itself may never directly access the memory area in question. In such a case, we
would not want the compiler to optimize-out this data area that never seems to
be used by the program, yet must exist for the program to function correctly in
a larger context.
Where fmtStr tells printf() how to format the variable list that follows. var1 through varN may be variables of any base type.
scanf( fmtStr, &var1, &var2, &varN);
This routine is the input compliment to printf().
scanf() requires the address of each variable instead of the variable's value
(as in printf()). This is subtle source of serious bugs.
In the case of call-by-reference, a pointer reference to a variable is passed
into a function instead of the actual value. The function's operations will
effect the variable in a global as well as local sense. Call-by-value (C's
method of parameter passing), by contrast, passes a copy of the variable's value
into the function. Any changes to the variable made by function have only a
local effect and do not alter the state of the variable passed into the
function.
A structure is an aggregate data type. It combines one or more base or
aggregate data types into a package that may treated as a whole. A structure is
like a record in other languages. A union combines two or more data types in the
same area of storage. The contents of a union may be one data type at one time
and another type at a different time. A union is sometimes called a trick-
record.
struct nameAddr { char name[30]; char addr[30]; char city[20]; char state[3]; char zip[5]; };
This keyword provides a short-hand way to write variable declarations. It is
not a true data typing mechanism, rather, it is syntactic "sugar coating."
typedef struct nameAddr *addrPtr;
addrPtr address;
address->city
They both specify a file for inclusion into the current source file. The
difference is where the file stdio.h is expected to be. In the case of the
brackets, the compiler will look in all the default locations. In the case of
the quotes, the compiler will only look in the current directory.
It is used for condition compilation. Specifically the source code between
#ifdef and #endif (or #else) is compiled if the associated symbol is defined to
the compiler.
The C language itself has no provision for constants. However, its companion
program, the preprocessor, can be used to make manifest constants. It does this
through the use of the #define keyword.
Trick question: You can nest structure definitions.
No. (You can in Pascal, a close relative to C.)
It is a reference to a variable or function before it is defined to the
compiler. The cardinal rule of structured languages is that everything must be
defined before it can be used. There are rare occasions where this is not
possible. It is possible (and sometimes necessary) to define two functions in
terms of each other. One will obey the cardinal rule while the other will need a
forward declaration of the former in order to know of the former's existence.
Confused?
int An integer, usually +/- 215 in magnitude.
long A larger version of int, usually +/- 231 in magnitude.
float A single precision real (floating point) number. Magnitude varies.
double A double precision real number. Magnitude varies.
#define SQR(x) (x * x)
(The parenthesis around "x * x" are extremely important because the macro may
be expanded into a place where any embedded spaces could cause the compiler to
misinterpret the expression. The consequences could range from a pesky syntax
error to wrong answers when the program is run.). Moral: The preprocessor does
not know C.
Yes. There is no square-root operator; such computation is performed though
the use of a function.
fprintf( stderr, "%-20.4f", num);
& and | are bitwise AND and OR operators respectively. They are usually used
to manipulate the contents of a variable on the bit level. && and || are logical
AND and OR operators respectively. They are usually used in conditionals.
They both provide access to members of a structure or union. They differ in that -> is used when the variable is a pointer to a structure or union. The dot is used when the variable is itself the structure or union. The -> operator combines the pointer dereferencing operator with the member access operator; it is syntactic "sugar coating."
address->city is equivalent to (*address).city.
% (the percent symbol)
Nothing. They are different ways to express the same logic.
(Thanks to Peter Hedinger for correction).
Do the following until either the end of standard input or the variable c
takes on the value of a tab, space, or backspace character: Store the character
that succeeds the character stored in c into the current location pointed by
buff. Then increment buff to point to the next location in memory. Meanwhile, d
is assigned the same value as c and it is the value of d that is used in the
comparison to EOF.
Yes.
inFile = fopen( fileName, "r+");
Upon success fopen() returns a pointer to a filestream. Otherwise it returns
the value of NULL.
The void data type is used when no other data type is appropriate. A void
pointer is a pointer that may point to any kind of object at all. It is used
when a pointer must be specified but its type is unknown.
unsigned long (*fnc)();
struct nameAddr *(*pfnc)();
No. However, it is possible to return pointers to structures and functions.
The lvalue refers to the left-hand side of an assignment expression. It must
always evaluate to a memory location. The rvalue represents the right-hand side
of an assignment expression; it may have any meaningful combination of variables
and constants.
0x1B
This function allocates heap storage for dynamic data structures.
The malloc() function allocates raw memory given a size in bytes. On the
other hand, calloc() clears the requested memory to zeros before return a
pointer to it. (It can also compute the request size given the size of the base
data structure and the number of them desired.)
C was designed to be a "universal" assembly language. It is used for
producing system software such as operation systems,
compilers/interpreters, device drivers, editors, DBMS's and similar
things. It is not as well suited to application programs.
void *ptr;
assign the pointer to a long number
and the number with 11...1100
add 4 to the number
have an array of length 26. put 'x' in array element corr to 'a' put 'y' in array element corr to 'b' put 'z' in array element corr to 'c' put 'd' in array element corr to 'd' put 'e' in array element corr to 'e' and so on.
the code
while (!eof) { c = getc(); putc(array[c - 'a']); }
An object is a package that contains related data and instructions. The data
relates to what the object represents, while the instructions define how this
object relates to other objects and itself.
A message is a signal from one object to another requesting that a
computation take place. It is roughly equivalent to a function call in other
languages.
A class defines the characteristics of a certain type of object. It defines
what its members will remember, the messages to which they will respond, and
what form the response will take.
An individual object that is a member of some class.
Given a class, a super-class is the basis of the class under consideration.
The given class is defined as a subset (in some respects) of the super-class.
Objects of the given class potentially posses all the characteristics belonging
to objects of the super-class.
Inheritance is property such that a parent (or super) class passes the
characteristics of itself to children (or sub) classes that are derived from it.
The sub-class has the option of modifying these characteristics in order to make
a different but fundamentally related class from the super-class.
An object's message protocol is the exact form of the set of messages to
which the object can respond.
Polymorphism refers to the ability of an object to respond in a logically
identical fashion to messages of the same protocol, containing differing types
of objects. Consider 1 + 5 and 1 + 5.1. In the former, the message "+ 5" is sent
to an object of class integer (1). In the later, the message "+ 5.1" is sent to
the same integer object. The form of the message (its protocol) is identical in
both cases. What differs is the type of object on the right-hand side of these
messages. The former is an integer object (5) while the later is a floating
point object (5.1). The receiver (1) appears (to other objects) to respond in
the same way to both messages. Internally, however, it knows that it must treat
the two types of objects differently in order to obtain the same overall
response.
These represent an object's private memory. They are defined in an object's
class.
These represent a class's memory which it shares with each of its instances.
A method is a class's procedural response to a given message protocol. It is
like the definition of a procedure in other languages.
A constructors and destructors are methods defined in a class that are
invoked automatically when an object is created or destroyed. They are used to
initialize a newly allocated object and to cleanup behind an object about to be
removed.
Comparison: C++ is an extension to the C language. When C++ is used as a procedural language, there are only minor syntactical differences between them.
Contrast: When used as a procedural language, C++ is a better C because:
It is the process of, and ability to redefine the way an object responds to a
C++ operator symbol. This would be done in the object's class definition.
They are objects corresponding to a program's default input and output files.
The procedural paradigm performs computation through a step-by-step manipulation of data items. Solving problems this way is akin to writing a recipe. ie: All the ingredients (data items) are defined. Next a series of enumerated steps (statements) are defined to transform the raw ingredients into a finished meal.
The object oriented model, in contrast, combines related data and procedural
information into a single package called an object. Objects are meant to
represent logically separate entities (like real world objects). Objects are
grouped together (and defined by) classes. (This is analogous to user defined
data types in procedural languages.) Classes may pass-on their "makeup" to
classes derived from them. In this way, Objects that are of a similar yet
different nature need not be defined from scratch. Computation occurs though the
intercommunication of objects. Programming this way is like writing a play.
First the characters are defined with their attributes and personalities. Next
the dialog is written so that the personalities interact. The sum total
constitutes a drama.
By using the extern "C" linkage specification around the C function declarations.
You should know about mangled function names and type-safe linkages. Then you
should explain how the extern "C" linkage specification statement turns that
feature off during compilation so that the linker properly links function calls
to C functions. Another acceptable answer is "I don't know. We never had to do
that." Merely describing what a linker does would indicate to me that you do not
understand the issue that underlies the question.
The scope resolution operator permits a program to reference an identifier in the global scope that has been hidden by another identifier with the same name in the local scope.
The answer can get complicated. It should start with "colon-colon," however.
(Some readers had not heard the term, "scope resolution operator," but they knew
what :: means. You should know the formal names of such things so that you can
understand all communication about them.) If you claim to be well into the
design or use of classes that employ inheritance, you tend to address overriding
virtual function overrides to explicitly call a function higher in the
hierarchy. That's good knowledge to demonstrate, but address your comments
specifically to global scope resolution. Describe C++'s ability to override the
particular C behavior where identifiers in the global scope are always hidden by
similar identifiers in a local scope.
The default member and base class access specifiers are different.
This is one of the commonly misunderstood aspects of C++. Believe it or not,
many programmers think that a C++ struct is just like a C struct, while a C++
class has inheritance, access specifiers, member functions, overloaded
operators, and so on. Some of them have even written books about C++. Actually,
the C++ struct has all the features of the class. The only differences are that
a struct defaults to public member access and public base class inheritance, and
a class defaults to the private access specifier and private base class
inheritance. Getting this question wrong does not necessarily disqualify you
because you will be in plenty of good company. Getting it right is a definite
plus.
Two.
There are two formats for initializers in C++ as shown in Example 1. Example 1(a) uses the traditional C notation, while Example 1(b) uses constructor notation. Many programmers do not know about the notation in Example 1(b), although they should certainly know about the first one. Many old-timer C programmers who made the switch to C++ never use the second idiom, although some wise heads of C++ profess to prefer it.
A reader wrote to tell me of two other ways, as shown in Examples 2(a) and 2(b),
which made me think that maybe the answer could be extended even further to
include the initialization of an int function parameter with a constant argument
from the caller.
The throw operation calls the destructors for automatic objects instantiated since entry to the try block.
Exceptions are in the mainstream of C++ now, so most programmers, if they are familiar with setjmp and longjmp, should know the difference. Both idioms return a program from the nested depths of multiple function calls to a defined position higher in the program. The program stack is "unwound" so that the state of the program with respect to function calls and pushed arguments is restored as if the calls had not been made. C++ exception handling adds to that behavior the orderly calls to the destructors of automatic objects that were instantiated as the program proceeded from within the try block toward where the throw expression is evaluated.
It's okay to discuss the notational differences between the two idioms. Explain the syntax of try blocks, catch exception handlers, and throw expressions. Then specifically address what happens in a throw that does not happen in a longjmp. Your answer should reflect an understanding of the behavior described in the answer just given.
One valid reason for not knowing about exception handling is that your experience is exclusively with older C++ compilers that do not implement exception handling. I would prefer that you have at least heard of exception handling, though.
It is not unusual for C and C++ programmers to be unfamiliar with setjmp/
longjmp. Those constructs are not particularly intuitive. A C programmer who has
written recursive descent parsing algorithms will certainly be familiar with
setjmp/ longjmp. Others might not, and that's acceptable. In that case, you
won't be able to discuss how setjmp/longjmp differs from C++ exception handling,
but let the interview turn into a discussion of C++ exception handling in
general. That conversation will reveal to the interviewer a lot about your
overall understanding of C++.
delete this;
It's not a good practice.
A good programmer will insist that the statement is never to be used if the class is to be used by other programmers and instantiated as static, extern, or automatic objects. That much should be obvious.
The code has two built-in pitfalls. First, if it executes in a member function for an extern, static, or automatic object, the program will probably crash as soon as the delete statement executes. There is no portable way for an object to tell that it was instantiated on the heap, so the class cannot assert that its object is properly instantiated. Second, when an object commits suicide this way, the using program might not know about its demise. As far as the instantiating program is concerned, the object remains in scope and continues to exist even though the object did itself in. Subsequent dereferencing of the pointer can and usually does lead to disaster.
A reader pointed out that a class can ensure that its objects are instantiated on the heap by making its destructor private. This idiom necessitates a kludgy DeleteMe kind of function because the instantiator cannot call the delete operator for objects of the class. The DeleteMe function would then use "delete this."
I got a lot of mail about this issue. Many programmers believe that delete this
is a valid construct. In my experience, classes that use delete this when
objects are instantiated by users usually spawn bugs related to the idiom, most
often when a program dereferences a pointer to an object that has already
deleted itself.
A constructor that has no arguments or one where all the arguments have default argument values.
If you don't code a default constructor, the compiler provides one if there are
no other constructors. If you are going to instantiate an array of objects of
the class, the class must have a default constructor.
A constructor that accepts one argument of a different type.
The compiler uses this idiom as one way to infer conversion rules for a class. A
constructor with more than one argument and with default argument values can be
interpreted by the compiler as a conversion constructor when the compiler is
looking for an object of the type and sees an object of the type of the
constructor's first argument.
A copy constructor constructs a new object by using the content of the argument object. An overloaded assignment operator assigns the contents of an existing object to another existing object of the same class.
First, you must know that a copy constructor is one that has only one argument, which is a reference to the same type as the constructor. The compiler invokes a copy constructor wherever it needs to make a copy of the object, for example to pass an argument by value. If you do not provide a copy constructor, the compiler creates a member-by-member copy constructor for you.
You can write overloaded assignment operators that take arguments of other classes, but that behavior is usually implemented with implicit conversion constructors. If you do not provide an overloaded assignment operator for the class, the compiler creates a default member-by-member assignment operator.
This discussion is a good place to get into why classes need copy constructors
and overloaded assignment operators. By discussing the requirements with respect
to data member pointers that point to dynamically allocated resources, you
demonstrate a good grasp of the problem.
There are three acceptable answers: "Never," "Rarely," and "When the problem domain cannot be accurately modeled any other way."
There are some famous C++ pundits and luminaries who disagree with that third answer, so be careful.
Let's digress to consider this issue lest your interview turn into a religious
debate. Consider an Asset class, Building class, Vehicle class, and CompanyCar
class. All company cars are vehicles. Some company cars are assets because the
organizations own them. Others might be leased. Not all assets are vehicles.
Money accounts are assets. Real-estate holdings are assets. Some real-estate
holdings are buildings. Not all buildings are assets. Ad infinitum. When you
diagram these relationships, it becomes apparent that multiple inheritance is an
intuitive way to model this common problem domain. You should understand,
however, that multiple inheritance, like a chainsaw, is a useful tool that has
its perils, needs respect, and is best avoided except when nothing else will do.
Stress this understanding because your interviewer might share the common bias
against multiple inheritance that many object-oriented designers hold.
The simple answer is that a virtual destructor is one that is declared with the virtual attribute.
The behavior of a virtual destructor is what is important. If you destroy an
object through a pointer or reference to a base class, and the base-class
destructor is not virtual, the derived-class destructors are not executed, and
the destruction might not be complete.
A specialized class "is a" specialization of another class and, therefore, has the ISA relationship with the other class. An Employee ISA Person. This relationship is best implemented with inheritance. Employee is derived from Person. A class may have an instance of another class. For example, an Employee "has a" Salary, therefore the Employee class has the HASA relationship with the Salary class. This relationship is best implemented by embedding an object of the Salary class in the Employee class.
The answer to this question reveals whether you have an understanding of the fundamentals of object-oriented design, which is important to reliable class design.
There are other relationships. The USESA relationship is when one class uses the
services of another. The Employee class uses an object (cout) of the ostream
class to display the employee's name onscreen, for example. But if you get ISA
and HASA right, you usually don't need to go any further.
When you are designing a generic class to contain or otherwise manage objects of other types, when the format and behavior of those other types are unimportant to their containment or management, and particularly when those other types are unknown (thus the genericity) to the designer of the container or manager class.
Prior to templates, you had to use inheritance; your design might include a
generic List container class and an application-specific Employee class. To put
employees in a list, a ListedEmployee class is multiply derived (contrived) from
the Employee and List classes. These solutions were unwieldy and error-prone.
Templates solved that problem.
On GNU compiler both C and C++ give output as 2. I believe other C++
compiler will complain "syntax error", whereas C compiler will give 2.
C is based on structured programming whereas C++ supports the object-oriented
programming paradigm.Due to the advantages inherent in object-oriented programs
such as modularity and reuse, C++ is preferred. However almost anything that can
be built using C++ can also be built using C.
The access privileges in C++ are private, public and protected. The default
access level assigned to members of a class is private. Private members of a
class are accessible only within the class and by friends of the class.
Protected members are accessible by the class itself and it's sub-classes.
Public members of a class can be accessed by anyone.
Data Encapsulation is also known as data hiding. The most important advantage of
encapsulation is that it lets the programmer create an object and then provide
an interface to the object that other objects can use to call the methods
provided by the object. The programmer can change the internal workings of an
object but this transparent to other interfacing programs as long as the
interface remains unchanged.
Inheritance is the process of deriving classes from other classes. In such a
case, the sub-class has an 'is-a' relationship with the super class. For e.g.
vehicle can be a super-class and car can be a sub-class derived from vehicle. In
this case a car is a vehicle. The super class 'is not a' sub-class as the sub-
class is more specialized and may contain additional members as compared to the
super class. The greatest advantage of inheritance is that it promotes generic
design and code reuse.
Multiple Inheritance is the process whereby a sub-class can be derived from more
than one super class. The advantage of multiple inheritance is that it allows a
class to inherit the functionality of more than one base class thus allowing for
modeling of complex relationships. The disadvantage of multiple inheritance is
that it can lead to a lot of confusion when two base classes implement a method
with the same name.
Polymorphism refers to the ability to have more than one method with the same
signature in an inheritance hierarchy. The correct method is invoked at run-time
based on the context (object) on which the method is invoked. Polymorphism
allows for a generic use of method names while providing specialized
implementations for them.
When a class member is declared to be of a static type, it means that the member
is not an instance variable but a class variable. Such a member is accessed
using Classname.Membername (as opposed to Object.Membername). Const is a keyword
used in C++ to specify that an object's value cannot be changed.
Memory is allocated in C using malloc() and freed using free(). In C++ the new()
operator is used to allocate memory to an object and the delete() operator is
used to free the memory taken up by an object.
UML refers to Unified Modeling Language. It is a language used to model OO
problem spaces and solutions.
A shallow copy simply creates a new object and inserts in it references to the
members of the original object. A deep copy constructs a new object and then
creates in it copies of each of the members of the original object.
Note: I've only asked this question once; and yes, he understood that I
was asking him how cfront was put together.
#includeclass A { public: A() { this->Foo(); } virtual void Foo() { cout << "A::Foo()" << endl; } }; class B : public A { public: B() { this->Foo(); } virtual void Foo() { cout << "A::Foo()" << endl; } }; int main(int, char**) { B objectB; } p {return 0; }
#includeclass A { public: A() { cout << "A::A()" << endl; } ~A() { cout << "A::~A()" << endl; throw "A::exception"; } }; class B { public: B() { cout << "B::B()" << endl; throw "B::exception"; } ~B() { cout << "B::~B()"; } }; int main(int, char**) { try { cout << "Entering try...catch block" << endl; } p {A objectA; B objectB; } p {cout << "Exiting try...catch block" << endl; } catch (char* ex) { cout << ex << endl; } } p {return 0; }
One that can be modified by the class even when the object of the class or the member function doing the modification is const.
Understanding this requirement implies an understanding of C++ const, which many
programmers do not have. I have seen large class designs that do not employ the
const qualifier anywhere. Some of those designs are my own early C++ efforts.
One author suggests that some programmers find const to be such a bother that it
is easier to ignore const than to try to use it meaningfully. No wonder many
programmers don't understand the power and implications of const. Someone who
claims to have enough interest in the language and its evolution to keep pace
with the ANSI deliberations should not be ignorant of const, however.
A conversion constructor declared with the explicit keyword. The compiler
does not use an explicit constructor to implement an implied conversion of
types. Its purpose is reserved explicitly for construction.
A library of container templates approved by the ANSI committee for inclusion in the standard C++ specification.
An applicant who then launches into a discussion of the generic programming
model, iterators, allocators, algorithms, and such, has a higher than average
understanding of the new technology that STL brings to C++ programming.
The ability to determine at run time the type of an object by using the
typeid operator or the dynamic_cast operator.
Multiple providers of libraries might use common global identifiers causing a name collision when an application tries to link with two or more such libraries. The name-space feature surrounds a library's external declarations with a unique namespace that eliminates the potential for those collisions.
This solution assumes that two library vendors don't use the same namespace, of
course.
Yes. The ANSI committee added the bool intrinsic type and its true and false value keywords and the wchar_t data type to support character sets wider than eight bits.
Other apparent new types (string, complex, and so forth) are implemented as
classes in the Standard C++ Library rather than as intrinsic types.
describe boot block, super block, inodes and data layout
In UNIX, are the files allocated contiguous blocks of data
a) no, they might be fragmented
how is the fragmented data kept track of
a) describe the direct blocks and indirect blocks in UNIX
file system