C Interview Questions and Answers


What is C programming language?
  • C is a general-purpose, procedural, imperative computer programming language developed by Dennis Ritchie at Bell Labs in 1972. It is a low-level language that provides low-level memory access and is widely used for system programming, operating systems, embedded systems, and performance-critical applications.
What are the key features of C?
  • Procedural language.
  • Mid-level language (combines features of low-level and high-level languages).
  • Structured programming.
  • Rich set of built-in functions and operators.
  • Manual memory management (using pointers).
  • Extensibility.
  • Portability (relatively).
Explain the compilation process in C.
  • The compilation process in C involves several stages:
    1. Preprocessing: The preprocessor processes directives like #include (includes header files) and #define (expands macros). The output is a preprocessed source file.
    2. Compilation: The compiler translates the preprocessed code into assembly language.
    3. Assembly: The assembler translates the assembly code into machine code (object code).
    4. Linking: The linker combines the object code with necessary library functions and other object files to create an executable program.
What is the difference between a compiler and an interpreter?
  • Compiler: Translates the entire source code into machine code before execution. Finds errors in the entire program at once. Execution is generally faster after compilation.
  • Interpreter: Translates and executes the source code line by line. Finds errors line by line during execution. Execution is generally slower compared to compiled code. C is a compiled language.
What is the basic structure of a C program?
  • A basic C program structure includes:
    • Preprocessor directives (e.g., #include ).
    • Global declarations (optional).
    • The main() function (the entry point of the program).
    • Body of the main() function with statements, variables, and function calls.
    • User-defined functions (optional).
What is the purpose of the main() function?
  • The main() function is the entry point of execution for any C program. When a C program is run, the execution begins from the first statement inside the main() function. It typically returns an integer value (0 for successful execution, non-zero for errors).
What are keywords in C? Give some examples.
  • Keywords are reserved words in C that have predefined meanings and cannot be used as variable names or identifiers. Examples include int, float, char, void, if, else, for, while, do, switch, case, break, continue, return, sizeof, typedef, struct, union, enum, auto, register, static, extern, const, volatile, signed, unsigned.
What are identifiers?
  • Identifiers are names given to entities in a C program, such as variables, functions, arrays, structures, etc. They must follow certain rules:
    • Can contain letters (A-Z, a-z), digits (0-9), and underscore (_).
    • Must start with a letter or an underscore.
    • Cannot be a keyword.
    • Case-sensitive.
What are the basic data types in C?
  • The basic data types in C are:
    • int: Integer values.
    • char: Single characters.
    • float: Single-precision floating-point numbers.
    • double: Double-precision floating-point numbers.
    • void: Represents the absence of a type.
Explain the difference between char and char[] in C.
  • char: A single character variable.
  • char[]: An array of characters, often used to represent a string. A string in C is a null-terminated array of characters.
What is the purpose of sizeof operator?
  • The sizeof operator is a unary operator that returns the size (in bytes) of a type or a variable. It's useful for determining the memory allocated for different data types or structures.
What is type casting in C?
  • Type casting is the process of converting a value from one data type to another. It can be implicit (automatic conversion by the compiler) or explicit (manual conversion using the cast operator (type)).
What are the different types of operators in C?
  • Arithmetic, Relational, Logical, Assignment, Increment/Decrement, Bitwise, Ternary, Special (sizeof, address-of &, dereference *).
Explain the difference between ++i and i++.
  • ++i (prefix increment): Increments the value of i first, and then uses the new value in the expression.
  • i++ (postfix increment): Uses the current value of i in the expression first, and then increments the value of i.
What is the purpose of if-else statement?
  • The if-else statement is a conditional statement that allows you to execute different blocks of code based on whether a given condition is true or false.
Explain the switch statement.
  • The switch statement is used for selecting one of many code blocks to be executed. It evaluates an expression and compares its value to a list of case labels. When a match is found, the corresponding code block is executed. The break statement is used to exit the switch block.
What is the purpose of loops in C?
  • Loops are used to execute a block of code repeatedly as long as a certain condition is met. C provides while, do-while, and for loops.
Explain the difference between while and do-while loops.
  • while loop: The condition is checked *before* executing the loop body. The loop may not execute at all if the condition is initially false.
  • do-while loop: The loop body is executed *at least once*, and then the condition is checked *after* the first iteration. The loop continues as long as the condition is true.
What is the purpose of break and continue statements?
  • break: Used to exit a loop (for, while, do-while) or a switch statement immediately.
  • continue: Used to skip the rest of the current iteration of a loop and proceed to the next iteration.
What is an array in C?
  • An array is a collection of elements of the same data type stored in contiguous memory locations. Elements are accessed using an index (starting from 0).
How do you declare and initialize an array in C?
  • Declaration: data_type array_name[size]; (e.g., int numbers[10];)
  • Initialization: data_type array_name[size] = {value1, value2, ...}; (e.g., int numbers[] = {1, 2, 3};)
What is a string in C?
  • A string in C is a sequence of characters stored in a character array and terminated by a null character ('\0').
How do you declare and initialize a string in C?
  • Declaration: char string_name[size]; (e.g., char name[20];)
  • Initialization: char string_name[] = "Hello"; or char string_name[] = {'H', 'e', 'l', 'l', 'o', '\0'};
What is the purpose of the header file?
  • The header file contains functions for manipulating strings, such as calculating length (strlen), copying (strcpy), concatenating (strcat), and comparing (strcmp).
What is a function in C?
  • A function is a block of code that performs a specific task. Functions help in breaking down a large program into smaller, manageable modules, promoting code reusability and organization.
What is a function prototype?
  • A function prototype is a declaration of a function that tells the compiler about the function's name, return type, and parameters (number and types) before the function is defined. It's typically placed before the main() function or in a header file.
Explain pass by value and pass by reference in C.
  • Pass by Value: A copy of the actual argument's value is passed to the function. Changes made to the parameter inside the function do not affect the original argument.
  • Pass by Reference: The memory address of the actual argument is passed to the function (using pointers). Changes made to the parameter (using the pointer) inside the function affect the original argument.
What is recursion?
  • Recursion is a programming technique where a function calls itself directly or indirectly to solve a problem. A recursive function must have a base case to stop the recursion.
What is a pointer in C?
  • A pointer is a variable that stores the memory address of another variable. It allows for direct memory access and manipulation.
What are the & and * operators used for with pointers?
  • & (Address-of operator): Returns the memory address of a variable.
  • * (Dereference operator): Accesses the value stored at the memory address pointed to by a pointer.
What is a null pointer?
  • A null pointer is a pointer that does not point to any valid memory location. It is typically initialized with NULL (which is defined as 0 or (void*)0). It's used to indicate that a pointer is not currently pointing to anything.
What is a dangling pointer?
  • A dangling pointer is a pointer that points to a memory location that has been deallocated (e.g., using free()). Accessing a dangling pointer leads to undefined behavior.
What is a void pointer?
  • A void pointer (void *) is a generic pointer that can hold the address of any data type. It cannot be directly dereferenced; it must be type-casted to a specific data type pointer before dereferencing.
What is a pointer to a pointer?
  • A pointer to a pointer is a variable that stores the memory address of another pointer. It is declared using double asterisks (e.g., int **ptr;).
What is dynamic memory allocation in C?
  • Dynamic memory allocation is the process of allocating memory during program execution (runtime) from the heap section of memory. This allows for flexible memory management based on program needs.
What are the functions used for dynamic memory allocation in C?
  • malloc(): Allocates a block of memory of a specified size and returns a void pointer to the beginning of the block. The allocated memory is uninitialized.
  • calloc(): Allocates a block of memory for an array of elements, initializes all bytes to zero, and returns a void pointer.
  • realloc(): Changes the size of a previously allocated memory block.
  • free(): Deallocates the memory previously allocated by malloc(), calloc(), or realloc().
What is a memory leak?
  • A memory leak occurs when dynamically allocated memory is no longer reachable by the program but has not been deallocated using free(). This leads to a gradual reduction in available memory.
What is a structure in C?
  • A structure is a user-defined data type that allows you to group variables of different data types under a single name. It provides a way to create complex data types.
How do you access members of a structure?
  • Using the dot (.) operator for structure variables.
  • Using the arrow (->) operator for pointers to structures.
What is a union in C?
  • A union is a user-defined data type similar to a structure, but all members share the same memory location. Only one member of a union can hold a value at any given time. Unions are used to save memory.
What is the difference between a structure and a union?
  • Structure: Each member has its own separate memory location. The size of a structure is the sum of the sizes of its members (plus padding).
  • Union: All members share the same memory location. The size of a union is the size of its largest member.
What is an enumeration (enum) in C?
  • An enumeration is a user-defined data type that consists of a set of named integer constants. It makes the code more readable by using meaningful names instead of raw integer values.
What is the purpose of the typedef keyword?
  • The typedef keyword is used to create aliases for existing data types. It simplifies the syntax and improves code readability, especially for complex types like structures or pointers.
What is file handling in C?
  • File handling in C refers to the operations performed on files, such as creating, opening, reading, writing, and closing files. It allows for persistent storage and retrieval of data.
What is the FILE pointer in file handling?
  • The FILE pointer (declared as FILE *fp;) is a pointer to a structure that contains information about the file, such as its name, mode, and the current position within the file. It's used to interact with files.
What are the different file modes in C?
  • Common file modes include:
    • "r": Read mode (file must exist).
    • "w": Write mode (creates a new file or truncates an existing one).
    • "a": Append mode (opens for writing at the end of the file).
    • "r+": Read and write mode (file must exist).
    • "w+": Read and write mode (creates a new file or truncates).
    • "a+": Read and append mode (opens for reading and writing at the end).
    • Adding 'b' (e.g., "rb", "wb") specifies binary mode.
What is the difference between text mode and binary mode in file handling?
  • Text mode: Data is interpreted as text, and newline characters might be translated between platform-specific representations (e.g., '\n' to '\r\n' on Windows).
  • Binary mode: Data is read and written as raw bytes without any translation. Used for non-text data like images, executables, etc.
What are preprocessor directives in C?
  • Preprocessor directives are commands that are processed before the actual compilation begins. They start with a '#' symbol. Examples include #include, #define, #ifdef, #ifndef.
Explain the purpose of #include directive.
  • The #include directive is used to include the content of another file (usually a header file) into the current source file during the preprocessing stage.
What is the difference between #include and #include "filename"?
  • #include : The preprocessor searches for the header file in the standard system directories.
  • #include "filename": The preprocessor first searches for the header file in the directory of the current source file, and then in the standard system directories if not found.
What is the purpose of #define directive?
  • The #define directive is used to create macros. Macros are symbolic names or abbreviations for pieces of code. They are replaced by their defined value or code snippet during the preprocessing stage.
What are the types of macros in C?
  • Object-like macros: Simple text substitution (e.g., #define PI 3.14159).
  • Function-like macros: Macros that take arguments and perform text substitution with parameters (e.g., #define SQUARE(x) ((x)*(x))).
What is conditional compilation?
  • Conditional compilation is the process of including or excluding parts of the source code based on certain conditions defined by preprocessor directives like #ifdef, #ifndef, #if, #elif, and #else. This is useful for compiling different versions of a program for different platforms or configurations.
What are include guards?
  • Include guards are preprocessor directives (typically using #ifndef, #define, and #endif) used in header files to prevent the same header file from being included multiple times in a single compilation unit. This avoids redefinition errors.
What are command line arguments in C?
  • Command line arguments are values passed to the program when it is executed from the command line. They are accessed through the parameters of the main() function: argc (argument count) and argv (argument vector - an array of strings).
Explain the use of argc and argv in main().
  • int argc: Represents the number of command line arguments, including the program name itself.
  • char *argv[]: An array of strings (character pointers) where each string is one of the command line arguments. argv[0] is typically the program name.
What are storage classes in C?
  • Storage classes determine the scope, lifetime, and linkage of variables and functions. The main storage classes are auto, register, static, and extern.
Explain the static storage class.
  • The static storage class has different effects depending on where it is applied:
    • Inside a function (local variable): The variable retains its value between function calls (lifetime extends throughout the program execution), but its scope is limited to the function.
    • Outside a function (global variable or function): The variable or function's linkage is restricted to the current source file. It cannot be accessed from other source files using extern.
Explain the extern storage class.
  • The extern storage class is used to declare a variable or function that is defined in another source file or elsewhere in the current file. It tells the compiler that the definition exists elsewhere and linking will resolve it.
What is the difference between const and #define for defining constants?
  • const: A keyword that creates a read-only variable. It is processed by the compiler, has a specific data type, and respects scope.
  • #define: A preprocessor directive that performs simple text substitution. It is processed before compilation, has no data type, and does not respect scope. Generally, const is preferred for type safety and debugging.
What is the difference between malloc() and calloc()?
  • Both allocate memory dynamically.
    • malloc(size): Allocates a single block of memory of size bytes. The allocated memory is uninitialized (contains garbage values).
    • calloc(num_elements, element_size): Allocates memory for an array of num_elements, each of size element_size. It initializes all bytes in the allocated memory to zero.
What is the return value of malloc() and calloc() on failure?
  • Both functions return NULL if the memory allocation fails (e.g., due to insufficient memory).
What is the purpose of realloc()?
  • realloc() is used to resize a previously allocated block of memory. It can either increase or decrease the size. It may return a new memory address if the original block cannot be resized in place.
What is the importance of using free()?
  • Using free() is crucial to deallocate dynamically allocated memory when it's no longer needed. Failing to do so leads to memory leaks, which can consume system resources and eventually crash the program or system.
What is a pointer to a function?
  • A pointer to a function is a variable that stores the memory address of a function. It allows you to call a function indirectly through the pointer. This is useful for implementing callback functions or creating arrays of function pointers.
How do you declare a pointer to a function?
  • The syntax is: return_type (*pointer_name)(parameter_list); (e.g., int (*add_ptr)(int, int);)
What is a callback function?
  • A callback function is a function passed as an argument to another function, which is then invoked inside the receiving function to complete some kind of routine or action. Function pointers are used to implement callbacks.
What is the difference between an array and a pointer?
  • Array: A block of contiguous memory to store elements of the same type. The array name is a constant pointer to the first element. Array size is fixed at compile time (for static arrays).
  • Pointer: A variable that stores a memory address. Can point to single variables or the first element of an array. Pointer values can be changed.
Can you return a pointer from a function? Explain.
  • Yes, you can return a pointer from a function. However, you must be careful not to return a pointer to a local variable that will go out of scope when the function returns. It's safe to return pointers to dynamically allocated memory (allocated with malloc, etc.) or pointers to global/static variables.
What is the difference between NULL and '\0'?
  • NULL: A macro representing a null pointer (typically defined as 0 or (void*)0). Used for pointers.
  • '\0': The null character, which has an ASCII value of 0. Used to terminate strings in C.
What is the difference between "" and ' '?
  • "": Represents an empty string literal. It's a character array containing only the null terminator ({'\\0'}).
  • ' ': Represents a single character literal containing a space.
What is the difference between printf() and sprintf()?
  • printf(): Writes formatted output to the standard output stream (usually the console).
  • sprintf(): Writes formatted output to a character array (string). It does not print to the console.
What is the difference between scanf() and fgets() for reading strings?
  • scanf("%s", str): Reads a sequence of non-whitespace characters. It stops reading when it encounters whitespace (space, newline, tab). It can lead to buffer overflows if the input string is larger than the buffer size.
  • fgets(str, size, stdin): Reads a line of input from the specified stream (e.g., stdin for standard input) up to size-1 characters or until a newline character is encountered. It includes the newline character in the buffer (if read) and automatically adds the null terminator. It is generally safer than scanf("%s", ...) for reading lines.
What is the purpose of the restrict keyword?
  • The restrict keyword is a type qualifier primarily used for pointers. It indicates that the pointer is the sole initial means of accessing the object it points to within the scope of its declaration. This helps the compiler optimize the code more effectively by assuming that the pointed-to data will not be modified through other pointers.
What is a static function?
  • A static function is a function declared with the static keyword. Its scope is limited to the source file in which it is defined. It cannot be called from other source files.
What is a static variable within a function?
  • A static variable within a function retains its value between function calls. It is initialized only once when the function is first called. Its scope is limited to the function, but its lifetime is the entire program execution.
What is the difference between global and static global variables?
  • Global variable: Declared outside any function. Its scope is the entire program, and its linkage is external (can be accessed from other source files using extern).
  • Static global variable: Declared outside any function with the static keyword. Its scope is the entire source file, and its linkage is internal (cannot be accessed from other source files).
What is the purpose of the volatile keyword?
  • The volatile keyword is a type qualifier that tells the compiler that the value of a variable may be changed by something outside the program's control (e.g., hardware, interrupt handler, another thread). This prevents the compiler from optimizing away accesses to the variable, ensuring that the value is always read from memory.
What is the difference between const and volatile?
  • const: Indicates that the program should not change the value of the variable.
  • volatile: Indicates that something *else* might change the value of the variable, and the compiler should not make assumptions about its value.
What is the purpose of enum? (revisited)
  • enum (enumeration) is used to define a set of named integer constants, making the code more readable and maintainable by using descriptive names instead of magic numbers.
Can you assign a value to an enum member?
  • Yes, you can explicitly assign integer values to enum members. If no values are assigned, they are assigned consecutive integers starting from 0 by default.
What is a bit field in a structure?
  • A bit field is a way to specify the number of bits a structure member should occupy. This is useful for saving memory when dealing with flags or small integer values within a structure.
What is the purpose of the sizeof operator? (revisited)
  • The sizeof operator returns the size in bytes of a variable or data type. It's essential for dynamic memory allocation and determining the memory layout of data structures.
What are the different types of errors in C?
  • Syntax errors (compiler errors).
  • Linker errors.
  • Runtime errors (e.g., division by zero, segmentation fault).
  • Logical errors.
How do you debug a C program?
  • Using a debugger (like GDB) to set breakpoints, step through code, inspect variables.
  • Adding print statements to trace program execution and variable values.
  • Checking compiler warnings and errors carefully.
  • Using memory error detection tools (like Valgrind).
What is the purpose of assert()?
  • The assert() macro (from ) is used to add assertions to your code. An assertion checks if a given condition is true. If the condition is false, the program terminates and prints an error message indicating the file name, line number, and the condition that failed. It's primarily used for debugging.
What is the difference between malloc(0) and free(NULL)?
  • malloc(0): Behavior is implementation-defined. It might return NULL or a unique pointer that can be passed to free().
  • free(NULL): This is a safe operation. Calling free() with a NULL pointer has no effect.
Can you free memory allocated by a different function?
  • Yes, you can free memory allocated by a function in another function, as long as you have a valid pointer to the allocated memory block.
What is a segmentation fault?
  • A segmentation fault (or segfault) is a runtime error that occurs when a program tries to access a memory location that it is not allowed to access (e.g., accessing memory outside of its allocated space, dereferencing a null or dangling pointer, writing to read-only memory).
What is the difference between a header file and a source file?
  • Header file (.h): Contains declarations (function prototypes, variable declarations with extern, macro definitions, structure/union/enum definitions). Intended to be included in source files.
  • Source file (.c): Contains the actual definitions of functions and global variables. Contains the executable code.
What is the purpose of the return statement?
  • The return statement is used to exit a function and return control to the calling function. It can also return a value from the function.
What is the default return type of a function if not specified? (Note: This is a common interview question, but the behavior is undefined in C99 and later. In C89, it defaulted to int.)
  • In modern C standards (C99 and later), omitting the return type is **undefined behavior**. The compiler is required to issue a diagnostic message. You should always explicitly specify the return type of a function.
What is the difference between const int *p, int *const p, and const int *const p?
  • const int *p: Pointer to a constant integer. The value pointed to by p cannot be changed through p, but p itself can be changed to point to a different memory location.
  • int *const p: Constant pointer to an integer. The pointer p cannot be changed to point to a different memory location, but the value pointed to by p can be changed.
  • const int *const p: Constant pointer to a constant integer. Neither the pointer p nor the value pointed to by p can be changed.
What is the purpose of goto statement? (Note: Generally discouraged)
  • The goto statement is used for unconditional jumps to a labeled statement within the same function. While it can be used, it often makes code hard to read and maintain and is generally considered bad practice.
What is the difference between a function and a macro?
  • Function: Compiled code, involves function call overhead, parameters are evaluated before the call, type-checked by the compiler.
  • Macro: Text substitution by the preprocessor, no function call overhead, parameters are substituted as text, no type checking (can lead to unexpected behavior).
What are the advantages and disadvantages of using macros?
  • Advantages: Faster execution (no function call overhead), can work with any data type (if written generically).
  • Disadvantages: No type checking, can lead to unexpected side effects with expressions as arguments, can increase code size (code is expanded inline), difficult to debug.
What is the difference between struct and class? (Note: class is not in C, but a common comparison question)
  • struct (C): A user-defined data type to group variables of different types. By default, members are public. Does not support features like inheritance, polymorphism, or access specifiers (public/private/protected).
  • class (C++): A blueprint for creating objects. Encapsulates data and methods. Supports object-oriented programming concepts like inheritance, polymorphism, and access specifiers. By default, members are private.
What is the purpose of the main() function returning an integer?
  • The integer value returned by main() is the exit status of the program. A return value of 0 typically indicates successful execution, while a non-zero value indicates an error. This value can be checked by the operating system or calling process.
What is the difference between an Lvalue and an Rvalue?
  • Lvalue: An expression that refers to a memory location that can be assigned a value (e.g., a variable name). It appears on the left side of an assignment operator.
  • Rvalue: An expression that represents a value but does not necessarily refer to a specific memory location that can be assigned to (e.g., a literal, a result of an expression). It appears on the right side of an assignment operator.
What is pointer arithmetic?
  • Pointer arithmetic is performing arithmetic operations (addition, subtraction) on pointers. When adding or subtracting an integer to a pointer, the pointer is incremented or decremented by a multiple of the size of the data type it points to.
Can you add two pointers?
  • No, you cannot add two pointers in C. This operation does not have a meaningful interpretation in terms of memory addresses.
Can you subtract two pointers?
  • Yes, you can subtract two pointers if they point to elements within the same array. The result is the number of elements between the two pointers (an integer type like ptrdiff_t).
What is the purpose of the void keyword? (revisited)
  • void is used to indicate:
    • That a function does not return a value (e.g., void myFunction()).
    • That a function does not accept any parameters (e.g., int myFunction(void)).
    • A generic pointer that can point to any data type (void *).
What is the difference between NULL and a dangling pointer? (revisited)
  • NULL: A pointer that is explicitly assigned a value indicating it points to no valid memory.
  • Dangling pointer: A pointer that points to a memory location that *was* valid but has since been deallocated.
What is the purpose of the register storage class?
  • The register storage class suggests to the compiler that the variable should be stored in a CPU register for faster access. However, the compiler is free to ignore this suggestion. You cannot take the address of a register variable.
What is the difference between static and extern linkage?
  • Internal linkage (static): The identifier is only visible within the current translation unit (source file).
  • External linkage (extern): The identifier is visible across multiple translation units.
What is the purpose of the const qualifier? (revisited)
  • The const qualifier is used to declare variables whose values cannot be changed after initialization. It enforces read-only access and helps the compiler perform optimizations.
Can you modify a const variable using a pointer?
  • Yes, you *can* technically modify a const variable using a pointer that is not declared as pointing to a constant (e.g., casting a const int * to an int *). However, this is **undefined behavior** and should be avoided.
What is the difference between an array name and a pointer to the first element of an array?
  • In most contexts, the array name decays into a pointer to its first element. However, there are exceptions:
    • When used with sizeof, sizeof(array_name) gives the total size of the array, while sizeof(pointer) gives the size of the pointer variable.
    • When used with the address-of operator &, &array_name gives the address of the entire array, while &array_name[0] or &(*pointer) gives the address of the first element.
What is the maximum size of an array in C?
  • The maximum size of an array in C is limited by the available memory and the system architecture (e.g., 32-bit or 64-bit).
What is the difference between gets() and fgets()? (revisited)
  • gets(): Reads a line from standard input until a newline or EOF is encountered. It does **not** include the newline character and does **not** have a buffer size limit, making it vulnerable to buffer overflows. **Avoid using gets().**
  • fgets(): Reads a line from a specified stream (e.g., stdin) up to a specified size or until a newline/EOF. It includes the newline character (if read) and null-terminates the string. It is safer than gets().
What is the purpose of the #pragma directive?
  • The #pragma directive is a compiler-specific directive that allows you to give instructions to the compiler. Its behavior varies between compilers. Common uses include controlling compiler warnings or specifying packing alignments for structures.
What are bitwise operators?
  • Bitwise operators perform operations on individual bits of integers. They include AND (&), OR (|), XOR (^), NOT (~), left shift (<<), and right shift (>>).
Explain the difference between logical AND (&&) and bitwise AND (&).
  • Logical AND (&&): Used with boolean expressions. Returns true (non-zero) if both operands are non-zero, false (0) otherwise. Short-circuits (evaluates the second operand only if the first is true).
  • Bitwise AND (&): Performs a bit-by-bit AND operation on the operands.
Explain the difference between logical OR (||) and bitwise OR (|).
  • Logical OR (||): Used with boolean expressions. Returns true (non-zero) if at least one operand is non-zero, false (0) otherwise. Short-circuits (evaluates the second operand only if the first is false).
  • Bitwise OR (|): Performs a bit-by-bit OR operation on the operands.
What is the purpose of the ternary operator (?:)?
  • The ternary operator is a shorthand for a simple if-else statement. Its syntax is condition ? expression_if_true : expression_if_false;. It returns one of two expressions based on the condition.
What is the difference between struct student s; and struct student *s;?
  • struct student s;: Declares a variable s of type struct student. Memory for the structure is allocated directly. You access members using the dot operator (s.member).
  • struct student *s;: Declares a pointer variable s that can point to a struct student. Memory for the pointer is allocated, but memory for the structure itself is not. You need to allocate memory for the structure (e.g., using malloc()) and then make s point to it. You access members using the arrow operator (s->member).
What is padding in structures?
  • Padding is the process where the compiler inserts extra bytes between structure members or at the end of a structure to ensure proper alignment for the system's architecture. This can affect the size of a structure.
How can you avoid structure padding?
  • You can sometimes minimize padding by ordering structure members from largest to smallest. Some compilers also provide #pragma pack directives or other attributes to control padding, but this can make the code non-portable and might lead to performance issues.
What is the difference between exit(0) and exit(1)?
  • Both exit(0) and exit(1) terminate the program.
    • exit(0): Conventionally indicates successful program execution.
    • exit(1) (or any non-zero value): Conventionally indicates that the program terminated with an error.
What is the difference between exit() and _exit()?
  • exit(): Performs cleanup operations before terminating, such as flushing output buffers and calling functions registered with atexit().
  • _exit(): Terminates the program immediately without performing any cleanup.
What is the purpose of atexit()?
  • The atexit() function registers a function to be called when the program terminates normally (i.e., by returning from main() or calling exit()).
What is the difference between const char *p = "hello"; and char p[] = "hello";?
  • const char *p = "hello";: Declares a pointer p that points to the beginning of a string literal "hello". String literals are typically stored in read-only memory, so you cannot modify the characters through p. p itself can be changed to point elsewhere.
  • char p[] = "hello";: Declares a character array p and initializes it with the characters of "hello" (plus the null terminator). The array is stored in writable memory (e.g., on the stack), so you can modify the characters in the array. p is the array name, which is a constant pointer to the first element and cannot be changed.
What is the difference between malloc(size) and new type[size]? (Note: new is C++)
  • malloc(size) (C): Allocates raw memory. Returns a void* that needs to be type-casted. Does not call constructors for objects.
  • new type[size] (C++): Allocates memory and calls the constructor for each element in the array. Returns a pointer of the specified type.
What is the difference between free(ptr) and delete[] ptr? (Note: delete[] is C++)
  • free(ptr) (C): Deallocates memory previously allocated by malloc, calloc, or realloc.
  • delete[] ptr (C++): Deallocates memory for an array allocated with new[] and calls the destructor for each element in the array before deallocating the memory.
What is the purpose of the restrict keyword? (revisited)
  • The restrict keyword is a type qualifier for pointers that tells the compiler that the pointer is the only way to access the object it points to within its scope. This allows the compiler to make optimizations that would otherwise be unsafe.
What is a self-referential structure?
  • A self-referential structure is a structure that contains a member which is a pointer to another structure of the same type. This is commonly used to build linked data structures like linked lists, trees, and graphs.
How do you represent a linked list node in C?
  • A linked list node is typically represented as a structure containing the data and a pointer to the next node:
    struct Node {
        int data;
        struct Node *next;
    };
What is the difference between passing an array to a function and passing a pointer to the first element?
  • When you pass an array to a function, what is actually passed is a pointer to the first element of the array. The size information of the original array is lost within the function. You typically need to pass the size of the array as a separate argument.
What is the purpose of the volatile keyword? (revisited)
  • The volatile keyword is a type qualifier that prevents the compiler from performing certain optimizations on a variable, ensuring that every access to the variable reads directly from memory. This is necessary when the variable's value can be changed by external factors (like hardware or other threads).
What is the difference between auto and register storage classes?
  • auto: The default storage class for local variables. Variables are stored on the stack and exist only within their scope.
  • register: A hint to the compiler to store the variable in a CPU register for faster access. The compiler may ignore the hint. You cannot take the address of a register variable.
What is the purpose of #undef directive?
  • The #undef directive is used to undefine a previously defined macro. This allows the macro name to be reused later or to prevent its expansion.
What is the difference between a function declaration and a function definition?
  • Declaration (Prototype): Specifies the function's name, return type, and parameters. It tells the compiler about the function's signature.
  • Definition: Provides the actual implementation (body) of the function.
What is the purpose of the static keyword in the context of a function definition? (revisited)
  • When applied to a function definition, static limits the scope of the function to the current source file. It cannot be called from other source files.
What are some common standard libraries in C?
  • (Standard Input/Output)
  • (Standard Library - includes memory allocation, conversions, etc.)
  • (String Manipulation)
  • (Mathematical Functions)
  • (Character Classification)
  • (Date and Time Functions)
  • (Boolean Type - C99)
What is the purpose of const in function parameters?
  • Using const with function parameters (e.g., void print_string(const char *str)) indicates that the function will not modify the value of the parameter. This allows the compiler to enforce immutability and helps users of the function understand its behavior.
What is the purpose of the restrict keyword? (final revisit)
  • The restrict keyword is a type qualifier for pointers that tells the compiler that the pointer is the only way to access the object it points to within its scope. This allows the compiler to make optimizations that would otherwise be unsafe.
What is the difference between size_t and ssize_t? (Note: ssize_t is often found in POSIX systems)
  • size_t: An unsigned integer type used to represent sizes of objects and counts. It is the return type of sizeof.
  • ssize_t: A signed integer type used to represent sizes or counts that can also be negative (e.g., for error indications in system calls).
What is the purpose of the va_list, va_start, va_arg, and va_end macros?
  • These macros (from ) are used to handle functions with a variable number of arguments (variadic functions), like printf().
    • va_list: Declares a variable to hold the arguments.
    • va_start: Initializes the va_list variable.
    • va_arg: Retrieves the next argument from the list.
    • va_end: Cleans up the va_list variable.
What is the difference between an empty structure and a structure with a single member?
  • An empty structure (e.g., struct Empty {};) is not allowed in standard C. A structure must have at least one member. A structure with a single member will have a size at least equal to the size of that member (possibly more due to padding).
What is the purpose of the _Noreturn function specifier (C11)?
  • The _Noreturn function specifier indicates that a function will not return to its caller (e.g., functions like exit() or abort()). This allows the compiler to make optimizations by knowing that the code after a call to such a function is unreachable.
What is the difference between const void *p; and void *const p;?
  • const void *p;: Pointer to a constant void. You cannot modify the data pointed to by p using p (after casting to a specific type), but p itself can be changed to point elsewhere.
  • void *const p;: Constant pointer to void. The pointer p cannot be changed to point elsewhere, but the data pointed to by p can be modified (after casting to a specific type).
What is strict aliasing?
  • Strict aliasing is a rule in C that restricts how pointers of different types can access the same memory location. It assumes that pointers of different types do not point to the same data unless the types are compatible or one is a char*. Violating strict aliasing rules can lead to undefined behavior due to compiler optimizations.
What is the difference between #define SIZE 10 and enum { SIZE = 10 };?
  • #define SIZE 10: A preprocessor macro for text substitution. No type safety, no scope.
  • enum { SIZE = 10 };: Declares an integer constant within an anonymous enum. Provides type safety and respects scope. Generally preferred over #define for defining integer constants.
What is the difference between an array of pointers and a pointer to an array?
  • Array of pointers: An array where each element is a pointer (e.g., int *arr[5]; - an array of 5 pointers to integers).
  • Pointer to an array: A pointer that points to an entire array (e.g., int (*ptr_arr)[5]; - a pointer to an array of 5 integers).
What is the purpose of function pointers? (revisited)
  • Function pointers allow you to store the address of a function in a variable and call the function indirectly through the pointer. They are used for implementing callbacks, creating jump tables, and passing functions as arguments.
What is the difference between char *p = "hello"; and char p[] = "hello";? (revisited)
  • char *p = "hello";: p is a pointer to the first character of a string literal stored in read-only memory. Modifying the string via p is undefined behavior.
  • char p[] = "hello";: p is an array initialized with the string literal. The array is in writable memory, and its contents can be modified.
What is the purpose of the restrict keyword? (final final revisit)
  • The restrict keyword is a type qualifier for pointers that tells the compiler that the pointer is the only way to access the object it points to within its scope. This allows the compiler to make optimizations that would otherwise be unsafe, particularly in loops involving pointer manipulation.