10 Questions × 2 Marks = 20 Marks | Answer ALL questions
6 Questions × 5 Marks = 30 Marks | Answer ANY FOUR (200–250 words)
4 Questions × 10 Marks = 40 Marks | Answer ANY THREE (400–500 words)
In C, comments are enclosed in /* */ for multi-line comments and // for
single-line comments (C99+). The # symbol is used for preprocessor directives, not
comments. * and ** are used for pointers.
Every C program must have exactly one main() function — it's the entry point. The
operating system calls main() when the program starts. printf() and
scanf() are library functions, not mandatory.
scanf() reads data from stdin (keyboard by default) according to format
specifiers like %d, %f, %s. Example:
scanf("%d", &x); reads an integer from the user.
x -= 3 is shorthand for x = x - 3. Since x = 8: 8 - 3 = 5. The
compound assignment operators (+=, -=, *=, /=)
combine an arithmetic operation with assignment.
continue skips the remaining code in the current loop iteration and jumps to the next
iteration's condition check. Unlike break (which exits the loop entirely),
continue keeps the loop running.
while(1) creates an infinite loop because the condition 1 is always true.
The variable i keeps incrementing until overflow. To exit such a loop, you'd need a
break statement inside.
Recursion is when a function calls itself. Every recursive function needs a base
case to terminate. Example: factorial — fact(n) = n * fact(n-1) with base
case fact(0) = 1.
Tokenization splits a string into smaller pieces using a delimiter. In C, strtok() does
this. Example: strtok("hello world", " ") returns "hello" first, then "world" on the
next call.
C does not have a for each keyword. It uses for, while, and
do-while loops. "for each" exists in languages like Java and Python but not in standard
C.
The tilde ~ performs bitwise NOT — it flips all bits. Example: ~5 (binary
0101) = -6 (binary ...1010 in two's complement). | is OR, << is left
shift, >> is right shift.
📝 Each answer below is written to the 200–250 word exam requirement
C is a general-purpose, structured programming language developed by Dennis Ritchie at Bell Laboratories in 1972. It is one of the most influential programming languages in computing history and has several distinctive characteristics that make it widely used even today.
1. Structured Language: C supports modular programming through functions. A large program can be divided into smaller, manageable functions that can be developed, tested, and debugged independently. This promotes code reusability and maintainability.
2. Middle-Level Language: C combines the features of both high-level languages (readability, abstraction) and low-level languages (direct hardware access). This makes it suitable for both system programming (operating systems, device drivers) and application development.
3. Rich Set of Operators: C provides a comprehensive set of operators including arithmetic, relational, logical, bitwise, assignment, and conditional operators. This allows programmers to perform complex operations concisely.
4. Pointers: C supports pointers, which are variables that store memory addresses. Pointers enable dynamic memory allocation, efficient array handling, and direct hardware manipulation — features critical for system-level programming.
5. Portability: C programs written on one platform can be compiled and executed on other platforms with minimal or no modifications. This cross-platform capability has contributed to C's widespread adoption.
6. Fast Execution: C produces highly optimized machine code, making it one of the fastest high-level languages available. Its efficiency is close to assembly language.
7. Extensibility: C allows programmers to create custom functions and libraries, extending the language's capabilities as needed for specific applications.
The const keyword in C is a type qualifier that declares a variable as read-only,
meaning its value cannot be modified after initialization. It plays an important role in writing
safe, readable, and maintainable code.
Syntax and Usage: When a variable is declared with const, it must be
initialized at the time of declaration, and any subsequent attempt to modify it will result in a
compilation error.
const int MAX_SIZE = 100; MAX_SIZE = 200; // ERROR: assignment of read-only variable const float PI = 3.14159; PI = 3.14; // ERROR: cannot modify a const variable
Significance:
1. Prevents Accidental Modification: By marking variables as const,
programmers ensure that critical values (like mathematical constants or configuration parameters)
cannot be accidentally changed during program execution. This prevents subtle bugs that are
difficult to detect.
2. Improves Code Readability: Using const clearly communicates to other
developers that a particular value is intended to remain fixed throughout the program's execution.
This makes the code self-documenting and easier to understand.
3. Compiler Optimization: The compiler can optimize const variables
more aggressively because it knows their values will never change. This can lead to faster and more
efficient code.
4. Safer than #define: Unlike #define macros, const
variables have a specific data type and obey scope rules. This provides type safety and prevents
naming conflicts that can occur with preprocessor macros.
5. Pointer Safety: const can be used with pointers to prevent
modification of the pointed-to data: const int *ptr means the data pointed to cannot be
changed through the pointer.
The if-else statement is one of the most fundamental decision-making constructs in C programming. It allows the program to execute different blocks of code depending on whether a condition evaluates to true (non-zero) or false (zero). There are several forms of the if-else statement.
1. Simple if Statement: The simplest form executes a block of code only when the condition is true. If the condition is false, the block is skipped entirely.
if (age >= 18) {
printf("You are eligible to vote.\n");
}
2. if-else Statement: This form provides an alternative block of code that executes when the condition is false, ensuring that one of the two blocks always executes.
if (marks >= 40) {
printf("Result: Pass\n");
} else {
printf("Result: Fail\n");
}
3. else-if Ladder: When multiple conditions need to be checked sequentially, the else-if ladder is used. The program evaluates conditions from top to bottom and executes the first matching block.
if (grade == 'A') {
printf("Excellent\n");
} else if (grade == 'B') {
printf("Good\n");
} else if (grade == 'C') {
printf("Average\n");
} else {
printf("Below Average\n");
}
The condition inside if() is evaluated as true (any non-zero value) or false (zero).
Only one block in an if-else chain executes. Proper use of braces {} is recommended
even for single-statement blocks to prevent logical errors.
In C programming, there are two methods for passing arguments to functions: Call by Value and Call by Address (also called Call by Reference). Understanding the difference between these two methods is crucial for effective function design.
Call by Value: In this method, a copy of the actual argument's value is passed to the function parameter. Any changes made to the parameter inside the function do not affect the original variable in the calling function. The original data remains safe and unmodified.
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
// Only local copies are swapped
}
int main() {
int x = 10, y = 20;
swap(x, y);
printf("x=%d, y=%d", x, y); // x=10, y=20 (unchanged!)
}
Call by Address: In this method, the memory address of the actual argument is passed to the function using pointers. The function accesses and modifies the original variable directly through its memory address. Changes made inside the function are reflected in the calling function.
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
// Original values are swapped via pointers
}
int main() {
int x = 10, y = 20;
swap(&x, &y);
printf("x=%d, y=%d", x, y); // x=20, y=10 (swapped!)
}
Key Differences: Call by Value is safer because the original data is protected, but it cannot modify the original variables. Call by Address allows functions to modify original data, which is essential for operations like swapping values, dynamic memory allocation, and returning multiple values from a function.
A function prototype (also called a function declaration) is a statement that informs the compiler about a function's name, return type, and the number and types of its parameters before the function is actually defined or called. Function prototypes are typically placed at the beginning of a program or in header files.
Syntax:
return_type function_name(parameter_type1, parameter_type2, ...); // Examples: int add(int, int); float calculateArea(float, float); void displayMessage(char[]);
Importance of Function Prototypes:
1. Type Checking at Compile Time: The prototype enables the compiler to verify that function calls use the correct number and types of arguments. Without a prototype, passing a float where an int is expected would go undetected, potentially causing runtime errors or incorrect results.
2. Enables Function Definition After main(): Programmers can define functions after
main() while still calling them from within main(). The prototype tells
the compiler what to expect before it encounters the actual function definition.
int add(int, int); // prototype
int main() {
int result = add(3, 5); // compiler knows add() signature
printf("Sum: %d\n", result);
}
int add(int a, int b) { return a + b; }
3. Prevents Implicit Declaration Warnings: Without a prototype, the compiler assumes
a default return type of int and does not check parameter types, which can lead to
subtle and dangerous bugs. Modern compilers issue warnings for missing prototypes.
4. Essential for Multi-File Programs: In large projects with multiple source files,
function prototypes are placed in header files (.h files). This allows functions
defined in one file to be called from another file, enabling modular programming.
The assignment operator (=) and the equality operator (==) are two distinct
operators in C that serve fundamentally different purposes. Confusing these two operators is one of
the most common and dangerous bugs in C programming.
Assignment Operator (=): The assignment operator stores a value in a variable. It takes the value on the right side and assigns it to the variable on the left side. The expression itself evaluates to the assigned value.
int x = 5; // assigns 5 to x float pi = 3.14; // assigns 3.14 to pi x = x + 3; // x becomes 8
Equality Operator (==): The equality operator compares two values and returns 1 (true) if they are equal, or 0 (false) if they are not. It does not modify either operand — it only checks for equality.
if (x == 5) {
printf("x is equal to 5\n");
}
if (a == b) {
printf("a and b are equal\n");
}
Common Bug — Using = Instead of ==: This is a frequently made mistake that can cause
serious logical errors. When = is used inside an if condition, it performs
an assignment rather than a comparison:
if (x = 5) // WRONG: assigns 5 to x, always true! if (x == 5) // CORRECT: compares x with 5
The expression x = 5 assigns 5 to x and evaluates to 5 (non-zero = true), so the
condition is always true regardless of x's original value. This subtle bug is difficult to detect
because the compiler does not always flag it as an error. To prevent this, some programmers use the
"Yoda condition" technique: if (5 == x) — this causes a compiler error if
= is accidentally used.
📝 Each answer below is written to the 400–500 word exam requirement
The switch-case statement is a multi-way branching statement in C that provides an efficient and readable alternative to long if-else-if ladders when a variable needs to be compared against multiple constant values. It evaluates an expression once and then matches the result against a series of case labels, executing the corresponding block of code.
Syntax:
switch (expression) {
case constant1:
// statements for constant1
break;
case constant2:
// statements for constant2
break;
...
default:
// statements if no case matches
}
How It Works: The expression inside the switch() is evaluated once, and
its value is compared against each case label sequentially. When a matching case is
found, the statements following that case are executed until a break statement is
encountered. The break statement transfers control out of the switch block, preventing
"fall-through" to subsequent cases. The default case is optional and executes when no
other case matches — it acts as a catch-all, similar to the final else in an if-else
ladder.
Detailed Example — Simple Calculator:
#include <stdio.h>
int main() {
char operator;
float num1, num2, result;
printf("Enter operator (+, -, *, /): ");
scanf("%c", &operator);
printf("Enter two numbers: ");
scanf("%f %f", &num1, &num2);
switch (operator) {
case '+':
result = num1 + num2;
printf("%.2f + %.2f = %.2f\n", num1, num2, result);
break;
case '-':
result = num1 - num2;
printf("%.2f - %.2f = %.2f\n", num1, num2, result);
break;
case '*':
result = num1 * num2;
printf("%.2f * %.2f = %.2f\n", num1, num2, result);
break;
case '/':
if (num2 != 0) {
result = num1 / num2;
printf("%.2f / %.2f = %.2f\n", num1, num2, result);
} else {
printf("Error: Division by zero!\n");
}
break;
default:
printf("Error: Invalid operator '%c'\n", operator);
}
return 0;
}
Important Rules and Characteristics:
1. Expression Type: The switch expression must evaluate to an integer or character type. Floating-point numbers and strings are not allowed as switch expressions or case labels.
2. Case Labels Must Be Constants: Each case label must be a compile-time constant expression (integer literal or character literal). Variables and expressions are not permitted as case labels.
3. Break Statement: Without break, execution "falls through" to the
next case. This is sometimes used intentionally when multiple cases should execute the same code,
but unintentional fall-through is a common source of bugs.
4. Default Case: While optional, including a default case is considered
good practice as it handles unexpected or invalid input values gracefully.
5. No Duplicate Cases: Each case label must be unique within the same switch block. Duplicate values cause a compilation error.
Advantages over if-else: Switch-case is more readable and efficient for multi-way branching based on a single variable. The compiler can optimize switch statements using jump tables, making them faster than equivalent if-else chains for large numbers of cases.
The if statement is the most fundamental decision-making construct in C programming. It
controls the flow of program execution by allowing the program to choose between different paths
based on whether a specified condition evaluates to true (any non-zero value) or false (zero). The
if statement comes in several forms, each suited to different decision-making scenarios.
1. Simple if Statement: The simplest form of the if statement executes a block of code only when the condition is true. If the condition is false, the program simply skips the block and continues with the next statement after it. This is useful when an action needs to be performed only under specific circumstances, without any alternative action.
// Syntax:
if (condition) {
// code executes only when condition is true
}
// Example:
int temperature = 35;
if (temperature > 30) {
printf("Warning: It is very hot today!\n");
printf("Stay hydrated and avoid direct sunlight.\n");
}
// Program continues here regardless of condition
2. if-else Statement: The if-else form provides a two-way branching mechanism. When the condition is true, the if-block executes; when it is false, the else-block executes instead. This guarantees that exactly one of the two blocks will always execute, making it useful for binary decisions.
// Example:
int age = 16;
if (age >= 18) {
printf("You are eligible to vote.\n");
} else {
printf("You are not eligible to vote yet.\n");
printf("You need to wait %d more years.\n", 18 - age);
}
3. else-if Ladder (Nested if): When multiple conditions need to be evaluated
sequentially, the else-if ladder is used. The program checks each condition from top to bottom and
executes the first block whose condition is true. If no condition is true, the optional final
else block executes as a default. This structure is essential for grading systems,
menu-driven programs, and any scenario requiring multiple mutually exclusive outcomes.
// Example: Grade calculation
int marks = 82;
if (marks >= 90) {
printf("Grade: A (Outstanding)\n");
} else if (marks >= 75) {
printf("Grade: B (Very Good)\n");
} else if (marks >= 60) {
printf("Grade: C (Good)\n");
} else if (marks >= 40) {
printf("Grade: D (Satisfactory)\n");
} else {
printf("Grade: F (Fail)\n");
}
4. Ternary Operator (Shorthand if-else): C provides a compact alternative for simple
if-else decisions using the conditional operator ? :. The syntax is:
result = (condition) ? value_if_true : value_if_false; For example:
int max = (a > b) ? a : b; This assigns the larger of a and b to max in a single line.
Important Notes: Conditions in if statements can use relational operators
(>, <, ==, !=, >=,
<=) and logical operators (&&, ||, !)
to form complex expressions. Always use curly braces {} for the if and else blocks,
even for single statements, to prevent subtle bugs when modifying code later. The if statement can
be nested to any depth, but excessive nesting reduces readability — in such cases, consider using
switch-case or restructuring the logic.
Strings in C are arrays of characters terminated by a null character (\0). Unlike
languages like Python or Java, C does not have a built-in string data type, so it relies on
character arrays and a rich set of library functions provided in the <string.h>
header file to manipulate strings. Understanding these functions is essential for effective text
processing in C programs.
1. strlen() — String Length: This function returns the number of characters in a
string, excluding the null terminator. It iterates through the string counting characters until it
encounters \0.
char name[] = "Hello"; int len = strlen(name); // len = 5 (not 6, excludes \0)
2. strcpy() — String Copy: This function copies the contents of the source string into the destination string, including the null terminator. The destination must have enough space to hold the copied string, otherwise buffer overflow occurs.
char dest[20]; strcpy(dest, "Hello World"); // dest now contains "Hello World"
3. strcat() — String Concatenation: This function appends the source string to the end of the destination string. The null terminator of the destination is overwritten by the first character of the source, and a new null terminator is added at the end.
char greeting[30] = "Hello"; strcat(greeting, " World"); // greeting = "Hello World"
4. strcmp() — String Comparison: This function compares two strings character by
character using their ASCII values. It returns 0 if the strings are equal, a negative value if the
first string is lexicographically less than the second, and a positive value if greater. This
function is essential because the == operator cannot compare string contents in C — it
only compares addresses.
int result = strcmp("Apple", "Banana"); // negative (A < B)
int result2 = strcmp("Hello", "Hello"); // 0 (equal)
5. strrev() — String Reverse: This function reverses a string in place. Note that
strrev() is not part of the ANSI C standard but is available in many compilers (like
Turbo C). In standard C, string reversal must be implemented manually using a loop that swaps
characters from both ends of the string toward the center.
6. strtok() — String Tokenization: This function breaks a string into a series of
tokens using specified delimiter characters. On the first call, the string and delimiter are passed.
On subsequent calls, NULL is passed as the first argument to continue tokenizing the
same string.
char str[] = "Hello World C";
char *token = strtok(str, " ");
while (token != NULL) {
printf("%s\n", token); // prints Hello, World, C
token = strtok(NULL, " ");
}
7. strstr() — Substring Search: This function finds the first occurrence of a
substring within a larger string. It returns a pointer to the beginning of the located substring, or
NULL if the substring is not found.
char *result = strstr("Hello World", "World");
// result points to "World" within the original string
Conclusion: These string handling functions are fundamental tools in C programming. They enable text processing, data parsing, input validation, and many other operations. Understanding their proper usage, including memory allocation requirements and null terminator handling, is essential for writing correct and efficient C programs.
Loops are fundamental control structures in C programming that allow a block of code to be executed repeatedly as long as a specified condition remains true. They are essential for automating repetitive tasks, processing arrays, reading input, and implementing algorithms. C provides three types of loops, each designed for different scenarios.
1. for Loop: The for loop is the most commonly used loop in C programming. It is ideal when the number of iterations is known in advance. The for loop combines initialization, condition checking, and increment/decrement in a single line, making it compact and readable.
// Syntax:
for (initialization; condition; update) {
// loop body
}
// Example: Print numbers 1 to 10
for (int i = 1; i <= 10; i++) {
printf("%d ", i);
}
// Output: 1 2 3 4 5 6 7 8 9 10
// Example: Sum of first N natural numbers
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
printf("Sum = %d", sum); // Sum = 5050
The for loop executes in this order: initialization (once) → condition check → body execution → update → condition check → ... This continues until the condition becomes false.
2. while Loop: The while loop is a pre-test loop, meaning it checks the condition before each iteration. If the condition is false initially, the loop body never executes — zero iterations are possible. The while loop is best suited when the number of iterations depends on a condition rather than a fixed count.
// Syntax:
while (condition) {
// loop body
// update statement
}
// Example: Print digits of a number
int num = 12345;
while (num > 0) {
printf("%d ", num % 10); // print last digit
num = num / 10; // remove last digit
}
// Output: 5 4 3 2 1
A key distinction of the while loop is that the programmer is responsible for including the update statement within the loop body. Forgetting this leads to an infinite loop.
3. do-while Loop: The do-while loop is a post-test loop, meaning it executes the loop body first and then checks the condition. This guarantees that the loop body executes at least once, even if the condition is false from the start. This makes the do-while loop ideal for menu-driven programs and input validation.
// Syntax:
do {
// loop body
} while (condition); // note the semicolon!
// Example: Menu-driven program
int choice;
do {
printf("\n1. Add\n2. Delete\n3. Exit\n");
printf("Enter choice: ");
scanf("%d", &choice);
switch(choice) {
case 1: printf("Adding...\n"); break;
case 2: printf("Deleting...\n"); break;
case 3: printf("Goodbye!\n"); break;
default: printf("Invalid choice!\n");
}
} while (choice != 3);
Loop Control Statements:
break: Immediately terminates the loop and transfers control to the statement following the loop. Used when a certain condition requires early exit from the loop.
continue: Skips the remaining statements in the current iteration and jumps to the next iteration's condition check (for while/do-while) or update expression (for for loops).
Comparison: Use for when the number of iterations is known beforehand.
Use while when the loop depends on a condition that may prevent the first execution.
Use do-while when the loop must execute at least once. All three loops can achieve the
same results, but choosing the right one improves code readability and intent.