Skip to main content

C Programming 202 - 2018

 




Solutions to BCA Examination (May 2018) - C Programming


Section-A: Very Short Answer Questions

  1. Differentiate between string and character array.

    • A string in C is an array of characters terminated by a null character \0. Strings are used to store and manipulate text data, and the standard library provides functions like strlen, strcpy, and strcat to handle strings.
    • A character array is simply a collection of characters. It may or may not have a null character. If it doesn’t, it cannot be considered a string. Character arrays are used for generic storage and manipulation of characters.
  2. What is a generic pointer? How can it be converted to a specific type of pointer?

    • A generic pointer in C is a pointer of type void*. It can point to any data type because it has no associated type information.
    • To convert a generic pointer to a specific type, you use type casting. For example:
      int x = 10;
      void *ptr = &x;
      int *int_ptr = (int*)ptr;
      
  3. What is the output?

    #include <stdio.h>
    int func(int a) {
        int a = 2;
        printf("%d", func(a));
        return 0;
    }
    
    int func(int a) {
        if (a > 1)
            return func(--a) * 10;
        else
            return 0;
    }
    
    • Answer: The code snippet contains a duplicate definition of func and will not compile. However, if you resolve this issue, the recursive function's base case would return 0, leading to 0 as the final output for any input.
  4. Explain the difference between malloc() and calloc() functions.

    • malloc(): Allocates a block of memory of the specified size but does not initialize it. The memory contains garbage values.
    • calloc(): Allocates memory for an array of elements and initializes all bytes to zero. Syntax includes two parameters: the number of elements and their size.
  5. Explain the importance of the #define preprocessor directive.

    • The #define directive is used for defining symbolic constants and macros. It improves code readability, reduces redundancy, and makes maintenance easier. For example:
      #define PI 3.14159
      #define SQUARE(x) ((x) * (x))
      

Section-B: Short Answer Questions

  1. Write a program to sort an array.

    #include <stdio.h>
    
    void sortArray(int arr[], int n) {
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
    
    int main() {
        int arr[] = {5, 2, 9, 1, 5, 6};
        int n = sizeof(arr) / sizeof(arr[0]);
        sortArray(arr, n);
    
        printf("Sorted array: ");
        for (int i = 0; i < n; i++) {
            printf("%d ", arr[i]);
        }
        return 0;
    }
    
  2. Write a C program to find the reverse of each word of a string.

    #include <stdio.h>
    #include <string.h>
    
    void reverseWord(char *start, char *end) {
        while (start < end) {
            char temp = *start;
            *start = *end;
            *end = temp;
            start++;
            end--;
        }
    }
    
    void reverseWords(char str[]) {
        char *start = str, *end = str;
        while (*end) {
            if (*end == ' ' || *(end + 1) == '\0') {
                reverseWord(start, (*end == ' ') ? end - 1 : end);
                start = end + 1;
            }
            end++;
        }
    }
    
    int main() {
        char str[] = "how are you";
        reverseWords(str);
        printf("Reversed words: %s", str);
        return 0;
    }
    
  3. Differentiate between rewind() and fseek(). Can fseek() work as an alternative to rewind()?

    • rewind(): Resets the file position to the beginning of a file.
    • fseek(): Moves the file pointer to a specified position, based on an offset and a reference position.
    • Yes, fseek(fp, 0, SEEK_SET) can work as an alternative to rewind(fp).

Section-C: Detailed Answer Questions

  1. (a) Why are arrays needed? Write a program to calculate the number of duplicate entries in an array.

    • Arrays are needed to store multiple elements of the same data type in contiguous memory locations, enabling efficient indexing and manipulation.
    • Program:
      #include <stdio.h>
      
      void countDuplicates(int arr[], int n) {
          int count = 0;
          for (int i = 0; i < n - 1; i++) {
              for (int j = i + 1; j < n; j++) {
                  if (arr[i] == arr[j]) {
                      count++;
                      break;
                  }
              }
          }
          printf("Number of duplicate entries: %d", count);
      }
      
      int main() {
          int arr[] = {1, 2, 3, 2, 4, 5, 1};
          int n = sizeof(arr) / sizeof(arr[0]);
          countDuplicates(arr, n);
          return 0;
      }
      
  2. (b) With an example, explain how pointers can be used to dynamically allocate space for a two-dimensional array.

    • Explanation: Pointers can dynamically allocate memory for a 2D array by allocating memory row by row using malloc().
    • Example:
      #include <stdio.h>
      #include <stdlib.h>
      
      int main() {
          int rows = 3, cols = 4;
          int **arr = (int**)malloc(rows * sizeof(int*));
      
          for (int i = 0; i < rows; i++) {
              arr[i] = (int*)malloc(cols * sizeof(int));
          }
      
          for (int i = 0; i < rows; i++) {
              for (int j = 0; j < cols; j++) {
                  arr[i][j] = i * cols + j;
                  printf("%d ", arr[i][j]);
              }
              printf("\n");
          }
      
          for (int i = 0; i < rows; i++) {
              free(arr[i]);
          }
          free(arr);
      
          return 0;
      }


    • 11. (a) Create a Structure BANK to Maintain Customer Records

      Below is the solution that implements a structure BANK, which includes features for adding a new customer, updating their balance, and displaying customer details.

      Program to Create and Manage Bank Customer Records

      #include <stdio.h>
      #include <string.h>
      
      // Structure definition for BANK
      struct BANK {
          int cust_id;
          char name[50];
          char account_type[20];
          double balance;
      };
      
      // Function to add a new record
      void add_record(struct BANK *customer, int id, const char *name, const char *type, double balance) {
          customer->cust_id = id;
          strcpy(customer->name, name);
          strcpy(customer->account_type, type);
          customer->balance = balance;
      }
      
      // Function to update balance (deposit/withdraw)
      void update_balance(struct BANK *customer, double amount, int deposit) {
          if (deposit) {
              customer->balance += amount; // Deposit
              printf("Amount Deposited. New Balance: %.2f\n", customer->balance);
          } else if (customer->balance >= amount) {
              customer->balance -= amount; // Withdraw
              printf("Amount Withdrawn. New Balance: %.2f\n", customer->balance);
          } else {
              printf("Insufficient Balance for Withdrawal.\n");
          }
      }
      
      // Function to display customer details
      void display_record(struct BANK customer) {
          printf("\nCustomer ID: %d\n", customer.cust_id);
          printf("Name: %s\n", customer.name);
          printf("Account Type: %s\n", customer.account_type);
          printf("Balance: %.2f\n", customer.balance);
      }
      
      int main() {
          struct BANK customer;
      
          // Add a new customer
          add_record(&customer, 101, "John Doe", "Savings", 5000.00);
          printf("Initial Record:\n");
          display_record(customer);
      
          // Update the balance (Deposit 2000)
          printf("\nDepositing Amount...\n");
          update_balance(&customer, 2000.00, 1);
      
          // Update the balance (Withdraw 1500)
          printf("\nWithdrawing Amount...\n");
          update_balance(&customer, 1500.00, 0);
      
          return 0;
      }
      

      Output for the Above Program:

      Initial Record:
      Customer ID: 101
      Name: John Doe
      Account Type: Savings
      Balance: 5000.00
      
      Depositing Amount...
      Amount Deposited. New Balance: 7000.00
      
      Withdrawing Amount...
      Amount Withdrawn. New Balance: 5500.00
      

      11. (b) Menu-Driven Program for Bank Management

      This program allows a user to interact with multiple customer records in a menu-driven way. Users can add records, deposit/withdraw money, and view all customer records.

      Code for the Menu-Driven Program

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      // Structure definition for BANK
      struct BANK {
          int cust_id;
          char name[50];
          char account_type[20];
          double balance;
      };
      
      // Function prototypes
      void add_record(struct BANK *customers, int *count);
      void deposit_money(struct BANK *customers, int count);
      void withdraw_money(struct BANK *customers, int count);
      void display_all_records(struct BANK *customers, int count);
      
      int main() {
          struct BANK customers[100];
          int count = 0, choice;
      
          while (1) {
              printf("\n--- Bank Management System ---\n");
              printf("1. Add New Record\n");
              printf("2. Deposit Money\n");
              printf("3. Withdraw Money\n");
              printf("4. Display All Records\n");
              printf("5. Exit\n");
              printf("Enter your choice: ");
              scanf("%d", &choice);
      
              switch (choice) {
                  case 1:
                      add_record(customers, &count);
                      break;
                  case 2:
                      deposit_money(customers, count);
                      break;
                  case 3:
                      withdraw_money(customers, count);
                      break;
                  case 4:
                      display_all_records(customers, count);
                      break;
                  case 5:
                      exit(0);
                  default:
                      printf("Invalid Choice! Try Again.\n");
              }
          }
      
          return 0;
      }
      
      // Function to add a new record
      void add_record(struct BANK *customers, int *count) {
          printf("Enter Customer ID: ");
          scanf("%d", &customers[*count].cust_id);
          printf("Enter Name: ");
          scanf(" %[^\n]", customers[*count].name);
          printf("Enter Account Type: ");
          scanf("%s", customers[*count].account_type);
          printf("Enter Initial Balance: ");
          scanf("%lf", &customers[*count].balance);
      
          (*count)++;
          printf("Record Added Successfully!\n");
      }
      
      // Function to deposit money
      void deposit_money(struct BANK *customers, int count) {
          int id, i;
          double amount;
          printf("Enter Customer ID: ");
          scanf("%d", &id);
      
          for (i = 0; i < count; i++) {
              if (customers[i].cust_id == id) {
                  printf("Enter Deposit Amount: ");
                  scanf("%lf", &amount);
                  customers[i].balance += amount;
                  printf("Deposit Successful. Updated Balance: %.2f\n", customers[i].balance);
                  return;
              }
          }
          printf("Customer ID Not Found.\n");
      }
      
      // Function to withdraw money
      void withdraw_money(struct BANK *customers, int count) {
          int id, i;
          double amount;
          printf("Enter Customer ID: ");
          scanf("%d", &id);
      
          for (i = 0; i < count; i++) {
              if (customers[i].cust_id == id) {
                  printf("Enter Withdrawal Amount: ");
                  scanf("%lf", &amount);
                  if (customers[i].balance >= amount) {
                      customers[i].balance -= amount;
                      printf("Withdrawal Successful. Updated Balance: %.2f\n", customers[i].balance);
                  } else {
                      printf("Insufficient Balance.\n");
                  }
                  return;
              }
          }
          printf("Customer ID Not Found.\n");
      }
      
      // Function to display all customer records
      void display_all_records(struct BANK *customers, int count) {
          printf("\n--- Customer Records ---\n");
          for (int i = 0; i < count; i++) {
              printf("ID: %d, Name: %s, Type: %s, Balance: %.2f\n",
                     customers[i].cust_id,
                     customers[i].name,
                     customers[i].account_type,
                     customers[i].balance);
          }
      }
      

      Key Features of the Program:

      1. Add Record: Enables the user to input customer details.
      2. Deposit Money: Allows deposits into a customer's account.
      3. Withdraw Money: Enables withdrawals while checking for sufficient balance.
      4. Display Records: Lists all customer details.

      Output Example for Menu-Driven Program:

      --- Bank Management System ---
      1. Add New Record
      2. Deposit Money
      3. Withdraw Money
      4. Display All Records
      5. Exit
      Enter your choice: 1
      
      Enter Customer ID: 101
      Enter Name: John Doe
      Enter Account Type: Savings
      Enter Initial Balance: 5000
      Record Added Successfully!
      
      Enter your choice: 4
      
      --- Customer Records ---
      ID: 101, Name: John Doe, Type: Savings, Balance: 5000.00
      

      12. Macros in C Programming

      Macros are preprocessor directives in C, which are processed before the compilation stage. They provide a way to define constants, inline functions, or repetitive tasks in a program, improving code readability and maintainability.


      12(a). What is a Macro?

      A macro is a fragment of code that is given a name. Whenever the name is used, it gets replaced by the contents of the macro. Macros are handled by the preprocessor, and they are defined using the #define directive.

      Types of Macros:

      1. Object-like Macro: Used to define constants.
      2. Function-like Macro: Used to define reusable code blocks, mimicking functions.


      Examples of Object-like Macros

      #include <stdio.h>
      
      #define PI 3.14159 // Defining a constant for Pi
      #define MAX 100    // Defining the maximum limit
      
      int main() {
          printf("Value of PI: %.2f\n", PI);
          printf("Maximum Limit: %d\n", MAX);
          return 0;
      }
      

      Output:

      Value of PI: 3.14
      Maximum Limit: 100
      


      Examples of Function-like Macros

      Function-like macros are used to perform small operations without the overhead of a function call. However, they do not check for types or scope, so careful usage is necessary.

      #include <stdio.h>
      
      #define SQUARE(x) ((x) * (x)) // Macro to calculate square of a number
      #define MAXIMUM(a, b) ((a) > (b) ? (a) : (b)) // Macro to find maximum
      
      int main() {
          int num = 5;
          printf("Square of %d: %d\n", num, SQUARE(num));
          printf("Maximum of 5 and 10: %d\n", MAXIMUM(5, 10));
          return 0;
      }
      

      Output:

      Square of 5: 25
      Maximum of 5 and 10: 10
      


      12(b). Difference Between Macro and Function

      Aspect Macro Function
      Definition Preprocessor directive; substituted before compilation. Block of code executed during runtime.
      Execution Inline substitution, no function call overhead. Requires a function call.
      Type Checking No type checking; may cause unexpected behavior. Enforces type checking.
      Debugging Difficult to debug due to direct text substitution. Easier to debug.
      Scope Global; cannot be limited to a specific block or function. Local to where it's defined.


      12(c). Advantages and Disadvantages of Macros

      Advantages:

      1. Improves Readability: Constants like #define PI 3.14 are easier to understand.
      2. No Function Call Overhead: Increases performance for small operations.
      3. Reusability: Macros can replace repetitive code, making programs concise.

      Disadvantages:

      1. No Type Checking: Misuse may lead to unexpected errors.
      2. Complexity in Debugging: Errors in macros are harder to trace.
      3. Code Bloat: Inline expansion may increase program size.


      12(d). Applications of Macros

      1. Defining Constants: Commonly used for values that do not change (e.g., PI, MAX_LIMIT).
      2. Inline Functions: To perform small, repetitive tasks (e.g., SQUARE(x)).
      3. Conditional Compilation: Used for platform-specific code (e.g., #ifdef directives).


      12(e). Example: Conditional Compilation with Macros

      Macros are often used to include or exclude code depending on conditions, making the code portable.

      #include <stdio.h>
      
      #define WINDOWS 1 // 1 for Windows, 0 for Linux
      
      int main() {
          #if WINDOWS
              printf("This code runs on Windows.\n");
          #else
              printf("This code runs on Linux.\n");
          #endif
      
          return 0;
      }
      

      Output (when WINDOWS is 1):

      This code runs on Windows.
      


      12(f). Limitations of Macros

      1. Lack of Scope: Macros cannot have local scope, which can lead to naming conflicts.
      2. No Debugging Information: Preprocessor removes macros before compilation, so debugging tools cannot trace them.
      3. Unintended Side Effects: Improper usage of macros like SQUARE(a + b) may expand incorrectly (((a + b) * (a + b))).


      Complete Example Combining Macro Concepts

      Below is a complete example demonstrating multiple macro functionalities:

      #include <stdio.h>
      
      #define PI 3.14159
      #define AREA_CIRCLE(r) (PI * (r) * (r))
      #define DEBUG 1 // Enable debugging
      
      int main() {
          float radius = 5.0;
      
          #if DEBUG
              printf("Debugging is enabled.\n");
          #endif
      
          printf("Area of Circle with radius %.2f: %.2f\n", radius, AREA_CIRCLE(radius));
      
          return 0;
      }
      

      Output (with DEBUG enabled):

      Debugging is enabled.
      Area of Circle with radius 5.00: 78.54
      




      13. Explain the use of bitwise operators in programming

      Bitwise Operators in C

      Bitwise operators in C perform operations at the binary level. These operators work directly on bits and are commonly used in low-level programming such as embedded systems, cryptography, and memory optimization.


      Types of Bitwise Operators

      1. Bitwise AND (&)

        • Performs a logical AND operation on each bit of two numbers.
        • The result is 1 if both bits are 1; otherwise, it is 0.

        Example:

        int a = 5, b = 3; // Binary: a = 0101, b = 0011
        int result = a & b; // result = 0001 (1 in decimal)
        printf("Bitwise AND: %d\n", result);
        

        Output: Bitwise AND: 1

      2. Bitwise OR (|)

        • Performs a logical OR operation on each bit of two numbers.
        • The result is 1 if either bit is 1.

        Example:

        int a = 5, b = 3; // Binary: a = 0101, b = 0011
        int result = a | b; // result = 0111 (7 in decimal)
        printf("Bitwise OR: %d\n", result);
        

        Output: Bitwise OR: 7

      3. Bitwise XOR (^)

        • Performs an exclusive OR operation on each bit.
        • The result is 1 if the bits are different; otherwise, it is 0.

        Example:

        int a = 5, b = 3; // Binary: a = 0101, b = 0011
        int result = a ^ b; // result = 0110 (6 in decimal)
        printf("Bitwise XOR: %d\n", result);
        

        Output: Bitwise XOR: 6

      4. Bitwise NOT (~)

        • Inverts all bits of a number (1 becomes 0, and 0 becomes 1).
        • Works only on a single operand.

        Example:

        int a = 5; // Binary: a = 0101
        int result = ~a; // result = 1010 (in two's complement: -6 in decimal)
        printf("Bitwise NOT: %d\n", result);
        

        Output: Bitwise NOT: -6

      5. Left Shift (<<)

        • Shifts the bits of a number to the left by a specified number of positions.
        • Each shift doubles the number.

        Example:

        int a = 5; // Binary: a = 0101
        int result = a << 1; // result = 1010 (10 in decimal)
        printf("Left Shift: %d\n", result);
        

        Output: Left Shift: 10

      6. Right Shift (>>)

        • Shifts the bits of a number to the right by a specified number of positions.
        • Each shift halves the number (ignoring the remainder).

        Example:

        int a = 5; // Binary: a = 0101
        int result = a >> 1; // result = 0010 (2 in decimal)
        printf("Right Shift: %d\n", result);
        

        Output: Right Shift: 2


      Program Demonstrating All Bitwise Operators

      Here is a program to demonstrate all the bitwise operators:

      #include <stdio.h>
      
      int main() {
          int a = 5, b = 3; // Binary: a = 0101, b = 0011
      
          // Bitwise AND
          printf("Bitwise AND (a & b): %d\n", a & b);
      
          // Bitwise OR
          printf("Bitwise OR (a | b): %d\n", a | b);
      
          // Bitwise XOR
          printf("Bitwise XOR (a ^ b): %d\n", a ^ b);
      
          // Bitwise NOT
          printf("Bitwise NOT (~a): %d\n", ~a);
      
          // Left Shift
          printf("Left Shift (a << 1): %d\n", a << 1);
      
          // Right Shift
          printf("Right Shift (a >> 1): %d\n", a >> 1);
      
          return 0;
      }
      


      Output

      Bitwise AND (a & b): 1
      Bitwise OR (a | b): 7
      Bitwise XOR (a ^ b): 6
      Bitwise NOT (~a): -6
      Left Shift (a << 1): 10
      Right Shift (a >> 1): 2
      


      Applications of Bitwise Operators

      1. Setting and Clearing Bits

        • To set a bit: Use | (OR) with a mask.
        • To clear a bit: Use & (AND) with the complement of a mask.

        Example: Setting the 2nd bit of a number

        int num = 5; // Binary: 0101
        num = num | (1 << 1); // Set 2nd bit
        printf("After Setting 2nd Bit: %d\n", num); // Output: 7
        

        Example: Clearing the 2nd bit of a number

        int num = 7; // Binary: 0111
        num = num & ~(1 << 1); // Clear 2nd bit
        printf("After Clearing 2nd Bit: %d\n", num); // Output: 5
        
      2. Swapping Two Numbers Without Using a Temporary Variable

        int a = 5, b = 3;
        a = a ^ b; // Step 1
        b = a ^ b; // Step 2
        a = a ^ b; // Step 3
        printf("After Swapping: a = %d, b = %d\n", a, b);
        

        Output: a = 3, b = 5

      3. Efficient Multiplication and Division by Powers of 2

        • Left shift (<<) multiplies a number by 2.
        • Right shift (>>) divides a number by 2.

        Example:

        int num = 4;
        printf("Multiplying by 2: %d\n", num << 1); // Output: 8
        printf("Dividing by 2: %d\n", num >> 1);   // Output: 2
        
      4. Finding Whether a Number is Even or Odd

        • Use the & operator to check the least significant bit.
        int num = 5;
        if (num & 1)
            printf("%d is Odd\n", num);
        else
            printf("%d is Even\n", num);
        

        Output: 5 is Odd


      Conclusion

      Bitwise operators are essential tools in C programming for optimizing code performance. They allow direct manipulation of bits, making them highly efficient in tasks such as:

      • Encryption
      • Data compression
      • Graphics processing
      • Embedded systems development.

      By understanding and applying these operators, developers can write powerful and optimized programs.


Comments

Popular posts from this blog

C PROGRAMING 202 - 2023

1. Write various data types supported in C with examples. Introduction: In C programming, data types specify the type of data that a variable can hold. They are essential for defining variables and managing memory efficiently. Types of Data Types in C: C supports the following primary data types: Basic Data Types : int : Used for integers (whole numbers). Example: int age = 25; float : Used for single-precision floating-point numbers. Example: float height = 5.8; double : Used for double-precision floating-point numbers. Example: double pi = 3.14159; char : Used for characters. Example: char grade = 'A'; Derived Data Types : Array : A collection of elements of the same type. Example: int marks[5] = {90, 85, 78, 92, 88}; Pointer : Stores the address of another variable. Example: int *p; p = &age; Structure : A user-defined data type to group related variables. Example: struct Student { int id; char name[50]; float marks; }; Enumeratio...

Digital Electronics and Computer Organisation.2021

Section A : 1. Prove that NOR and NAND gates are universal gates. Definition of Universal Gates : Universal gates are those which can be used to implement any Boolean function without needing any other gate types. Proof : NAND Gate : A NAND gate can be used to create the basic gates: NOT Gate : Input A A to both inputs of the NAND gate: Output = A ⋅ A = A ′ \text{Output} = A \cdot A = A' AND Gate : Combine NOT gates and NAND gates: ( A ⋅ B ) ′ ⋅ ( A ⋅ B ) ′ = A ⋅ B (A \cdot B)' \cdot (A \cdot B)' = A \cdot B . OR Gate : Using De Morgan's theorem and NOT gates: A ′ ⋅ B ′ = ( A + B ) ′ A' \cdot B' = (A + B)' . NOR Gate : Similarly, NOR gates can be used to create: NOT Gate : Input A A to both inputs of the NOR gate: Output = ( A + A ) ′ = A ′ \text{Output} = (A + A)' = A' OR Gate : Combine two NOT gates and NOR gates: ( A + B ) ′ + ( A + B ) ′ = A + B (A + B)' + (A + B)' = A + B . AND Gate : Using De Morgan...
Answer 1: What is a real-time operating system? A Real-Time Operating System (RTOS) is an operating system that processes data and events within a guaranteed time frame . It is designed to handle real-time tasks where timely execution is crucial. There are two types: Hard Real-Time OS – Strict deadlines must be met (e.g., pacemakers, aircraft systems). Soft Real-Time OS – Deadlines are important but not critical (e.g., video streaming). RTOS is used in embedded  systems , robotics, and industrial control systems. Great! Here's a detailed and unrestricted explanation of hard and soft semaphores : Answer 2: What is a Hard and Soft Semaphore? A semaphore is a synchronization mechanism used in operating systems and concurrent programming to control access to shared resources and avoid issues like race conditions and deadlocks. Semaphores help coordinate multiple processes or threads trying to access critical sections of code or shared data. There are two main types of ...