Q-1: What is a Programming Paradigm?
Answer: Programming paradigm means the principle that is used for organization programs. There are two major Programming Paradigms: Structured Programming and Object Oriented Programming (OOP). C language uses the Structured Paradigm, whereas, C++, C#, VB.NET or Java use OOP. OOP has lots of advantages to offer. But even while using this organizing principle you would still need a good hold over the language elements of C and the basic programming skills.
Q-2: Is it true that Operating Systems like Windows, Linux and Unix are written in C?
Answer: Major parts of popular operating systems like Windows, Unix, and Linux are still written in C. This is because even today when it comes to performance nothing beats C. Also, the functions exposed by the Operating System API can be easily called through any language. Moreover, if one is to extend the operating system to work with new devices one needs to write Device Driver programs. These programs are exclusively written in C.
Q-3: What do you mean by the scope of a variable? What are the different types of scopes that a variable can have?
Answer: Scope indicates the region over which the variables declaration has an effect. The four kinds of scopes are – file, function, block and prototype.
Q-4: Which of the following statement is a declaration and which is a definition?
extern int i;
int j;
Answer: First is a declaration, and second is a definition.
Q-5: What are the differences between a declaration and a function?
Answer: There are two differences between a declaration and a definition:
In the definition of a variable space is reserved for the variable and some initial value is given to it, whereas a declaration only identifies the type of the variable. This definition is the place where the variable is created or assigned storage, whereas declaration refers to places where the nature of the variable is stated but no storage is allocated.
Secondly, redefinition is an error, whereas, redeclaration is not an error.
Q-6: Is it true a global variable may have several declarations, but only one definition? [Yes/No]
Answer: Yes.
Q-7: Is it true a function may have several declarations, but only one definition? [Yes/No]
Answer: Yes.
Q-8: When we mention the prototype of a function are we defining the function or declaring it?
Answer: We are declaring it. When the function, along with the statements belonging to it is mentioned, we are defining the function.
Q-9: Some books suggest that the following definitions should be preceded by the word static. Is it correct?
int a[] = {2, 3, 4, 12, 32};
struct emp e = {"sandy", 23};
Answer: Pre-ANSI C compilers had such a requirement. Compilers which conform to ANSI C standards do not have such a requirement.
Q-10: If you are to share the variables or functions across several sources files how would you ensure that all definitions and declarations are consistent?
Answer: The best arrangement is to place each definition in a relevant ‘.c’ file. Then, put an external declaration in a header file (‘.h’ file) and use #include to bring in the declaration wherever needed. The ‘.c’ file which contains the definition should also include the header file so that the compiler can check that the definition matches the declaration.
Q-11: Global variables are available to all functions. Does there exist a mechanism by way of which I can make it available to some and not to others?
Answer: No. The only way this can be achieved is to define the variable locally in main() instead of defining it globally and then passing it to the functions which need it.
Q-12: What are the different types of linkages?
Answer: There are three different types of linkages – external, internal and none. External linkage means global, non-static variables and functions, internal linkage means static variables and functions with file scope, and no linkage means local variables.
Q-13: What is size_t?
Answer: It is the type of the result of the sizeof operator. size_t is used to express the size of something or the number of characters in something. For example, it is the type that you pass to malloc( ) to indicate how many bytes you wish to allocate. Or it is the type returned by strlen( ) to indicate the number of characters in a string.
Each implementation chooses a type like unsigned int or unsigned long (or something else) to be its size_t, depending on what makes the most sense. Each implementation publishes its own choice of size_t in several header files like ‘stdio.h’, etc. In most implementations, size_t is defined as:
typedef unsigned int size_t
This means that in this particular implementation, size_t is an unsigned int. Other implementations may make other choices.
Q-14: What is more efficient a switch statement or an if-else chain?
Answer: As far as efficiency is concerned there would hardly be any difference, if at all. If the cases in a switch are sparsely distributed the compiler may internally use the equivalent of an if-else chain instead of a compact jump table. However, one should use a switch where one can. It is definitely a cleaner way to program and certainly is not any less efficient than the if-else chain.
Q-15: Can we use a switch statement to switch on strings?
Answer: No. The cases in a switch must either have integer constants or constant expressions.
Q-16: In which order do the Relational, Arithmetic, Logical and Assignment operators get evaluated in C?
Answer: Arithmetic, Relational, Logical, Assignment.
Q-17: How come the C standard says that the expression j = i++ * i++
is undefined, whereas, the expression j = i++ && i++
is perfectly legal?
Answer: According to the C standard an object’s stored value can be modified only once (by evaluation of expression) at two sequence points. A sequence point occurs:
- at the end of all expressions (an expression which is not a subexpression in a larger expression)
- at the &&, || and ?: operators
- at a functions call (after the evaluation of all arguments, just before the actual call)
Since the first expression, i is getting modified twice between two sequence points the expression is undefined. Also, the second expression is legal because a sequence point is occurring at && and i is getting modified once before and once after this sequence point.
Q-18: If a[j] = i++
is undefined, then for the same reason, i = i + 1
should also be undefined. But it is not so. Why?
Answer: The standard says that if an object is to get modified within an expression then all accesses to it within the same expression must be for computing the value to be stored in the object. The expression a[i] = i++
is disallowed because one of the accesses of i
(the one in a[i]
) has nothing to do with the value that ends up being stored in i
. In this case, the compiler may not know whether the access should take place before or after the incremented value is stored. Since there’s no good way to define it, the standard declares it as undefined. As against this, the expression i = i + 1
is allowed because i
is accessed to determine i
‘s the final value.
Q-19: Will the expression *p++ = c
be disallowed by the compiler?
Answer: No. Because here even though the value of p is accessed twice it is used to modify two different objects p and *P.
Q-20: Why should I use functions at all?
Answer: There are two reasons for using functions:
(a) Writing functions avoids rewriting the same code over and over Suppose you have a section of code in your program that calculates the area of a triangle. If later in the program you want to estimate the size of a different triangle, you won’t like it you are required to write the exact instructions all over again. Instead, you would prefer to jump to a ‘section of code’ that calculates area and then jump back to the place from where you left off. This section of code is nothing but a function.
(b) By using functions it becomes easier to write programs and keep track of what they are doing. If the operation of a program can be divided into separate activities, and each activity is placed in a different function, then each could be written and checked more or less independently. Separating the code into modular functions also makes the program easier to design and understand.
Q-21: In what form are the library functions provided?
Answer: Library functions are never provided in source code form. They are always made available in object code form obtained after compilation.
Q-22: What is the type of variable b in the following declaration?
#define FLOATPTR float*
FLOATPTR a, b;
Answer: float and not a pointer to a float, since on expansion the declaration becomes:
float *a, b;
Q-23: Is it necessary that the header files should have a .h
extension?
Answer: No. However, traditionally they have been given a .h
extension to identify them as something different than the .c
program files.
Q-24: What do the header files usually contain?
Answer: Header files contain preprocessor directives like #define, structure, union and enum declaration, typedef declaration, global variable declarations and external function declarations. You should not write the actual code (i.e function bodies) or global variable definition (that is defining or initialising instances) in header files. The #include directive should be used to pull in header files, not other ‘.c’ files.
Q-25: Will it result in an error if a header file is included twice? [Yes/ No]
Answer: Yes, unless the header file has taken care to ensure that if already included it doesn’t get included again.
Q-26: How can a header file ensure that it doesn’t get included more than once?
Answer: All declarations must be written in the manner shown below. Assume that the name of the header file is ‘FUNCS.H’.
// funch.h
#ifndef_FUNCS
#define_FUNCH
// all declaration would go here
#endif
Now if we include this file twice as shown below, it will get included only once.
#include "funcs.h"
#include "funcs.h"
int main()
{
// some code
return 0;
}
Q-27: On doing #include
where are the header files searched?
Answer: If #included
using < > the files get searched in the predefined include path. It is possible to change the predefined include path. If #included
with the ” ” syntax in addition to the predefined include path the files also get searched in the current directory (usually the directory from which you invoked the compiler).
Q-28: Can you combine the following two statements into one?
char *p;
p = (char*) malloc (100);
Answer:
char *p = (char*) malloc (100);
Note that the typecasting operation can be dropped completely if this program is built using gcc compiler.
Q-29: Are the expressions *ptr++
and ++*ptr
the same?
Answer: No. *ptr++
increments the pointer and not the value pointed by it, whereas ++*ptr
increments the value being pointed to by ptr.
Q-30: Can you write another expression which does the same job as ++*ptr
?
Answer:
(*ptr)++
Q-31: What would be the equivalent pointer expression for referring to the array element a [i] [j] [k] [l]
?
Answer:
*(*(*(*(a + i) + j) + k) + l)
Q-32: Where can one think of using pointers?
Answer: At a lot of places, some of which are:
- Accessing array or string elements
- In passing big objects like arrays, strings and structures to functions
- Dynamic memory allocation
- Call by reference
- Implementing linked lists, trees, graphs and many other data structures
Q-33: How will you declare an array of three function pointers where each function receives two ints and returns a float?
Answer:
float (*arr[3]) (int, int);
Q-34: Is the NULL pointer the same as an uninitialised pointer? [Yes/No]
Answer: No.
Q-35: In which header file is the NULL macro defined?
Answer: In files “stdio.h” and “stddef.h”
Q-36: Is there any difference between the following two statements?
char *p = 0
char *t = NULL
Answer: No. NULL is #defined
as 0 in the ‘stdio.h’ file. Thus, both p and t are null pointers.
Q-37: What is a null pointer?
Answer: For each pointer type (like say a char pointer) C defines a special pointer value, which is guaranteed not to point to any object or function of that type. Usually, the null pointer constant used for representing a null pointer is the integer 0.
Q-38: What’s the difference between a null pointer, a NULL macro, the ASCII NUL character and a null string?
Answer:
A null pointer is a pointer, which doesn’t point anywhere.
A NULL macro is used to represent the null pointer in the source code. It has a value of 0 associated with it.
The ASCII NUL character has all its bits as 0 but doesn’t have any relationship with the null pointer.
The null string is just another name for an empty string ” “.
Q-39: Is there any difference between the following two statements?
char *ch = "Ctg";
char ch[] = "Ctg";
Answer: Yes. In the first statement, the character pointer ch stores the address of the string “Ctg”. The pointer ch can be made to point to some other character string (or even nowhere). The second statement, on the other hand, specifies that space for 7 characters is allocated and that the name of the location is ch. Thus, it specifies the size as well as initial values of the characters in array ch.
Q-40: When are char a[ ] and char *a treated as same by the compiler?
Answer: When using them as formal parameters while defining a function.
Q-41: What is the difference in the following declaration?
char *p = "Samuel"
char a[ ] = "Samuel"
Answer:
Here a is an array big enough to hold the message and the ‘\0’ following the message. Individual characters within the array can be changed but the address of the array will remain the same.
On the other hand, p is a pointer, initialized to point to a string constant. The pointer p may be modified to point to another string, but if you attempt to modify the string at which p is pointing the result is undefined.
Q-42: While handling a string do we always have to process it character by character or there exists a method to process the entire string as one unit?
Answer: A string can be processed only on a character-by-character basis.
Q-43: What is the similarity between a structure, union and an enumeration?
Answer: All of them let you define new data types.
Q-44: Can a structure contain a pointer to itself?
Answer: Certainly. Such structures are known as self-referential structures.
Q-45: How are structure passing and returning implemented by the compiler?
Answer: When structures are passed as arguments to functions, the entire structure is pushed on the stack. For big structures, this is an extra overhead. This overhead can be avoided by passing pointers to structures instead of actual structures. To return structures a hidden argument generated by the compiler is passed to the function. This argument points to a location where the returned structure is copied.
Q-46: What is the difference between a structure and a union?
Answer: A union is essentially a structure in which all of the fields overlay each other. At a time only one field can be used. We can write to one field and read from another.
Q-47: What is the difference between an enumeration and a set of preprocessor #defines
?
Answer: There is hardly any difference between the two, except that a #define has a global effect (throughout the file), whereas, an enumeration can have an effect local to the block if desired. Some advantages of enumeration are that the numeric values are automatically assigned, whereas, in #define we have to explicitly define them. A disadvantage of enumeration is that we have no control over the sizes of enumeration variables.
Q-48: Is there an easy way to print enumeration values symbolically?
Answer: No. You can write a small function (one per enumeration) to map an enumeration constant to a string, either by using a switch statement or by searching an array.
Q-49: What is the use of bit fields in a structure declaration?
Answer: Bit fields are used to save space in structures having several binary flags or other small fields. Note that the colon notation for specifying the size of a field in bits is valid only in structures (and in unions); you cannot use this mechanism to specify the size of arbitrary variables.
Q-50: Can we have an array of bits fields? [Yes/No]
Answer: No.
Q-51: Can we specify a variable field width in a scanf()
format string?
Answer: No. In scanf()
a * in format string after a % sing is used for suppression of assignment. That is, the current input field is scanned but not stored.
Q-52: Out of fgets()
and gets()
which function is safe to use?
Answer: fgets()
, because unlike fgets()
, gets()
can not be told the size of the buffer into which the string supplied will be stored. As a result, there is always a possibility of the overflow of the buffer.
Q-53: To which numbering system can the binary number 1011011111000101 be easily converted?
Answer: Hexadecimal, since each 4-digit binary represents one hexadecimal digit.
Q-54: Which bitwise operator is suitable for checking whether a particular bit is on or off?
Answer: The & operator
Q-55: Which bitwise operator is suitable for turning off a particular bit in a number?
Answer: The & operator.
Q-56: Which bitwise operator is suitable for putting on a particular bit in a number?
Answer: The | operator.
Q-57: What is the type of comparison in the following code segment?
typedef int (*ptrofun)(char*, char*);
ptrtofun compare;
Answer: It is a pointer to a function that receives two character pointers and returns an integer.
Q-58: What are the advantages of using typedef in a program?
Answer: There are three main reasons for using typedefs:
- It makes the writing of complicated declarations a lot easier. This helps in eliminating a lot of clutter in the program.
- It helps in achieving portability in programs. If we use typedefs for machine-dependent data types, only the typedefs need to change when the program is moved to a new machine platform.
- It helps in providing better documentation for a program. For example, a node of a double-linked list is better understood as
ptrtolist
rather than just a pointer to a complicated structure.
Q-59: What does the following prototype indicate?
void strcpy (char *target, const char *source)
Answer: We can modify the pointers source as well as the target. However, the object to which the source is the pointer cannot be modified.
Q-60: What does the following prototype indicate?
const char *change (char*, int)
Answer: The function change( ) receives a char pointer and an int and returns a pointer to a constant char.