B.Tech Even Semester Examination 2023–2024 · Paper Code: ESCS201 · Full Marks: 70
#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 ]
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.
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) \]
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.
#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 ]
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}\).
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)).
#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}\).
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.
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.
#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!
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.
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.
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.
| 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; } |
void func(int *x) { *x = 10; } |
Mathematical Basis: \[ n! = \begin{cases} 1 & \text{if } n = 0 \text{ or } n = 1 \\ n \times (n-1)! & \text{if } n > 1 \end{cases} \]
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. |
| 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. |
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:
(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!
(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.
(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.
(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)\)!
Computers can be systematically categorized based on two fundamental criteria: Operating Data Principles and Size / 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. |
(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.
(b) C Program to Print Fibonacci Series Upto n-th Term [7 Marks]: