1. How to declare a pointer to a function?Ans: int myFunc(); // The function
int (*fp)(); // pointer to the function.
fp = myFunc; // Assigning address of the function to the pointer.
(*fp)(); // Calling the function.
fp(); // Another way to call the function.
A function pointer is a pointer variable which holds the address of a function and used to invoke that function indirectly. The main use for function pointers is setting up "listener" or "callback" functions that are invoked when a particular event happens. The function is called and this notifies your code that something of interest has taken place. Sometimes user will click on a button or enter a test in the field. These operations are events that may require a response that your program needs to handle. How can your code known what happening? Using Call Back function. The user's click should cause the interface to call a function that you wrote to handle the event.
Ex: void click_button(int x, int y, const char *test, function callback_func);
Whenever the button clicked, callback_func will be invoked. Exactly what callback_func does depends on the button; this is why allowing the click_button function to take a function pointer is useful.
Syntax: void * (*foo) (int *); // Here *foo should refers to the function that returns void pointer and takes integer pointer as argument.
2. What is the use of function prototype?
Ans: The 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, order) and the nature of the value returned by the function.
3. What are the inline functions?
Ans: The inline comment is a request to the compiler to copy the code into the object at every place the function is called. That is, the function is expanding at each point of call. Most of the advantage of inline functions comes from avoiding the overhead of calling an actual function. Such overhead includes saving registers, setting up stack frames and so on. But with large functions the overhead becomes less important. Hence inline is a request not a command. Inlining tends to blow up the code size, because the function is expanding each point of call.
Syntax: inline int myFunc() { }
inline functions are not faster as compared to macros, but they kind of better than macros.
The problem with macros is it wont check syntax errors, and the code literally copies onto the location where it was called.
Ex: int i = 5; int i = 5;
int res = MULT(++i); int res = mult(++i);
macro is: MULT(a) a*a
inline is: inline int mult(int a) { return a*a; }
Macro expands, ++5 * ++5, so result would be 49 which is not expected.
While, inline expands, 6 * 6, so result would be 36 which is expected.
But, in some reasons inline can't prefer.
a) The function calls itself, that is recursive.
b) The function contains loop such as for(;;); or while();
c) The function size is too large.
4. How to variable argument list to a function?
Ans: printf is the best example for variable arguments. printf() is library function which declared int stdio.h. The declaration of printf is:
Syntax: int printf(const char *format, ...);
In order to access arguments within the called function, the functions declared in header file must be included. This introduces a new type called va_list and three functions that operate on objects of this type, called va_start, va_arg, and va_end.
Ex: printArgs(3, 45, 56, 67); // Call from main().
int printArgs(int numArgs, ...)
{
va_list ptr; va_start(ptr, numArgs); // Declare a pointer to arg list and initialized
for (int i = 0; i -lt numArgs; i++)
{
int arg = va_arg(ptr, int); // Retrieving arguments one by one.
printf("%d\n", arg);
}
va_end(ptr); // Set the pointer to point starting location for further use.
}
5. What are #pragmas?
Ans: Pragmas are special compiler commands which controls certain features of a compiler. Two problems arise when using pragmas.
a) Pragmas are compiler specific. You can't expect that one compiler will understand pragmas of other compile, even if both running on same machine.
b) You are not guaranteed that a compiler ignores pragmas, that he doesn't understand. Even more: It might not help, to some thing like this: #ifndef MY_COMPILER
#pragma DoAnything
#endif
A workaround is to put pragmas in a special include file.
The most common use is to tell the compiler about how to call library functions; Simple C functions expect their arguments on the stack, but library functions want their arguments in special processor registers.
6. Is ++i really faster than i = i + 1?
Ans: Any good compiler will and should generate identical code for ++i, i += 1, and i = i + 1; Compilers are meant to optimize the code. The programmer should not bother about such things. Also, it depends on the processor and compiler you are using. One needs to check the compiler's assembly language output, to see which one of the different approaches are better, if at all.
Note that speed comes good, well written algorithms and not from such silly tricks.
The reasons for using ++i or i += 1 or i = i +1 have to do with style, not efficiency.
7. What do mean lval and rval?
Ans: lvalue refers to the left hand side of an assignment expression. It must always evaluate to a memory location. rvalue represents the right side of an assignment expression; it may have any meaningful combination of variable and constant.
8. What is the purpose of typedef?
Ans: typedef is a keyword, used for to assign alternative names to existing data types.
A typedef can be used to simplify the declaration for a compound type(struct, union) or pointer type such as:
Ex: struct var {
int data1;
int data2;
char data3;
};
Here a struct var data type has been defined. To declare a variable of this type: struct var a;
A typedef can be used to eliminate the need for the struct keyword.
typedef struct var newtype;
We can now create a variable of this type with:
newtype a;
9. What is the difference between a deep copy and a shallow copy?
Ans: In object oriented programming, a type includes a collection of member fields. These fields may be stored either by value or by reference.
In shallow copy, a new instance of the type is created and the values are copied into the new instance. The reference pointers are also copied just like values. Therefore, the references are pointing to the original objects. Any changes to the members that are stored by reference appear in both the original and the copy, since no copy was made of the referenced object. Using a copy constructor, we simply copy the data values member by member.
In deep copy, the fields that are stored by value are copied as before, but pointers to objects stored by reference are not copied. Instead, a deep copy is made of the referenced object, and a pointer to the new object is stored. Any changes that are made to those referenced objects will not effect other copies of the object. The overloaded assignment operator would create a deep copy of objects.
10. If 'a' is an array, is a++ is valid?
Ans: No, We will get error message like, Lvalue required in function main().
Doing a++ is asking the compiler to change the base address of the array. This is only thing that the compiler remembers about the an array once its declared and it won't allow to change the base address. If it allows, it would be unable to remember the beginning of the array.
11. What is storage class?
Ans: This is part of variable declaration that tells the compiler how to interpret the variable's symbol. It does't itself allocate storage, but usually tells the compiler how the variables should be stored. Only one storage class specifiers is permitted in a declaration. If you omit the storage class in the declaration, then default storage class would consider. For outside declaration, the default storage class is extern. For inside declaration, auto. The only exception to this rule is the declaration of functions, whose default storage class specifier is always extern.
Some storage classes in C are:
a) auto: Local variables.
b) static: Static variables are defined in a non-volatile memory such that they retain their contents throughout the program's execution.
c) register: Ask the compiler to devote a processor register to this variable in order to speed the program's execution.
d) extern: tells the compiler that the variable is defined in another module.
12. What is the difference between const and #define?
Ans: #define ABC 5
const int abc = 5;
There are two main advantages of the second statement over first.
a) The type of the constant is defined. This allows for some type checking by the compiler. For #define, there is no type.
b) The constants are variables with definite scope. But, #define are global scope.
13. What is structure padding?
Ans: Most processors require specific memory alignment on variables certain types. char variable can be byte aligned and appear at any byte boundary. short variable must be 2 bytes, they can appear at any even byte boundary. This means that 0x123 is not valid location for short, 0x122 is valid location. int variable must be 4 bytes, they can appear any byte boundaries that are multiple of 4 bytes. This means that 0x122 is not memory location for int, 0x124 is valid location.
Ex: struct myStruct {
char a; // 1-byte size
short b; // 2-bytes size
int c; // 4 bytes size
};
If we sum bytes of inside variables in the structure, the value would be 7, but not.
If you assume base memory location for this structure is 0x100.
0x100 - char
0x101 - hole
0x102 and 0x103 - short
0x104-0x107 - int
So, total size of this structure is 8. Padding enables the CPU to access the members faster.
14. What are bit fields in structures?
Ans: Because of padding in structures, some memory holes observed. To avoid wastage of memory in structures, a group of bits can be packed together into an integer and its called a bit field.
Ex: struct student {
char name[30]; // 30-bytes memory
unsigned sex:1; // 1 bit
unsigned age:3; // 3 bits
unsigned rollNo:7; // 7 bits
unsigned branch:2; // 2 bits.
}my;
but, size of this structure is 32 bytes.
There are some limitations with respect to these bit fields, however
a) Cannot scanf() directly into bit fields. Ex: scanf(%d", my.age);
b) Pointers cannot be used on bit fields to access them.
c) Cannot have an array of bit fields.
The main use of bit fields is either to allow tight packing of data or to be able to specify the fields within some externally produced data files.
15. What is union?
Ans: Union is just like a structure contain members whose individual data types may differ from one another. However the members that compose a union all share same storage area within the computers memory whereas each member within a structure us assigned its own unique storage area. Thus unions can save memory if you have a group of data where only one of the type is used at a time. The size of union is equal to the size of it's largest data member. The C compiler allocates just enough space for the largest member. This is because only one member can be used at a time, so the size of the largest is sufficient for all.
Ex: union time {
long simpleTime;
double preciseTime;
} myTime;
The union above could be used to either store the current time in seconds or store the accurate time in milliseconds.
16. What is token pasting operator and stringing operator?
Ans: Token pasting operator is ##.
Ex: #define f(g1,g2) g1##g2
main() {
int var12 = 12;
printf(%d", f(var,12));
}
Output is 12. ## will concatenate strings.
Stringing operator is #
Ex: #define sum(x,y) printf(#xy "=%f\n", xy)
main() {
sum(a+b); // As good as printf("a+b = %f\n", a+b);
}
17. How do stat(), fstat() and vstat() work?
Ans: These functions are used to get the file status.
stat(const char *file_name, struct stat *buff);
- states the file pointed by file_name and fills in buff
fstat(int file_desc, struct stat *buff);
- identical to stat, only open file pointed by file_desc is stat-ed in place of place of file_name.
lstat(const char *file_name, struct stat *buff);
- identical to stat, except in case of a symbolic link, where the link itself is stat-ed, not the file that it refers to.
On success, zero is returned. On error, -1 is returned.
Use function like stat() to find out if a file exist or not. Also, one can open fopen(). When using fopen(), just open for reading and close immediately. If the file does't exist, fopen() will given an error.
18. What are the file related functions?
Ans:
a) fopen: FILE * fopen(const char * filename, const char * mode);
Open the file whose name is specified in the parameter filename and associates it with a stream that can be identified in future operations by the FILE objects whose pointer is returned. The operations that are allowed on the steam and how these performed are defined by the mode parameter. Modes are "r" for read, "w" for write, "a" for append, "r+" for both reading and writing(existing file), "w+" for both reading and writing(new file) and "a+" for reading and appending.
b) fclose: int fclose(FILE *stream);
Closes the file associated with the stream and disassociates it. All internal buffers associated with it are flushed. Even if the call fails, the stream passed as parameter will no longer be associated with the file. On success, zero value is returned, on failure EOF is returned.
c) fprintf: int fprintf(FILE * stream, const char * format, ...);
Writes to the specified stream a sequence of the data formatted as the format argument specifies. After the format parameter, the function expects at least as many additional arguments as specified in format.
d) fscanf: int fscanf(FILE * stream, const * format, ... );
Reads data from the stream and stores the according to the parameter format into the locations pointed by the additional arguments.
e) getc: int getc(FILE * stream);
Get character from stream. Returns the character currently pointed by the internal file position indicator of the specified stream. The internal file position indicator is then advanced by one character to point to the next character.getc is equivalent to fgetc, but getc may be implemented as a macro, so the argument passed to it should be an expression with potential side effects. getchar() is similar function without stream parameter.
f) putc: int putc(int character, FILE * stream);
The character is written at the current position of the stream as indicated by the internal position indicator, which is then advanced one character. pu tc is equivalent to fputc, but getc may be implemented as a macro, so the argument passed to it should be an expression with potential side effects. putchar() is similar function without stream parameter.
g) feof: int feof(FILE * stream);
Checks whether the End-of-File indicator associated with stream is set, returning a different from zero if it is. This indicator is generally set by a previous operation on the stream that reached the End-of-File.
h) fseek: int fseek(FILE * stream, long int offset, int origin);
Set the position indicator associated with the stream to a new position defined by adding offset to a reference position specified by origin. The End-of-File internal indicator of the stream is cleared after a call to this function and all effects from previous calls to ungetc are dropped. Possible origins are
SEEK_SET - Beginning of the file
SEEK_CUR - Current position of the file pointer
SEEK_END - End of the file.
i) rewind: void rewind(FILE * stream);
Set the position indicator associated with stream to the beginning of the file. A call to rewind is equivalent to:
fseek(stream, 0L, SEEK_SET);
Except that, unlike fseek, rewind clears the error indicator.
On streams open for update (read+write), a call to rewind allows to switch between reading and writing.
j) fgetpos: int fgetpos(FILE * stream, fpos_t * pos);
Gets the information needed to uniquely identify the current value of the stream's position indicator and stores it in the location pointed by position. The parameter position should point to an already allocated object of the type fpos_t, which is only intended to be used as a parameter in future calls to fputpos.
k) fsetpos: int fsetpos(FILE * stream, const fpos_t * pos);
Changes the internal file position indicator associated with stream to a new position. The position parameter is a pointer to an fpos_t object whose value shall have been previously obtained with a call to fgetpos.
l) fread: size_t fread(void * ptr, size_t size, size_t count, FILE * stream);
Reads an array of count elements, each one with a size of size bytes, from the steam and stores them in the block of memory specified by ptr. The position indicator of the stream is advanced by the total amount of bytes read. The total amount of bytes read if successful is (size * count).
m) fwrite: size_t fwrite(const void * ptr, size_t size, size_t count, FILE * stream);
Writes an array of count elements, each one with a size of size bytes, from the block of memory pointed by ptr to the current position in the steam. The position indicator of the stream is advanced by the total number of bytes written. The total amount of bytes written is (size*count).
n) fgets: char * fgets(char * str, int num, FILE * stream);
Reads characters from stream and stores them as a C string into str until(num-1) characters have been read or either a newline or the end-of-file is reached, whichever comes first. A newline character makes fgets stop reading, but it is considered a valid character and therefore it is included in the string copied to str. A null character is automatically appended in str after the characters read to signal the end of the C string.
o) fputs: int fputs(const char * str, FILE * stream);
Writes the string pointed by str to the stream. The function begins copying from the address specified(str) until it reaches the terminating null character('\0'). This final null-character is not copied to the stream.