C INTERVIEW QUESTIONS
1.What is C language?
A..The C programming language is a standardized programming language developed in the early 1970s by Ken Thompson and Dennis Ritchie for use on the UNIX operating system. It has since spread to many other operating systems, and is one of the most widely used programming languages. C is prized for its efficiency, and is the most popular programming language for writing system software, though it is also used for writing applications.
2.What does static variable mean?
A.there are 3 main uses for the static.
1. If you declare within a function:
It retains the value between function calls
2.If it is declared for a function name:
By default function is extern..so it will be visible from other files if the function declaration is as static..it is invisible for the outer files
3. Static for global variables:
By default we can use the global variables from outside files If it is static global..that variable is limited to with in the file
3.What are the different storage classes in C ?
A.C has three types of storage: automatic, static and allocated.
Variable having block scope and without static specifier have automatic storage duration.
Variables with block scope, and with static specifier have static scope. Global variables (i.e, file scope) with or without the the static specifier also have static scope.
Memory obtained from calls to malloc(), alloc() or realloc() belongs to allocated storage class.
4.What is hashing?
A.To hash means to grind up, and that’s essentially what hashing is all about. The heart of a hashing algorithm is a hash function that takes your nice, neat data and grinds it into some random-looking integer.
The idea behind hashing is that some data either has no inherent ordering (such as images) or is expensive to compare (such as images). If the data has no inherent ordering, you can’t perform comparison searches.
If the data is expensive to compare, the number of comparisons used even by a binary search might be too many. So instead of looking at the data themselves, you’ll condense (hash) the data to an integer (its hash value) and keep all the data with the same hash value in the same place. This task is carried out by using the hash value as an index into an array.
To search for an item, you simply hash it and look at all the data whose hash values match that of the data you’re looking for. This technique greatly lessens the number of items you have to look at. If the parameters are set up with care and enough storage is available for the hash table, the number of comparisons needed to find an item can be made arbitrarily close to one.
One aspect that affects the efficiency of a hashing implementation is the hash function itself. It should ideally distribute data randomly throughout the entire hash table, to reduce the likelihood of collisions. Collisions occur when two different keys have the same hash value.
There are two ways to resolve this problem. In open addressing, the collision is resolved by the choosing of another position in the hash table for the element inserted later. When the hash table is searched, if the entry is not found at its hashed position in the table, the search continues checking until either the element is found or an empty position in the table is found.
The second method of resolving a hash collision is called chaining. In this method, a bucket or linked list holds all the elements whose keys hash to the same value. When the hash table is searched, the list must be searched linearly.
5.Can static variables be declared in a header file?
A.You can’t declare a static variable without defining it as well (this is because the storage class modifiers static and extern are mutually exclusive). A static variable can be defined in a header file, but this would cause each source file that included the header file to have its own private copy of the variable, which is probably not what was intended.
6.Can a variable be both const and volatile?
A.Yes. The const modifier means that this code cannot change the value of the variable, but that does not mean that the value cannot be changed by means outside this code. For instance, in the example in FAQ 8, the timer structure was accessed through a volatile const pointer. The function itself did not change the value of the timer, so it was declared const. However, the value was changed by hardware on the computer, so it was declared volatile. If a variable is both const and volatile, the two modifiers can appear in either order.
7.Can include files be nested?
Answer Yes. Include files can be nested any number of times. As long as you use precautionary measures , you can avoid including the same file twice. In the past, nesting header files was seen as bad programming practice, because it complicates the dependency tracking function of the MAKE program and thus slows down compilation. Many of today’s popular compilers make up for this difficulty by implementing a concept called precompiled headers, in which all headers and associated dependencies are stored in a precompiled state.
Many programmers like to create a custom header file that has #include statements for every header needed for each module. This is perfectly acceptable and can help avoid potential problems relating to #include files, such as accidentally omitting an #include file in a module.
8.What is a null pointer?
A.There are times when it’s necessary to have a pointer that doesn’t point to anything. The macro NULL, defined in , has a value that’s guaranteed to be different from any valid pointer. NULL is a literal zero, possibly cast to void* or char*. Some people, notably C++ programmers, prefer to use 0 rather than NULL.
The null pointer is used in three ways:
1) To stop indirection in a recursive data structure
2) As an error value
3) As a sentinel value
9.printf() Function
What is the output of printf("%d")?
A.1. When we write printf("%d",x); this means compiler will print the value of x. But as here, there is nothing after %d so compiler will show in output window garbage value.
2. When we use %d the compiler internally uses it to access the argument in the stack (argument stack). Ideally compiler determines the offset of the data variable depending on the format specification string. Now when we write printf("%d",a) then compiler first accesses the top most element in the argument stack of the printf which is %d and depending on the format string it calculated to offset to the actual data variable in the memory which is to be printed. Now when only %d will be present in the printf then compiler will calculate the correct offset (which will be the offset to access the integer variable) but as the actual data object is to be printed is not present at that memory location so it will print what ever will be the contents of that memory location.
3. Some compilers check the format string and will generate an error without the proper number and type of arguments for things like printf(...) and scanf(...).
malloc()
10.What is the difference between "calloc(...)" and "malloc(...)"?
A.1. calloc(...) allocates a block of memory for an array of elements of a certain size. By default the block is initialized to 0. The total number of memory allocated will be (number_of_elements * size).
malloc(...) takes in only a single argument which is the memory required in bytes. malloc(...) allocated bytes of memory and not blocks of memory like calloc(...).
2. malloc(...) allocates memory blocks and returns a void pointer to the allocated space, or NULL if there is insufficient memory available.
calloc(...) allocates an array in memory with elements initialized to 0 and returns a pointer to the allocated space. calloc(...) calls malloc(...) in order to use the C++ _set_new_mode function to set the new handler mode.
11.printf() Function- What is the difference between "printf(...)" and "sprintf(...)"?
A.sprintf(...) writes data to the character array whereas printf(...) writes data to the standard output device.
12.Compilation How to reduce a final size of executable?
A.Size of the final executable can be reduced using dynamic linking for libraries.
13.Linked Lists -- Can you tell me how to check whether a linked list is circular?
A.Create two pointers, and set both to the start of the list. Update each as follows:
while (pointer1) {
pointer1 = pointer1->next;
pointer2 = pointer2->next;
if (pointer2) pointer2=pointer2->next;
if (pointer1 == pointer2) {
print ("circular");
}
}
If a list is circular, at some point pointer2 will wrap around and be either at the item just before pointer1, or the item before that. Either way, its either 1 or 2 jumps until they meet.
14."union" Data Type What is the output of the following program? Why?
#include
main() {
typedef union {
int a;
char b[10];
float c;
}
Union;
Union x,y = {100};
x.a = 50;
strcpy(x.b,"hello");
x.c = 21.50;
printf("Union x : %d %s %f n",x.a,x.b,x.c);
printf("Union y : %d %s %f n",y.a,y.b,y.c);
}
String Processing --- Write out a function that prints out all the permutations of a string. For example, abc would give you abc, acb, bac, bca, cab, cba.
void PrintPermu (char *sBegin, char* sRest) {
int iLoop;
char cTmp;
char cFLetter[1];
char *sNewBegin;
char *sCur;
int iLen;
static int iCount;
iLen = strlen(sRest);
if (iLen == 2) {
iCount++;
printf("%d: %s%s\n",iCount,sBegin,sRest);
iCount++;
printf("%d: %s%c%c\n",iCount,sBegin,sRest[1],sRest[0]);
return;
} else if (iLen == 1) {
iCount++;
printf("%d: %s%s\n", iCount, sBegin, sRest);
return;
} else {
// swap the first character of sRest with each of
// the remaining chars recursively call debug print
sCur = (char*)malloc(iLen);
sNewBegin = (char*)malloc(iLen);
for (iLoop = 0; iLoop < ctmp =" sCur[iLoop];" x="10;" x="10," y="15;" x =" x++;" y =" ++y;" a="0;" a="="0)" i="0;">>=1){
if (x & 0X1)
i++;
}
return i;
}
Answer: returns the number of ones in the input parameter X
What will happen in these three cases?
if(a=0){
//somecode
}
if (a==0){
//do something
}
if (a===0){
//do something
}
15.What are x, y, y, u
#define Atype int*
typedef int *p;
p x, z;
Atype y, u;
Answer: x and z are pointers to int. y is a pointer to int but u is just an integer variable
16.Advantages of a macro over a function?
A.Macro gets to see the Compilation environment, so it can expand __ __TIME__ __FILE__ #defines. It is expanded by the preprocessor.
For example, you can’t do this without macros
#define PRINT(EXPR) printf( #EXPR “=%d\n”, EXPR)
PRINT( 5+6*7 ) // expands into printf(”5+6*7=%d”, 5+6*7 );
You can define your mini language with macros:
#define strequal(A,B) (!strcmp(A,B))
Macros are a necessary evils of life. The purists don’t like them, but without it no real work gets done.
17.What is the difference between strings and character arrays?
A.A major difference is: string will have static storage duration, whereas as a character array will not, unless it is explicity specified by using the static keyword.
Actually, a string is a character array with following properties:
* the multibyte character sequence, to which we generally call string, is used to initialize an array of static storage duration. The size of this array is just sufficient to contain these characters plus the terminating NUL character.
* it not specified what happens if this array, i.e., string, is modified.
* Two strings of same value[1] may share same memory area. For example, in the following declarations:
char *s1 = “Calvin and Hobbes”;
char *s2 = “Calvin and Hobbes”;
the strings pointed by s1 and s2 may reside in the same memory location. But, it is not true for the following:
char ca1[] = “Calvin and Hobbes”;
char ca2[] = “Calvin and Hobbes”;
[1] The value of a string is the sequence of the values of the contained characters, in order.
18.Write down the equivalent pointer expression for referring the same element a[i][j][k][l]?
A.a[i] == *(a+i)
a[i][j] == *(*(a+i)+j)
a[i][j][k] == *(*(*(a+i)+j)+k)
a[i][j][k][l] == *(*(*(*(a+i)+j)+k)+l)
19.Which bit wise operator is suitable for checking whether a particular bit is on or off?
A.The bitwise AND operator. Here is an example:enum {
KBit0 = 1,
KBit1,
…
KBit31,
};
if ( some_int & KBit24 )
printf ( “Bit number 24 is ON\n” );
else
printf ( “Bit number 24 is OFF\n” );
20.Which bit wise operator is suitable for turning off a particular bit in a number?
A.The bitwise AND operator, again. In the following code snippet, the bit number 24 is reset to zero.
some_int = some_int & ~KBit24;
21.Which bit wise operator is suitable for putting on a particular bit in a number?
A.The bitwise OR operator. In the following code snippet, the bit number 24 is turned ON:
some_int = some_int | KBit24;
22.Does there exist any other function which can be used to convert an integer or a float to a string?
A.Some implementations provide a nonstandard function called itoa(), which converts an integer to string.
#include
char *itoa(int value, char *string, int radix);
DESCRIPTION
The itoa() function constructs a string representation of an integer.
PARAMETERS
value:
Is the integer to be converted to string representation.
string:
Points to the buffer that is to hold resulting string.
The resulting string may be as long as seventeen bytes.
radix:
Is the base of the number; must be in the range 2 - 36.
A portable solution exists. One can use sprintf():
char s[SOME_CONST];
int i = 10;
float f = 10.20;
sprintf ( s, “%d %f\n”, i, f );
23.Why does malloc(0) return valid memory address ? What's the use ?
A.malloc(0) does not return a non-NULL under every implementation.
An implementation is free to behave in a manner it finds
suitable, if the allocation size requested is zero. The
implmentation may choose any of the following actions:
* A null pointer is returned.
* The behavior is same as if a space of non-zero size
was requested. In this case, the usage of return
value yields to undefined-behavior.
Notice, however, that if the implementation returns a non-NULL
value for a request of a zero-length space, a pointer to object
of ZERO length is returned! Think, how an object of zero size
should be represented?
For implementations that return non-NULL values, a typical usage
is as follows:
void
func ( void )
{
int *p; /* p is a one-dimensional array,
whose size will vary during the
the lifetime of the program */
size_t c;
p = malloc(0); /* initial allocation */
if (!p)
{
perror (”FAILURE” );
return;
}
/* … */
while (1)
{
c = (size_t) … ; /* Calculate allocation size */
p = realloc ( p, c * sizeof *p );
/* use p, or break from the loop */
/* … */
}
return;
}
Notice that this program is not portable, since an implementation
is free to return NULL for a malloc(0) request, as the C Standard
does not support zero-sized objects.
23.Difference between const char* p and char
const* p
A.in const char* p, the character pointed by ‘p’
is constant, so u cant change the value of
character pointed by p but u can make ‘p’ refer
to some other location.
in char const* p, the ptr ‘p’ is constant not the
character referenced by it, so u cant make ‘p’
to reference to any other location but u can
change the value of the char pointed by ‘p’.
How can method defined in multiple base
classes with same name can be invoked from
derived class simultaneously
ex:
class x
{
public:
m1();
};
class y
{
public:
m1();
};
class z :public x, public y
{
public:
m1()
{
x::m1();
y::m1();
}
};
25.Write a program to interchange 2 variables
without using the third one.
A.a=7;
b=2;
a = a + b;
b = a - b;
a = a - b;
25.What is the result of using Option Explicit?
A.When writing your C program, you can
include files in two ways.
The first way is to surround the file you want
to include with the angled brackets <>.
This method of inclusion tells the preprocessor
to look for the file in the predefined default
location.
This predefined default location is often an
INCLUDE environment variable that denotes
the path to your include files.
For instance, given the INCLUDE variable
INCLUDE=C:\COMPILER\INCLUDE;S:\SO
URCE\HEADERS;
using the #include version of file inclusion, the
compiler first checks the
C:\COMPILER\INCLUDE
directory for the specified file. If the file is not
found there, the compiler then checks the
S:\SOURCE\HEADERS directory. If the file is
still not found, the preprocessor checks the
current directory.
The second way to include files is to surround
the file you want to include with double
quotation marks. This method of inclusion tells
the preprocessor to look for the file in the
current directory first, then look for it in the
predefined locations you have set up. Using the
#include file version of file inclusion and
applying it to the preceding example, the
preprocessor first checks the current directory
for the specified file. If the file is not found in
the current directory, the
C:COMPILERINCLUDE directory is
searched. If the file is still not found, the
preprocessor checks the S:SOURCEHEADERS
directory.
The #include method of file inclusion is often
used to include standard headers such as
stdio.h or
stdlib.h.
This is because these headers are rarely (if
ever) modified, and they should always be read
from your compiler’s standard include file
directory.
The #include file method of file inclusion is
often used to include nonstandard header files
that you have created for use in your program.
This is because these headers are often
modified in the current directory, and you will
want the preprocessor to use your newly
modified version of the header rather than the
older, unmodified version.
What is the benefit of using an enum rather
than a #define constant?
The use of an enumeration constant (enum) has
many advantages over using the traditional
symbolic constant style of #define. These
advantages include a lower maintenance
requirement, improved program readability,
and better debugging capability.
1) The first advantage is that enumerated
constants are generated automatically by the
compiler. Conversely, symbolic constants must
be manually assigned values by the
programmer.
For instance, if you had an enumerated
constant type for error codes that could occur
in your program, your enum definition could
look something like this:
enum Error_Code
{
OUT_OF_MEMORY,
INSUFFICIENT_DISK_SPACE,
LOGIC_ERROR,
FILE_NOT_FOUND
};
In the preceding example,
OUT_OF_MEMORY is automatically assigned
the value of 0 (zero) by the compiler because it
appears first in the definition. The compiler
then continues to automatically assign numbers
to the enumerated constants, making
INSUFFICIENT_DISK_SPACE equal to 1,
LOGIC_ERROR equal to 2, and
FILE_NOT_FOUND equal to 3, so on.
If you were to approach the same example by
using symbolic constants, your code would look
something like this:
#define OUT_OF_MEMORY 0
#define INSUFFICIENT_DISK_SPACE 1
#define LOGIC_ERROR 2
#define FILE_NOT_FOUND 3
values by the programmer. Each of the two
methods arrives at the same result: four
constants assigned numeric values to represent
error codes. Consider the maintenance
required, however, if you were to add two
constants to represent the error codes
DRIVE_NOT_READY and CORRUPT_FILE.
Using the enumeration constant method, you
simply would put these two constants anywhere
in the enum definition. The compiler would
generate two unique values for these constants.
Using the symbolic constant method, you would
have to manually assign two new numbers to
these constants. Additionally, you would want
to ensure that the numbers you assign to these
constants are unique.
2) Another advantage of using the enumeration
constant method is that your programs are
more readable and thus can be understood
better by others who might have to update your
program later.
3) A third advantage to using enumeration
constants is that some symbolic debuggers can
print the value of an enumeration constant.
Conversely, most symbolic debuggers cannot
print the value of a symbolic constant. This can
be an enormous help in debugging your
program, because if your program is stopped at
a line that uses an enum, you can simply
inspect that constant and instantly know its
value. On the other hand, because most
debuggers cannot print #define values, you
would most likely have to search for that value
by manually looking it up in a header file.
26.How can I open a file so that other
programs can update it at the same time?
Your C compiler library contains a low-level
file function called sopen() that can be used to
open a file in shared mode. Beginning with
DOS 3.0, files could be opened in shared mode
by loading a special program named
SHARE.EXE. Shared mode, as the name
implies, allows a file to be shared with other
programs as well as your own.
Using this function, you can allow other
programs that are running to update the same
file you are updating.
The sopen() function takes four parameters: a
pointer to the filename you want to open, the
operational mode you want to open the file in,
the file sharing mode to use, and, if you are
creating a file, the mode to create the file in.
The second parameter of the sopen() function,
usually referred to as the operation flag
parameter, can have the following values
assigned to it:
Constant Description O_APPEND Appends all
writes to the end of the file
O_BINARY Opens the file in binary
(untranslated) mode
O_CREAT If the file does not exist, it is
created
O_EXCL If the O_CREAT flag is used and the
file exists, returns an error
O_RDONLY Opens the file in read-only mode
O_RDWR Opens the file for reading and
writing
O_TEXT Opens the file in text (translated)
mode
O_TRUNC Opens an existing file and writes
over its contents
O_WRONLY Opens the file in write-only
mode
The third parameter of the sopen() function,
usually referred to as the sharing flag, can have
the following values assigned to it:
Constant Description
SH_COMPAT No other program can access
the file
SH_DENYRW No other program can read
from or write to the file
SH_DENYWR No other program can write to
the file
SH_DENYRD No other program can read
from the file
SH_DENYNO Any program can read from or
write to the file
If the sopen() function is successful, it returns a
non-negative number that is the file’s handle. If
an error occurs, 1 is returned, and the global
variable errno is set to one of the following
values:
Constant Description
ENOENT File or path not found
EMFILE No more file handles are available
EACCES Permission denied to access file
EINVACC Invalid access code
Constant Description
27.What is the quickest sorting method to use?
A.The answer depends on what you mean by
quickest. For most sorting problems, it just
doesn’t matter how quick the sort is because it
is done infrequently or other operations take
significantly more time anyway. Even in cases
in which sorting speed is of the essence, there is
no one answer. It depends on not only the size
and nature of the data, but also the likely
order. No algorithm is best in all cases.
There are three sorting methods in this
author’s toolbox that are all very fast and that
are useful in different situations. Those
methods are quick sort, merge sort, and radix
sort.
The Quick Sort
The quick sort algorithm is of the divide and
conquer type. That means it works by reducing
a sorting problem into several easier sorting
problems and solving each of them. A dividing
value is chosen from the input data, and the
data is partitioned into three sets: elements
that belong before the dividing value, the value
itself, and elements that come after the dividing
value. The partitioning is performed by
exchanging elements that are in the first set but
belong in the third with elements that are in the
third set but belong in the first Elements that
are equal to the dividing element can be put in
any of the three setsthe algorithm will still
work properly.
The Merge Sort
The merge sort is a divide and conquer sort as
well. It works by considering the data to be
sorted as a sequence of already-sorted lists (in
the worst case, each list is one element long).
Adjacent sorted lists are merged into larger
sorted lists until there is a single sorted list
containing all the elements. The merge sort is
good at sorting lists and other data structures
that are not in arrays, and it can be used to
sort things that don’t fit into memory. It also
can be implemented as a stable sort.
The Radix Sort
The radix sort takes a list of integers and puts
each element on a smaller list, depending on
the value of its least significant byte. Then the
small lists are concatenated, and the process is
repeated for each more significant byte until
the list is sorted. The radix sort is simpler to
implement on fixed-length data such as ints.
when should the volatile modifier be used?
The volatile modifier is a directive to the
compiler’s optimizer that operations involving
this variable should not be optimized in certain
ways. There are two special cases in which use
of the volatile modifier is desirable. The first
case involves memory-mapped hardware (a
device such as a graphics adaptor that appears
to the computer’s hardware as if it were part of
the computer’s memory), and the second
involves shared memory (memory used by two
or more programs running simultaneously).
Most computers have a set of registers that can
be accessed faster than the computer’s main
memory. A good compiler will perform a kind
of optimization called redundant load and
store removal. The compiler looks for places in
the code where it can either remove an
instruction to load data from memory because
the value is already in a register, or remove an
instruction to store data to memory because the
value can stay in a register until it is changed
again anyway.
If a variable is a pointer to something other
than normal memory, such as memory-mapped
ports on a peripheral, redundant load and
store optimizations might be detrimental. For
instance, here’s a piece of code that might be
used to time some operation:
time_t time_addition(volatile const struct timer
*t, int a)
{
int n;
int x;
time_t then;
x = 0;
then = t->value;
for (n = 0; n <>
{
x = x + a;
}
return t->value - then;
}
In this code, the variable t-> value is actually a
hardware counter that is being incremented as
time passes. The function adds the value of a to
x 1000 times, and it returns the amount the
timer was incremented by while the 1000
additions were being performed. Without the
volatile modifier, a clever optimizer might
assume that the value of t does not change
during the execution of the function, because
there is no statement that explicitly changes it.
In that case, there’s no need to read it from
memory a second time and subtract it, because
the answer will always be 0. The compiler
might therefore optimize the function by
making it always return 0.
If a variable points to data in shared memory,
you also don’t want the compiler to perform
redundant load and store optimizations.
Shared memory is normally used to enable two
programs to communicate with each other by
having one program store data in the shared
portion of memory and the other program read
the same portion of memory. If the compiler
optimizes away a load or store of shared
memory, communication between the two
programs will be affected.
28.When should the register modifier be used?
Does it really help?
A.The register modifier hints to the compiler
that the variable will be heavily used and
should be kept in the CPU’s registers, if
possible, so that it can be accessed faster.
There are several restrictions on the use of the
register modifier.
First, the variable must be of a type that can be
held in the CPU’s register. This usually means
a single value of a size less than or equal to the
size of an integer. Some machines have
registers that can hold floating-point numbers
as well.
Second, because the variable might not be
stored in memory, its address cannot be taken
with the unary & operator. An attempt to do so
is flagged as an error by the compiler. Some
additional rules affect how useful the register
modifier is. Because the number of registers is
limited, and because some registers can hold
only certain types of data (such as pointers or
floating-point numbers), the number and types
of register modifiers that will actually have any
effect are dependent on what machine the
program will run on. Any additional register
modifiers are silently ignored by the compiler.
Also, in some cases, it might actually be slower
to keep a variable in a register because that
register then becomes unavailable for other
purposes or because the variable isn’t used
enough to justify the overhead of loading and
storing it.
So when should the register modifier be used?
The answer is never, with most modern
compilers. Early C compilers did not keep any
variables in registers unless directed to do so,
and the register modifier was a valuable
addition to the language. C compiler design has
advanced to the point, however, where the
compiler will usually make better decisions
than the programmer about which variables
should be stored in registers.
In fact, many compilers actually ignore the
register modifier, which is perfectly legal,
because it is only a hint and not a directive.
29.How can you determine the size of an
allocated portion of memory?
A.You can’t, really. free() can , but there’s no
way for your program to know the trick free()
uses. Even if you disassemble the library and
discover the trick, there’s no guarantee the
trick won’t change with the next release of the
compiler.
Posted at 7:58 AM | Labels: TECHNICAL STUFF |

0 comments:
Post a Comment