C Language Topics For Interview
C Language Topics For Interview
1. Pre-Processing stage ( .c .i )
• Header files expanded
• Macros will get replaced
• Specific code will be included based on conditional macro’s
• Comments will be removed
2. Compilation/Translation stage ( .i .s )
• Syntax and semantics analyses will be done
• Reports errors if any which will help programmer to fix it.
• Generates assembly code
3. Assembly stage ( .s .o )
• Assembly code converted into machine readable code.
DATA .bss
3 local static Data Section 0 Within function / Till program .rodata
Block exists Mapped
global static Data Section 0 Within a file only Till program to
exists Flash CODE
Qualifiers
• const
Constant variable gets stored in different sections of the memory based on how you are declaring:
auto const variable will be stored in stack section and using pointer you can modify it.
Uninitialized global const variables will be stored in .bss section and using pointers you can modify it.
Assigned global const variables will be stored in RODATA section and using pointers you cannot modify it, it
leads to SIGFAULT or crash.
Static const variable behaviour is undefined.
Strings also gets stored in RODATA section.
• volatile
Assume that there is a TEMP sensor which will sense the temperature data and its driver can read the data and write
into some shared memory and there is an application which will display the whether condition on the screen by
reading the data from that same shared memory.
These are 2 different programs and in application your program only reads this memory value so compiler will
optimizes it to get better performance but we need always updated value from memory so to avoid optimization
we will use volatile.
const volatile is also possible as we are not modifying the variable in that program.
Memory Corruptions
Global Memory Corruption
A global data can be corrupted due to Array index overflow from the previous data or Array index underflow from
the next data.
Uninitialized pointers can also cause this issue.
To debug:
• Put a write break point and debug it.
• If no debug setup available then browse through the code to find if any previous or next data causing this.
• Or else looking at the patterns what has written in your global location can also give you an idea.
Reasons:
• If a crash is observed in memory management primitives of the operating system, heap corruption is a possibility. It has
been observed that memory buffer corruption sometimes leads to corruption of OS buffer linked list, causing crashes on
OS code.
• If a memory corruption is observed in an allocated buffer, check the buffers in the vicinity of this buffer to look for source
of corruption.
• Corruption of buffers close to heap boundary might be due to stack overflow or stack overwrite leading to heap
corruption Conversely, stack corruption might take place if a write into the heap overflows and corrupts the stack area.
Stack Memory Corruption
Stack corruption is a phenomenon in which some memory locations at stack are accessed unintentionally due to wrong
coding leading to change in values at those memory locations. Since the data corruption happens on stack memory
locations, hence the term Stack Corruption.
Reasons :
• Due to bad written code, all the stack memory gets eaten up (like infinite function call)
• Accessing array out of bounds.
• An undefined/freed pointer pointing or storing a garbage stack address.
• When due to some reason, the return address of a function call gets corrupted.
In most of the compilers, some extra bytes will be allocated for any dynamic memory allocations for book-keeping
information like SIZE of the allocation, etc.
1) malloc( 0 ) returns atleast small chunk of memory (16B for example) which needs to be freed later.
2) malloc(-ve value) will try to allocate huge block and fails if memory is not available because malloc takes unsigned value
and –ve value rounded to huge positive value.
3) free(ptr) looks for small chunk to find out SIZE of the allocated memory and frees it.
4) realloc (ptr, 0) also works as malloc (0).
Note:
1) Size of a pointer is equal to size of ARCH-bit/8.
For example, for 64-bit machine, 64/8 = 8 bytes and for 32-bit, 32/8 = 4 bytes.
main()
{
char x[2];
For example PROCESS is an entity and its structure can be defined as below:
struct process
{ without struct padding With struct padding
uint32_t process_no; x0 x0
uint32_t pp_no;
struct process *child_processes; x1 x1
… x2 x2
};
x3 x3
STRUCTURE PADDING: y0 y0
By default any processor access the memory word by word.
For example, on 32-bit ARM processor memory will be accessed 4 bytes (1 word) at a time. z0 0
ARM
z1 0
struct xyz
{ z2 0
int x; z3 z0
char y;
float z; z1
}; z2
z3
Bitfields:
Bitfields are used in the scenario where we use flag in our code and for that no need to waste lot of memory instead we
can use few bits from the byte or word. We can save the memory with bitfields.
Declaration:
struct bitfield
{
char flag1:1;
char flag2:4;
}b;
Typedef:
Using typedef we can give alias name to the existing/user defined data type to increase the readability and simplicity.
list *Node;
UNIONS:
Unions will be used in the scenario where there are multiple members needed in the application for a same entity but all
the members are mutual exclusion.
All the members share the common memory area where highest no. of bytes will be allocated for that union.
Ex:
union xyz
{
char x; x0/y0 y1 y2 y3
int y;
}u;
Enumerations or enums:
Enums are mainly used to assign names to integral constants, the names make a program easy to read and maintain.
enum week
{
Mon,
Tue,
Wed
..
}day;
Arrays of Pointers:
int *p[5] = { &x, &y, arr, &m, &n}
Pointer to Array:
int (*q)[5] = arr; Where arr is int arr[5]; array size must be 5 only.
int a[2][5] = { {1, 2, 3, 4, 5}, {11, 22, 33, 44, 55}};
int (*ptr2)[5] = a;
Below method will not give correct result using pointer to pointer
INLINE function:
Inline function must be declared with static keyword.
Ex:
static inline func(void)
{
}
Diff b/w macro’s and inline functions:
• Macro’s will be expanded in preprocessing stage and inline will be replaced in a code during compilation stage.
• Macros will not do any type checking but inline functions will do it.
Write a macro to find out the biggest among 2 different numbers. Also macro to find out the largest among 3 different
numbers.
Which one is good normal function or inline function:
• Its based on the requirement.
• Normal function always creates stack frame and destroys it once done and lot of other operation takes place which will
consume lot of CPU cycles. And it won’t give better performance compared to inline functions.
• But, with normal function call memory footprint will be less.
• Where as inline function will be expanded during compilation itself so memory footprint will be more.
• But, it gives better performance as there is no CPU cycles wasted during execution.
Note: Formal parameter of the functions can be declared with register storage class only.
Bit-wise operations:
Set bit : n = n | ( 1 << bit ) System is Little endian or big endian
n = ( n & 0xFF000000 >> 24) | ( n & 0x000000FF << 24) | ( n & 0x00FF0000 >> 8) | ( n & 0x0000FF00 << 8)
• Given no. is power of 2 or not : if(n & (n – 1) == 0) then power of 2
• Given no. is power of 4 or not: (1) it should be power of 2 .
(2) c = 0; while((n & 1) == 0) { c++; n >>= 1;} if( n == 1 || (c && c%2 == 0)) then power of 4
• Given no. is even or odd: if(n&1 == 0) then EVEN else ODD
• Reverse the bits of a given number: for(i = 0, j = 31; i<j; i++, j--) { if( !(n & ( 1 << i)) != !(n & (1 << j))) then toggle both bits
• Check if the given no. is –ve : if((n >> 31) & 1 ) == 1) then –ve
• Add 1 to the given no. : x = -(~x);
• Swap 2 no. using bit-wise: x = x^y; y = x^y; x = x^y;
File Operations:
14. Creating a file, reading, writing a file
15. Reading files from directory recursively and searching a particular string in it
16. Print the count of that string present in each file and total count in the directory.
Libraries
• A library in C is a collection of object
files exposed for use and build other
programs, so instead of re-write
sections of code we bring back
information that is already existing
through a library.
• There are 2 different kinds of libraries:
• Static libraries that allows us to link to
the program during compilation
• Dynamic or shared libraries those are
preferable use when you run a lot of
programs at the same time who are
using the same library.
How to create static library?
$gcc –c file1.c file2.c
The flag '-c' we use it to stop the compilation process till compilation and assembly stage but not
done the linker phase so in this case we created a new file call 'file1.o‘ and 'file2.o‘.
• $./test
Dynamic library?
Dynamic libraries (also called shared libraries) are linked into the program in two stages.
• First, during compile time, the linker verifies that all the symbols required by the program, are either linked
into the program or in one of its dynamic libraries. However, the object files from the dynamic library are
not inserted into the executable file.
• Instead, when the program is started, a program in the system (called a dynamic loader) checks out which
shared libraries were linked with the program, loads them to memory, and attaches them to the copy of the
program in memory.
./prog
./test: error while loading shared libraries: lib_dynlib.so: cannot open shared object file: No such file or
directory
$export LD_LIBRARY_PATH=/mnt/d/Code_WS/dynamic_libs
$./prog
THANK YOU…