MAKAUT Solved Paper · UPID : 002008

Programming for Problem Solving

B.Tech Even Semester Examination 2023–2024 · Paper Code: ESCS201 · Full Marks: 70

Group-A: Very Short Answer Type Questions Answer Any 10 · [ 1 x 10 = 10 Marks ]

1. (I) What will be the output of the following C code?
#include <stdio.h>
void main() {
  int a[2][3] = {1, 2, 3, 4, 5};
  int i = 0, j = 0;
  for (i = 0; i < 2; i++)
    for (j = 0; j < 3; j++)
      printf("%d", a[i][j]);
}
[ 1 Mark ]

Console Output 123450

Explanation: In C, when an array is partially initialized (here, a \(2 \times 3\) matrix with 6 elements is initialized with only 5 values: {1, 2, 3, 4, 5}), the compiler automatically fills all remaining uninitialized elements with zero (0).
Memory layout: a[0][0]=1, a[0][1]=2, a[0][2]=3, a[1][0]=4, a[1][1]=5, a[1][2]=0. Printing them sequentially yields 123450.

1. (II) What is the worst case complexity of bubble sort? [ 1 Mark ]

Answer: \(O(n^2)\) (Quadratic Time Complexity).

Explanation: In the worst-case scenario (when the input array is sorted in completely reverse order), Bubble Sort requires \((n-1)\) passes. The total number of comparisons and swaps is: \[ (n-1) + (n-2) + \dots + 2 + 1 = \frac{n(n-1)}{2} = \Theta(n^2) \]

1. (III) What is the default return type of function definition? [ 1 Mark ]

Answer: int (Integer).

Explanation: In traditional C (K&R and ISO C89/C90 standards), if a function is defined or declared without an explicit return type specifier (e.g., myFunc() { ... }), the compiler implicitly assumes the return type to be int. Note that in modern C99/C11 standards, implicit int return is deprecated and causes a compiler warning/error, requiring explicit return types like void or int.

1. (IV) What will be the output of the following C code?
#include<stdio.h>
main() { int n; n=f1(4); printf("%d", n); }
f1(int x) {
  int b;
  if(x==1) return 1;
  else b=x*f1(x-1);
  return b;
}
[ 1 Mark ]

Console Output 24

Explanation: The recursive function f1(x) computes the factorial of integer x.
Call stack trace for f1(4):
f1(4) = 4 * f1(3)
f1(3) = 3 * f1(2)
f1(2) = 2 * f1(1)
f1(1) = 1 (Base case reached!)
Unwinding the stack: \(2 \times 1 = 2 \implies 3 \times 2 = 6 \implies 4 \times 6 = \mathbf{24}\).

1. (V) What is the size of a C structure? [ 1 Mark ]

Answer: The total memory size of a C structure is greater than or equal to the sum of the byte sizes of all its individual members, plus any additional structure padding (slop bytes) added by the compiler for memory alignment.

It can always be precisely determined at compile time using the sizeof() operator on the structure type or variable (e.g., sizeof(struct Student)).

1. (VI) What will be the output?
#include <stdio.h>
int main(){
  int a=3, *b = &a;
  printf("%d", a*b);
}
[ 1 Mark ]

Answer: Compilation Error: invalid operands to binary * (have 'int' and 'int *').

Detailed Explanation:
In the expression a * b, variable a is an integer (int) while b is a pointer to an integer (int*). In C, the multiplication operator * is only defined for arithmetic numeric types; multiplying an integer by a memory address (pointer) is illegal and prohibited by the type system.
Note: If the programmer intended to dereference pointer b using parentheses as a * (*b), the output would be \(3 \times 3 = \mathbf{9}\).

1. (VII) Which language is written in binary codes only? [ 1 Mark ]

Answer: Machine Language (or First-Generation Programming Language / 1GL).

Explanation: Machine language is the lowest-level programming language consisting entirely of binary 0s and 1s (opcodes and operands). It is the only language that is directly understood and executed by the computer's CPU hardware without requiring an assembler, compiler, or interpreter.

1. (VIII) The C-preprocessors are specified with which symbol? [ 1 Mark ]

Answer: The hash / pound / octothorpe symbol: #.

Explanation: Every preprocessor directive in C must start with the # symbol (e.g., #include, #define, #ifdef, #pragma). This symbol instructs the preprocessor compiler phase to execute macro instructions before tokenizing and compiling the standard C syntax.

1. (IX) What will be the output of the following C code? (Assuming we enter value 1 in standard input)
#include <stdio.h>
void main() {
  double ch;
  printf("enter a value between 1 to 2:");
  scanf("%lf", &ch);
  switch (ch) {
    case 1: printf("1"); break;
    case 2: printf("2"); break;
  }
}
[ 1 Mark ]

Answer: Compilation Error: switch quantity not an integer.

Why? According to ISO C specifications, the controlling expression inside a switch(expr) statement MUST have an integral type (such as int, char, short, long) or an enumeration type. Here, ch is declared as a floating-point data type (double). Using float/double in a switch expression is strictly prohibited because floating-point precision issues make exact equality testing unreliable in hardware!

1. (X) What will happen if in a C program you assign a value to an array element whose subscript exceeds the size of array? [ 1 Mark ]

Answer: It results in Undefined Behavior (Buffer Overflow / Memory Corruption).

Explanation: C does not perform runtime array boundary checks (bounds checking). When a programmer writes beyond array limits (e.g., accessing arr[10] in an array declared as int arr[5]), the compiled program will simply calculate the target memory address and overwrite whatever data resides there—which could corrupt adjacent variables, destroy stack frame return addresses (segmentation fault / core dump), or create serious security vulnerabilities.

1. (XI) What is the advantage of selection sort over other sorting techniques? [ 1 Mark ]

Answer: It performs the absolute minimum number of data memory swaps among quadratic sorting algorithms—requiring at most exactly \((n - 1)\) swaps for an array of size \(n\).

Why is this beneficial? In systems where write operations to memory (such as Flash memory, EEPROM, or slow disk storage) are significantly more expensive or slower than read operations, Selection Sort is superior to algorithms like Bubble Sort or Insertion Sort that perform \(O(n^2)\) swaps.

1. (XII) What is the limit for number of functions in a C Program? [ 1 Mark ]

Answer: There is no theoretical or language-specified limit in the ISO/ANSI C standards.

Explanation: A C program can contain as many functions as required. The only practical limitations are imposed by the host system's physical resources—such as available RAM, compiler symbol table memory limits, disk space for the compiled object binary, and operating system architectural constraints.

Group-B: Short Answer Type Questions Answer Any 3 · [ 5 x 3 = 15 Marks ]

2. Write the differences between call by value and call by reference. [ 5 Marks ]

Comparison Parameter Call by Value Call by Reference / Address (via Pointers)
What is Passed? A copy of the actual argument's value is passed into the function's formal parameters. The memory address (reference) of the actual argument is passed using pointer variables.
Effect on Actual Data Modifications made inside the function affect only local stack copies; original caller variables remain unchanged. Modifications inside the function directly alter the original variables in the caller's memory space.
Memory Allocation New memory locations are allocated on the call stack for formal parameters to store copies. No new storage is created for data values; formal pointer parameters simply point to existing memory addresses.
Performance & Overhead Slower and memory-heavy when passing large structures or arrays due to deep copying. Highly efficient \(O(1)\) time and space overhead, passing only a 4-byte or 8-byte pointer regardless of data size.
Syntax Example void func(int x) { x = 10; }
// Called as: func(val);
void func(int *x) { *x = 10; }
// Called as: func(&val);

3. Write a program to compute factorial of a number using recursion. [ 5 Marks ]

Mathematical Basis: \[ n! = \begin{cases} 1 & \text{if } n = 0 \text{ or } n = 1 \\ n \times (n-1)! & \text{if } n > 1 \end{cases} \]

#include <stdio.h> // Recursive function prototype unsigned long long calculateFactorial(int n); int main() { int num; printf("Enter a positive integer: "); if (scanf("%d", &num) != 1 || num < 0) { printf("Error: Please enter a valid non-negative integer.\n"); return 1; } // Call recursive function unsigned long long fact = calculateFactorial(num); printf("Factorial of %d (%d!) = %llu\n", num, num, fact); return 0; } // Recursive factorial definition unsigned long long calculateFactorial(int n) { // Base Case if (n == 0 || n == 1) { return 1; } // Recursive Step return (unsigned long long)n * calculateFactorial(n - 1); }
Sample Output Enter a positive integer: 6 Factorial of 6 (6!) = 720

4. What is the difference between break and continue statement? [ 5 Marks ]

Feature break Statement continue Statement
Core Functionality Terminates the execution of the entire enclosing loop or switch statement immediately. Skips the remaining statements in the current iteration and jumps directly to the loop's next evaluation.
Loop Termination Ends the loop completely; execution resumes at the first statement after the loop body. Does not terminate the loop; it merely aborts the current cycle and proceeds with the next iteration.
Applicability Can be used inside all loop structures (for, while, do-while) AND inside switch statements. Can ONLY be used inside loop structures (for, while, do-while). Illegal in standalone switch.
Use Case Example Exiting a linear search loop as soon as the target item is found (early exit optimization). Skipping processing for negative numbers or invalid records while continuing to process remaining items in a file.

5. Differentiate between Compiler and Interpreter? [ 5 Marks ]

Basis of Comparison Compiler Interpreter
Translation Mechanism Scans and translates the entire high-level source code program into machine code (object binary) in a single batch process before execution. Translates and executes the high-level source code line-by-line or statement-by-statement at runtime.
Execution Speed Execution is extremely fast because pre-compiled machine binaries run directly on CPU without translation overhead. Execution is comparatively slower because translation occurs continuously during runtime for every instruction.
Error Detection Analyzes syntax errors across the entire code and reports all compilation errors together at the end of compilation. Stops translation and execution immediately upon encountering the very first error on a line, making debugging interactive.
Object Code Generation Generates a standalone executable binary file (e.g., .exe or .out) which can run without source code or compiler present. Never generates a persistent object or machine code file; the source code and interpreter must be present every time the app runs.
Representative Languages C, C++, Rust, Go, Fortran. Python, JavaScript, Ruby, PHP, MATLAB.

6. Write a C program to perform addition, subtraction, multiplication and division of two numbers by using switch case. [ 5 Marks ]

#include <stdio.h> int main() { char operator; double num1, num2, result; printf("=== Menu-Driven Calculator ===\n"); printf("Enter an arithmetic operator (+, -, *, /): "); scanf(" %c", &operator); printf("Enter two numeric operands separated by space: "); if (scanf("%lf %lf", &num1, &num2) != 2) { printf("Error: Invalid numeric input!\n"); return 1; } // Switch statement evaluating character operator switch (operator) { case '+': result = num1 + num2; printf("\nResult: %.2f + %.2f = %.2f\n", num1, num2, result); break; case '-': result = num1 - num2; printf("\nResult: %.2f - %.2f = %.2f\n", num1, num2, result); break; case '*': result = num1 * num2; printf("\nResult: %.2f * %.2f = %.2f\n", num1, num2, result); break; case '/': if (num2 == 0.0) { printf("\nError: Division by zero is undefined and illegal!\n"); } else { result = num1 / num2; printf("\nResult: %.2f / %.2f = %.2f\n", num1, num2, result); } break; default: printf("\nError: '%c' is an invalid operator! Please use +, -, *, or /.\n", operator); break; } return 0; }
Sample Execution === Menu-Driven Calculator === Enter an arithmetic operator (+, -, *, /): * Enter two numeric operands separated by space: 14.5 4.0 Result: 14.50 * 4.00 = 58.00
Group-C: Long Answer Type Questions Answer Any 3 · [ 15 x 3 = 45 Marks ]

7. Describe different types of asymptotic notation of complexity analysis of algorithms. [ 15 Marks ]

Introduction to Asymptotic Notations: When analyzing the efficiency of algorithms, we evaluate how the runtime or memory space grows as the input size \(n\) increases toward infinity (\(n \to \infty\)). Asymptotic notations provide mathematical bounds to categorize algorithm performance, stripping away hardware-dependent constants and lower-order terms.

There are 5 fundamental asymptotic notations used in computer science:

  • 1. Big-O Notation (\(O\)) — Asymptotic Upper Bound:
    Big-O defines the absolute worst-case growth rate. It guarantees that an algorithm will never execute slower than a specified curve.
    Formal Definition: \(f(n) = O(g(n))\) if there exist positive constants \(c\) and \(n_0\) such that: \[ 0 \le f(n) \le c \cdot g(n) \quad \forall n \ge n_0 \] Example: For linear search, worst-case runtime is \(O(n)\).
  • 2. Big-Omega Notation (\(\Omega\)) — Asymptotic Lower Bound:
    Big-Omega defines the best-case minimum time required. It guarantees that an algorithm will take at least this much time for large inputs.
    Formal Definition: \(f(n) = \Omega(g(n))\) if there exist positive constants \(c\) and \(n_0\) such that: \[ 0 \le c \cdot g(n) \le f(n) \quad \forall n \ge n_0 \] Example: Any comparison-based sorting algorithm has a lower bound of \(\Omega(n \log n)\).
  • 3. Big-Theta Notation (\(\Theta\)) — Asymptotic Tight Bound:
    Big-Theta provides an exact growth rate bounding the runtime from both above and below within constant factors. It applies when worst-case and best-case complexities match.
    Formal Definition: \(f(n) = \Theta(g(n))\) if there exist positive constants \(c_1, c_2,\) and \(n_0\) such that: \[ 0 \le c_1 \cdot g(n) \le f(n) \le c_2 \cdot g(n) \quad \forall n \ge n_0 \] Example: Merge Sort always takes \(\Theta(n \log n)\) time in all cases.
  • 4. Little-o Notation (\(o\)) — Strict Upper Bound:
    Represents an upper bound that is not asymptotically tight. It implies that \(f(n)\) grows strictly slower than \(g(n)\).
    Formal Definition: \(\lim_{n \to \infty} \frac{f(n)}{g(n)} = 0\). For example, \(2n = o(n^2)\), but \(2n^2 \neq o(n^2)\).
  • 5. Little-omega Notation (\(\omega\)) — Strict Lower Bound:
    Represents a lower bound that is not asymptotically tight. It implies that \(f(n)\) grows strictly faster than \(g(n)\).
    Formal Definition: \(\lim_{n \to \infty} \frac{f(n)}{g(n)} = \infty\). For example, \(n^2 = \omega(n)\).

8. (a) Write a C program to find the maximum and minimum of some values using a function that returns an array.
(b) Write a program in C to print all palindrome numbers in a given range using the function.
[ 7 + 8 = 15 Marks ]

(a) Find Max and Min Using a Function Returning an Array [7 Marks]:

Important Concept: In C, functions cannot return a standard local array directly by value because local arrays are deallocated from stack memory upon function return. To return an array safely, we can either return a pointer to a dynamically allocated array using malloc(), return a pointer to a static array, or wrap the array inside a struct. Below, we demonstrate using a static int[] array returned by pointer!

#include <stdio.h> // Function returning a pointer to a static array holding {min, max} int* findMinMax(const int arr[], int size) { static int result[2]; // static storage persists across function calls! result[0] = arr[0]; // Index 0 stores Minimum result[1] = arr[0]; // Index 1 stores Maximum for (int i = 1; i < size; i++) { if (arr[i] < result[0]) { result[0] = arr[i]; } if (arr[i] > result[1]) { result[1] = arr[i]; } } return result; // Returning base pointer of static array } int main() { int n; printf("Enter number of elements: "); scanf("%d", &n); int data[n]; printf("Enter %d integers:\n", n); for (int i = 0; i < n; i++) { scanf("%d", &data[i]); } // Receive array pointer from function int *minMaxPtr = findMinMax(data, n); printf("\n--- Analysis Result ---\n"); printf("Minimum Value : %d\n", minMaxPtr[0]); printf("Maximum Value : %d\n", minMaxPtr[1]); return 0; }
Sample Output Enter number of elements: 6 Enter 6 integers: 45 12 89 3 67 21 --- Analysis Result --- Minimum Value : 3 Maximum Value : 89

(b) Palindrome Numbers in a Given Range Using Function [8 Marks]:

A numeric palindrome is an integer that remains unchanged when its digits are reversed (e.g., 121, 1331, 404). We implement a function int isPalindrome(int num) which reverses the number algebraically using modulo 10 extraction and division.

#include <stdio.h> // Function returns 1 if num is a palindrome, 0 otherwise int isPalindrome(int num) { if (num < 0) return 0; // Negative numbers are not palindromes int original = num; int reversed = 0; while (num > 0) { int remainder = num % 10; reversed = reversed * 10 + remainder; num /= 10; } return (original == reversed); } int main() { int lower, upper, count = 0; printf("Enter lower bound of range: "); scanf("%d", &lower); printf("Enter upper bound of range: "); scanf("%d", &upper); printf("\nPalindrome numbers between %d and %d:\n", lower, upper); for (int i = lower; i <= upper; i++) { if (isPalindrome(i)) { printf("%d ", i); count++; if (count % 10 == 0) printf("\n"); } } printf("\n\nTotal palindrome numbers found: %d\n", count); return 0; }
Sample Execution Enter lower bound of range: 100 Enter upper bound of range: 200 Palindrome numbers between 100 and 200: 101 111 121 131 141 151 161 171 181 191 Total palindrome numbers found: 10

9. (a) Write an algorithm to sort an array using the Merge sort algorithm.
(b) Calculate the time complexity of Merge sort.
[ 10 + 5 = 15 Marks ]

(a) Merge Sort Algorithm (Divide and Conquer) [10 Marks]:

Merge Sort splits the unsorted array into two halves recursively until each sub-array contains only 1 element (which is inherently sorted), then merges the sorted halves back together in linear time.

Algorithm MERGE-SORT(ARR, left, right):
1. IF left < right THEN:
2.     mid = floor((left + right) / 2)       // Step 1: Divide
3.     MERGE-SORT(ARR, left, mid)           // Step 2: Conquer left half
4.     MERGE-SORT(ARR, mid + 1, right)      // Step 3: Conquer right half
5.     MERGE(ARR, left, mid, right)         // Step 4: Combine

Algorithm MERGE(ARR, left, mid, right):
1. Create temporary arrays L[] of size (mid - left + 1) and R[] of size (right - mid)
2. Copy data to temporary arrays L[] and R[]
3. Initialize pointers: i = 0 (for L), j = 0 (for R), k = left (for merged ARR)
4. WHILE i < size(L) AND j < size(R) DO:
5.     IF L[i] <= R[j] THEN ARR[k] = L[i], increment i
6.     ELSE ARR[k] = R[j], increment j
7.     increment k
8. Copy remaining elements of L[] (if any) to ARR[]
9. Copy remaining elements of R[] (if any) to ARR[]

(b) Time Complexity Calculation of Merge Sort [5 Marks]:

Let \(T(n)\) be the time taken by Merge Sort to sort an array of \(n\) elements.
• The divide step takes constant time: \(\Theta(1)\).
• The recursion solves two sub-problems of size \(n/2\), taking \(2T(n/2)\) time.
• The MERGE procedure combines two sorted halves of total size \(n\) in linear time: \(\Theta(n)\).

Thus, we formulate the recurrence relation: \[ T(n) = 2T\left(\frac{n}{2}\right) + c \cdot n \]

Solving using Master Theorem:
Comparing \(T(n) = aT(n/b) + f(n)\) with \(a = 2, b = 2, f(n) = \Theta(n^1)\):
We compute \(n^{\log_b a} = n^{\log_2 2} = n^1 = n\).
Since \(f(n) = \Theta(n^{\log_b a})\), this falls directly into Case 2 of Master Theorem.
Multiplying by \(\log n\) yields: \[ T(n) = \Theta(n \log_2 n) \]

Conclusion: The Best-case, Average-case, and Worst-case time complexity of Merge Sort are all identically \(\Theta(n \log n)\)!

10. What are the different types of Computer? [ 15 Marks ]

Computers can be systematically categorized based on two fundamental criteria: Operating Data Principles and Size / Processing Power.

A. Classification Based on Operating Principles (Data Handling)
  • 1. Analog Computers: Operate on continuous physical variables (such as voltage, pressure, temperature, or fluid flow) rather than discrete numbers. They excel at real-time physical simulations. Examples: Speedometers, thermometers, analog flight simulators.
  • 2. Digital Computers: Process information represented as discrete binary numbers (0s and 1s). They perform high-speed logical and arithmetic operations with absolute accuracy. Examples: Desktop PCs, laptops, smartphones, digital servers.
  • 3. Hybrid Computers: Combine the desirable features of both analog (real-time continuous measurement speed) and digital computers (precision and data storage). Examples: ICU patient monitoring systems in hospitals, radar defense systems.
B. Classification Based on Size, Speed, and Processing Power
Computer Type Key Characteristics & Capabilities Real-World Examples
Supercomputers The fastest and most expensive computers on Earth. Capable of processing quadrillions of floating-point calculations per second (petaflops) using thousands of parallel CPUs/GPUs. Weather forecasting, quantum physics modeling, climate research (e.g., PARAM Siddhi, IBM Summit, Fugaku).
Mainframes Massive, enterprise-grade systems designed for extreme reliability, high data throughput, and handling simultaneous I/O transactions for thousands of concurrent users. Bank ATM transaction processing, airline ticketing reservation databases, government census computing.
Minicomputers / Midrange Servers Mid-sized multi-user servers ranking between microcomputers and mainframes. Capable of supporting hundreds of users simultaneously. Departmental databases, university campus servers, factory manufacturing controllers.
Microcomputers (Personal Computers) General-purpose single-user systems built around a microprocessor chip (CPU on a single integrated circuit). Compact and cost-effective. Desktop PCs, laptops, tablets, smartphones, gaming consoles.
Workstations High-performance personal computers optimized for intensive graphics, scientific computing, engineering CAD, and 3D rendering. Engineering CAD/CAM workstations, video editing rigs, medical imaging analysis terminals.
Embedded Computers Specialized microcontrollers dedicated to performing a single specific control task within a larger mechanical or electrical system. Automotive engine control units (ECU), microwave oven timers, smart washing machines, IoT sensors.

11. (a) Write a program in C language to print the factorial of a number.
(b) Write a C program to print the Fibonacci series upto nth term.
[ 8 + 7 = 15 Marks ]

(a) C Program for Factorial of a Number (Iterative Approach) [8 Marks]:

We use an iterative loop multiplying integers from 1 up to \(n\). To handle large factorial values without overflow, we declare the accumulator as unsigned long long.

#include <stdio.h> int main() { int n, i; unsigned long long factorial = 1; printf("Enter a positive integer to compute factorial: "); if (scanf("%d", &n) != 1 || n < 0) { printf("Error: Factorial is not defined for negative numbers!\n"); return 1; } for (i = 1; i <= n; ++i) { factorial *= i; } printf("Factorial of %d = %llu\n", n, factorial); return 0; }
Sample Execution Enter a positive integer to compute factorial: 7 Factorial of 7 = 5040

(b) C Program to Print Fibonacci Series Upto n-th Term [7 Marks]:

#include <stdio.h> int main() { int terms, count; unsigned long long first = 0, second = 1, next; printf("Enter the number of Fibonacci terms to display: "); if (scanf("%d", &terms) != 1 || terms <= 0) { printf("Please enter a positive integer greater than 0.\n"); return 1; } printf("\nFirst %d terms of Fibonacci Sequence:\n", terms); for (count = 1; count <= terms; count++) { if (count == 1) { printf("%llu", first); continue; } if (count == 2) { printf(", %llu", second); continue; } next = first + second; printf(", %llu", next); first = second; second = next; } printf("\n"); return 0; }
Sample Output Enter the number of Fibonacci terms to display: 12 First 12 terms of Fibonacci Sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89