Problem-solving-through-Programming-In-C-2-2

C Programming for Problem Solving: A Comprehensive Guide

March 30, 2024 Off By admin
Shares

Table of Contents

Strings

Character array

A character array is a sequence of characters stored in consecutive memory locations. In programming, character arrays are often used to store strings, which are sequences of characters terminated by a null character (‘\0’). Character arrays can be manipulated using various string functions in languages like C, C++, and Python. For example, in C, a character array declaration and initialization might look like this:

c
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

In this example, str is a character array containing the string “Hello”.

Lab Exercise: Write a program to input a string from the user and display it

Here’s a simple C program that prompts the user to input a string and then displays the input string:

c
#include <stdio.h>

int main() {
char str[100];

// Input string from user
printf("Enter a string: ");
scanf("%s", str);

// Display the input string
printf("You entered: %s\n", str);

return 0;
}

In this program, we use scanf with the %s format specifier to read a string from the user. The input string is stored in the str character array. Finally, we use printf to display the input string back to the user.

Reading string from the standard input device

To read a string from the standard input device (typically the keyboard) in C, you can use the fgets function. fgets reads characters from the input stream (stdin) and stores them as a C string into the specified array.

Here’s an example program that reads a string from the user using fgets:

c
#include <stdio.h>

int main() {
char str[100];

printf("Enter a string: ");
fgets(str, sizeof(str), stdin);

// Replace newline character with null terminator
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == '\n') {
str[i] = '\0';
break;
}
}

printf("You entered: %s\n", str);

return 0;
}

In this program, fgets reads up to sizeof(str) characters from stdin (including the newline character) and stores them in the str array. We then loop through the str array to find the newline character (\n) and replace it with the null terminator (\0) to ensure that the string ends correctly. Finally, we print the string back to the user.

Lab Exercise: Write a program to read a string from the user and calculate its length

Here’s a C program that reads a string from the user and calculates its length:

c
#include <stdio.h>

int main() {
char str[100];
int length = 0;

// Input string from user
printf("Enter a string: ");
scanf("%[^\n]%*c", str); // Read until newline, %[^\n] is the format specifier

// Calculate length of the string
while (str[length] != '\0') {
length++;
}

// Display the length of the string
printf("Length of the string: %d\n", length);

return 0;
}

In this program, we use scanf with the %[^\n] format specifier to read a string from the user until a newline character is encountered. This format specifier reads all characters except newline (\n). The *c is used to consume the newline character.

Then, we calculate the length of the string by iterating through the characters in the array until we encounter the null terminator (\0). Finally, we display the length of the string to the user.

Displaying strings on the standard output device

Displaying strings on the standard output device (typically the console) can be done using the printf function in C. Here’s a simple example that demonstrates this:

c
#include <stdio.h>

int main() {
char str[] = "Hello, World!";

// Display the string
printf("%s\n", str);

return 0;
}

In this example, the %s format specifier is used in printf to display the string str. The \n is used to add a newline character after the string, so the output appears on a new line.

Lab Exercise: Write a program to display a string in reverse order

Here’s a C program that reads a string from the user and displays it in reverse order:

c
#include <stdio.h>
#include <string.h>

int main() {
char str[100];

// Input string from user
printf("Enter a string: ");
fgets(str, sizeof(str), stdin);

// Remove newline character if present
if (str[strlen(str) - 1] == '\n') {
str[strlen(str) - 1] = '\0';
}

// Display the string in reverse order
printf("Reversed string: ");
for (int i = strlen(str) - 1; i >= 0; i--) {
printf("%c", str[i]);
}
printf("\n");

return 0;
}

This program reads a string from the user using fgets and then uses a loop to iterate through the string in reverse order, printing each character one by one.

Importance of terminating a string

Terminating a string properly is important in C and other programming languages because it tells the program where the string ends. In C, strings are represented as arrays of characters, terminated by a null character ('\0'). This null character marks the end of the string and is essential for string manipulation functions to work correctly. Here are a few reasons why terminating a string is important:

  1. String Length: Without a null terminator, there is no way to know the length of a string. Functions that work with strings, such as strlen (which calculates the length of a string), rely on the null terminator to determine the end of the string.
  2. String Manipulation: Functions like strcpy (string copy), strcat (string concatenation), and strcmp (string comparison) all require null-terminated strings to work correctly. These functions assume that the strings end with a null character.
  3. Printing Strings: Functions like printf use the null terminator to determine when to stop printing characters from a string. Without a null terminator, printf would continue reading memory beyond the end of the string, leading to undefined behavior.
  4. Safety: Properly terminated strings are safer to work with, as they prevent buffer overflows. If a string is not null-terminated, functions that expect null-terminated strings could read or write memory beyond the intended boundaries of the string, leading to unpredictable behavior and potential security vulnerabilities.

Overall, terminating a string correctly with a null character is a fundamental aspect of working with strings in C and ensures that string operations are performed safely and correctly.

Lab Exercise: Write a program to count the number of vowels in a given string

Here’s a C program that counts the number of vowels in a given string:

c
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int count_vowels(const char *str) {
int count = 0;
for (int i = 0; str[i] != '\0'; i++) {
char ch = tolower(str[i]);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
count++;
}
}
return count;
}

int main() {
char str[100];

// Input string from user
printf("Enter a string: ");
fgets(str, sizeof(str), stdin);

// Remove newline character if present
if (str[strlen(str) - 1] == '\n') {
str[strlen(str) - 1] = '\0';
}

// Count the number of vowels
int vowel_count = count_vowels(str);

// Display the result
printf("Number of vowels: %d\n", vowel_count);

return 0;
}

This program defines a function count_vowels that takes a string as input and counts the number of vowels (both uppercase and lowercase) in the string. It then uses this function to count the vowels in a string input by the user and displays the result.

Standard string library functions

The standard C library provides several functions for working with strings. Some of the most commonly used string functions include:

  1. strlen: Calculates the length of a string.
    c
    size_t strlen(const char *str);
  2. strcpy: Copies a string.
    c
    char *strcpy(char *dest, const char *src);
  3. strcat: Concatenates two strings.
    c
    char *strcat(char *dest, const char *src);
  4. strcmp: Compares two strings.
    c
    int strcmp(const char *str1, const char *str2);
  5. strchr: Finds the first occurrence of a character in a string.
    c
    char *strchr(const char *str, int c);
  6. strstr: Finds the first occurrence of a substring in a string.
    c
    char *strstr(const char *haystack, const char *needle);
  7. strtok: Splits a string into tokens based on a delimiter.
    c
    char *strtok(char *str, const char *delim);
  8. sprintf: Formats a string into a buffer.
    c
    int sprintf(char *str, const char *format, ...);
  9. sscanf: Reads formatted input from a string.
    c
    int sscanf(const char *str, const char *format, ...);

These functions provide basic string manipulation and are part of the standard C library (<string.h> header). Note that some functions, like strcpy and strcat, do not perform bounds checking, so care should be taken to ensure that the destination buffer is large enough to hold the result.

Lab Exercise: Write a program to compare two strings without using the strcmp() function

Here’s a C program that compares two strings without using the strcmp function:

c
#include <stdio.h>

int compare_strings(const char *str1, const char *str2) {
while (*str1 && *str2 && (*str1 == *str2)) {
str1++;
str2++;
}

if (*str1 == '\0' && *str2 == '\0') {
return 0; // Both strings are equal
} else {
return (*str1 - *str2); // Difference in ASCII values
}
}

int main() {
char str1[100], str2[100];

// Input strings from user
printf("Enter first string: ");
scanf("%s", str1);

printf("Enter second string: ");
scanf("%s", str2);

// Compare the strings
int result = compare_strings(str1, str2);

// Display the result
if (result == 0) {
printf("The strings are equal.\n");
} else if (result < 0) {
printf("First string is less than second string.\n");
} else {
printf("First string is greater than second string.\n");
}

return 0;
}

In this program, the compare_strings function compares two strings character by character using pointers. It returns 0 if the strings are equal, a negative value if the first string is less than the second string, and a positive value if the first string is greater than the second string, based on ASCII values.

Pointers

Declaration, Initialization

In programming, the terms “declaration” and “initialization” are often used in the context of variables. Here’s a brief explanation of each:

  1. Declaration: Declaring a variable means defining its type and name so that the compiler knows how much memory to allocate for it. A declaration typically looks like this:
    c
    int x;

    This declares a variable x of type int. The variable x is not yet initialized and may contain garbage value if used without initialization.

  2. Initialization: Initialization is the process of assigning an initial value to a variable at the time of declaration or later in the program. For example:
    c
    int x = 5;

    Here, x is declared and initialized with the value 5. Initialization ensures that the variable has a known value before it is used in the program.

It’s important to note that some programming languages require variables to be initialized at the time of declaration, while others allow variables to be declared first and then initialized later.

Lab Exercise: Write a program to swap two numbers using pointers

Here’s a C program that swaps two numbers using pointers:

c
#include <stdio.h>

void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}

int main() {
int num1, num2;

// Input numbers from user
printf("Enter first number: ");
scanf("%d", &num1);

printf("Enter second number: ");
scanf("%d", &num2);

// Display the numbers before swapping
printf("Before swapping: num1 = %d, num2 = %d\n", num1, num2);

// Swap the numbers
swap(&num1, &num2);

// Display the numbers after swapping
printf("After swapping: num1 = %d, num2 = %d\n", num1, num2);

return 0;
}

In this program, the swap function takes two integer pointers as arguments and swaps the values they point to. The main function inputs two numbers from the user, displays them, calls the swap function to swap them using pointers, and then displays the numbers again to show the result of the swap.

Multiple indirection

Multiple indirection, also known as pointer to a pointer or double pointer, is a concept in C programming where a pointer points to another pointer, which in turn points to the actual data or variable. This allows for indirect access to a value through multiple levels of pointers.

Here’s a simple example to illustrate multiple indirection:

c
#include <stdio.h>

int main() {
int value = 42;
int *ptr = &value; // Pointer to an integer
int **ptr_to_ptr = &ptr; // Pointer to a pointer to an integer

// Accessing the value using double indirection
printf("Value of value: %d\n", **ptr_to_ptr);

return 0;
}

In this example, ptr is a pointer to an integer, and ptr_to_ptr is a pointer to a pointer to an integer. By using **ptr_to_ptr, we can access the value of value indirectly through ptr_to_ptr.

Multiple indirection is commonly used in situations where functions need to modify a pointer (such as when allocating memory) or when working with arrays of pointers.

Lab Exercise: Write a program to find the largest element in an array using pointers

Here’s a C program that finds the largest element in an array using pointers:

c
#include <stdio.h>

int find_largest(int *arr, int size) {
// Initialize max to the first element of the array
int max = *arr;

// Iterate through the array elements
for (int i = 1; i < size; i++) {
// Update max if the current element is greater
if (*(arr + i) > max) {
max = *(arr + i);
}
}

return max;
}

int main() {
int arr[] = {10, 5, 20, 8, 15};
int size = sizeof(arr) / sizeof(arr[0]);

// Find the largest element in the array
int largest = find_largest(arr, size);

// Display the largest element
printf("The largest element in the array is: %d\n", largest);

return 0;
}

In this program, the find_largest function takes an integer array and its size as input. It uses pointer arithmetic to iterate through the array elements and find the largest element. The main function initializes an integer array, calls find_largest to find the largest element, and then displays the result.

Pointer arithmetic

Pointer arithmetic is a feature in C (and C++) that allows you to perform arithmetic operations on pointers. When you perform arithmetic on a pointer, the compiler adjusts the pointer’s value based on the size of the data type it points to. This allows you to navigate through arrays and access individual elements efficiently.

Here’s a quick overview of pointer arithmetic operations:

  1. Increment: When you increment a pointer, it points to the next element of the same data type. For example:
    c
    int arr[] = {10, 20, 30, 40};
    int *ptr = arr; // ptr points to the first element of arr
    ptr++; // ptr now points to the second element of arr
  2. Decrement: Similarly, decrementing a pointer moves it to the previous element of the same data type.
    c
    ptr--; // ptr now points to the first element of arr again
  3. Addition: You can add an integer value to a pointer to move it forward by that many elements.
    c
    ptr = arr + 2; // ptr now points to the third element of arr
  4. Subtraction: Subtracting an integer value from a pointer moves it backward by that many elements.
    c
    ptr = ptr - 1; // ptr now points to the second element of arr
  5. Difference: You can find the difference between two pointers to determine the number of elements between them.
    c
    int diff = ptr2 - ptr1; // Number of elements between ptr1 and ptr2

Pointer arithmetic is particularly useful when working with arrays, as it allows you to traverse the array efficiently without needing to manually calculate the memory offsets. However, it’s important to be careful when performing pointer arithmetic to avoid accessing memory outside the bounds of an array, as this can lead to undefined behavior.

Lab Exercise: Write a program to concatenate two strings using pointers

Here’s a C program that concatenates two strings using pointers:

c
#include <stdio.h>

void concat_strings(char *dest, const char *src) {
// Move dest pointer to the end of the string
while (*dest) {
dest++;
}

// Copy src to dest
while (*src) {
*dest = *src;
dest++;
src++;
}

// Add null terminator to the concatenated string
*dest = '\0';
}

int main() {
char str1[100], str2[50];

// Input strings from user
printf("Enter the first string: ");
scanf("%s", str1);

printf("Enter the second string: ");
scanf("%s", str2);

// Concatenate the strings
concat_strings(str1, str2);

// Display the concatenated string
printf("Concatenated string: %s\n", str1);

return 0;
}

In this program, the concat_strings function takes two pointers (dest and src) as arguments. It first moves the dest pointer to the end of the string pointed to by dest. Then, it copies the string pointed to by src to the location pointed to by dest, and finally adds a null terminator to the concatenated string. The main function inputs two strings from the user, calls concat_strings to concatenate them, and then displays the concatenated string.

Relationship between arrays and pointers

In C, there is a close relationship between arrays and pointers, which can sometimes lead to confusion. Here are some key points to understand the relationship between arrays and pointers:

  1. Array Name as a Pointer: In most contexts, an array name behaves like a pointer to the first element of the array. For example:
    c
    int arr[5] = {1, 2, 3, 4, 5};
    int *ptr = arr; // 'arr' decays to a pointer to the first element
  2. Pointer Arithmetic: You can use pointer arithmetic with arrays. Adding an integer to an array name or a pointer to an array element moves the pointer to the corresponding element:
    c
    int *ptr = arr; // Points to the first element of arr
    ptr++; // Now points to the second element
  3. Array Indexing: Array indexing is a shorthand notation for pointer arithmetic. arr[i] is equivalent to *(arr + i):
    c
    int x = arr[2]; // Equivalent to *(arr + 2)
  4. Function Arguments: When you pass an array to a function, you are actually passing a pointer to the first element of the array. The function can then access and modify the original array:
    c
    void modifyArray(int arr[]) {
    arr[0] = 100;
    }
  5. Sizeof Operator: When you use the sizeof operator on an array, it gives you the size of the whole array in bytes. However, when used on a pointer, it gives you the size of the pointer:
    c
    int arr[5];
    int *ptr = arr;
    sizeof(arr); // Gives the size of the whole array (5 * sizeof(int))
    sizeof(ptr); // Gives the size of the pointer (sizeof(int*))

Understanding these relationships is crucial for writing correct and efficient C programs. However, it’s important to note that arrays and pointers are not the same thing, even though they are closely related.

Lab Exercise: Write a program to reverse an array using pointers

Here’s a C program that reverses an array using pointers:

c
#include <stdio.h>

void reverse_array(int *arr, int size) {
int *start = arr;
int *end = arr + size - 1;

while (start < end) {
// Swap elements pointed to by start and end
int temp = *start;
*start = *end;
*end = temp;

// Move start and end pointers towards the center
start++;
end--;
}
}

int main() {
int arr[] = {1, 2, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);

// Display the array before reversing
printf("Array before reversing:\n");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

// Reverse the array
reverse_array(arr, size);

// Display the array after reversing
printf("Array after reversing:\n");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

return 0;
}

In this program, the reverse_array function takes an integer array and its size as input. It uses two pointers (start and end) to traverse the array from both ends towards the center, swapping the elements pointed to by start and end in each iteration. The main function initializes an integer array, displays it before reversing, calls reverse_array to reverse it, and then displays it again after reversing.

Scaling up: array of arrays, array of pointers, pointer to a pointer, pointer to an array

To scale up the understanding of arrays and pointers, let’s explore the concepts of array of arrays, array of pointers, pointer to a pointer, and pointer to an array in C.

  1. Array of Arrays: An array of arrays is a two-dimensional array, where each element of the array is itself an array. For example:
    c
    int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
    };

    Here, matrix is a 3×3 array, and matrix[0] refers to the first row of the matrix.

  2. Array of Pointers: An array of pointers is an array where each element is a pointer to another data type. For example:
    c
    int *ptr_array[5]; // Array of 5 integer pointers

    Here, ptr_array is an array of 5 integer pointers.

  3. Pointer to a Pointer (Double Pointer): A pointer to a pointer is a pointer that points to another pointer. It is used for multiple levels of indirection. For example:
    c
    int value = 10;
    int *ptr = &value;
    int **ptr_to_ptr = &ptr; // Pointer to a pointer

    Here, ptr_to_ptr is a pointer to ptr.

  4. Pointer to an Array: A pointer to an array is a pointer that points to the first element of an array. For example:
    c
    int arr[5] = {1, 2, 3, 4, 5};
    int (*ptr_to_arr)[5] = &arr; // Pointer to an array of 5 integers

    Here, ptr_to_arr is a pointer to arr.

Understanding these concepts is important for working with more complex data structures and for efficiently managing memory in C programs.

Lab Exercise: Write a program to sort an array of strings using pointers

Here’s a C program that sorts an array of strings using pointers:

c
#include <stdio.h>
#include <string.h>

#define MAX_LENGTH 100
#define MAX_WORDS 5

void sort_strings(char *strings[], int size) {
char *temp;
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (strcmp(strings[i], strings[j]) > 0) {
// Swap strings[i] and strings[j]
temp = strings[i];
strings[i] = strings[j];
strings[j] = temp;
}
}
}
}

int main() {
char *words[MAX_WORDS];
char input[MAX_LENGTH];

// Input strings from user
for (int i = 0; i < MAX_WORDS; i++) {
printf("Enter a string: ");
fgets(input, sizeof(input), stdin);

// Remove newline character if present
if (input[strlen(input) - 1] == '\n') {
input[strlen(input) - 1] = '\0';
}

// Allocate memory for the string and copy it
words[i] = strdup(input);
}

// Sort the array of strings
sort_strings(words, MAX_WORDS);

// Display the sorted array of strings
printf("\nSorted array of strings:\n");
for (int i = 0; i < MAX_WORDS; i++) {
printf("%s\n", words[i]);
// Free memory allocated by strdup
free(words[i]);
}

return 0;
}

In this program, we first define a function sort_strings that uses a simple bubble sort algorithm to sort an array of strings. The main function declares an array of string pointers words and uses a loop to input strings from the user, allocating memory for each string using strdup. After sorting the array of strings using sort_strings, the program displays the sorted array and frees the memory allocated for each string.

Dynamic memory allocation functions

In C, dynamic memory allocation is done using functions from the stdlib.h header, primarily malloc, calloc, realloc, and free. Here’s a brief overview of these functions:

  1. malloc: Allocates a block of memory of a specified size and returns a pointer to the beginning of the block.
    c
    void *malloc(size_t size);

    Example:

    c
    int *ptr = (int *)malloc(5 * sizeof(int));
  2. calloc: Allocates a block of memory for an array of elements, initializes all bytes to zero, and returns a pointer to the beginning of the block.
    c
    void *calloc(size_t num, size_t size);

    Example:

    c
    int *ptr = (int *)calloc(5, sizeof(int));
  3. realloc: Changes the size of the memory block pointed to by a pointer, possibly moving it to a new location. Returns a pointer to the new block of memory, which may be the same as the old block if it was resized in place.
    c
    void *realloc(void *ptr, size_t size);

    Example:

    c
    ptr = (int *)realloc(ptr, 10 * sizeof(int));
  4. free: Frees a block of memory previously allocated with malloc, calloc, or realloc.
    c
    void free(void *ptr);

    Example:

    c
    free(ptr);

It’s important to check the return value of malloc, calloc, and realloc to ensure that the memory allocation was successful. If these functions return NULL, it means that the allocation failed, and you should handle this error condition appropriately. Also, remember to free dynamically allocated memory using free when it is no longer needed to avoid memory leaks.

Lab Exercise: Write a program to dynamically allocate memory for an integer array and initialize its elements

Here’s a C program that dynamically allocates memory for an integer array and initializes its elements:

c
#include <stdio.h>
#include <stdlib.h>

int main() {
int size;

// Input the size of the array from the user
printf("Enter the size of the array: ");
scanf("%d", &size);

// Dynamically allocate memory for the array
int *arr = (int *)malloc(size * sizeof(int));

// Check if memory allocation was successful
if (arr == NULL) {
printf("Memory allocation failed. Exiting...\n");
return 1;
}

// Initialize the elements of the array
for (int i = 0; i < size; i++) {
arr[i] = i * 10; // Initialize each element with a multiple of 10
}

// Display the initialized array
printf("Initialized array:\n");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

// Free the dynamically allocated memory
free(arr);

return 0;
}

In this program, the user inputs the size of the array, and memory is dynamically allocated for the array using malloc. Each element of the array is then initialized with a multiple of 10. Finally, the program displays the initialized array and frees the dynamically allocated memory to avoid memory leaks.

Structures

Defining a structure

In C, a structure is a user-defined data type that allows you to group together related data items. Here’s how you can define a structure:

c
#include <stdio.h>

// Define a structure named 'Student' with three members: 'name', 'roll', and 'marks'
struct Student {
char name[50];
int roll;
float marks;
};

int main() {
// Declare a variable 'student1' of type 'Student'
struct Student student1;

// Initialize the members of 'student1'
printf("Enter student name: ");
scanf("%s", student1.name);

printf("Enter student roll number: ");
scanf("%d", &student1.roll);

printf("Enter student marks: ");
scanf("%f", &student1.marks);

// Display the information of 'student1'
printf("\nStudent Information:\n");
printf("Name: %s\n", student1.name);
printf("Roll Number: %d\n", student1.roll);
printf("Marks: %.2f\n", student1.marks);

return 0;
}

In this program, we define a structure Student with three members: name (a character array), roll (an integer), and marks (a float). We then declare a variable student1 of type Student and use it to store and display information about a student. Structures are often used to represent complex data in a more organized manner.

Lab Exercise: Write a program to define a structure for a student record with name, roll number, and marks in three subjects

Here’s a C program that defines a structure for a student record with name, roll number, and marks in three subjects:

c
#include <stdio.h>

// Define a structure named 'Student' with four members: 'name', 'roll', 'marks1', 'marks2', 'marks3'
struct Student {
char name[50];
int roll;
float marks1, marks2, marks3;
};

int main() {
// Declare a variable 'student1' of type 'Student'
struct Student student1;

// Initialize the members of 'student1'
printf("Enter student name: ");
scanf("%s", student1.name);

printf("Enter student roll number: ");
scanf("%d", &student1.roll);

printf("Enter marks in three subjects: ");
scanf("%f %f %f", &student1.marks1, &student1.marks2, &student1.marks3);

// Display the information of 'student1'
printf("\nStudent Information:\n");
printf("Name: %s\n", student1.name);
printf("Roll Number: %d\n", student1.roll);
printf("Marks in Subject 1: %.2f\n", student1.marks1);
printf("Marks in Subject 2: %.2f\n", student1.marks2);
printf("Marks in Subject 3: %.2f\n", student1.marks3);

return 0;
}

In this program, the structure Student has four members: name (a character array), roll (an integer), and marks1, marks2, marks3 (floats for marks in three subjects). The program inputs the student’s name, roll number, and marks in three subjects, and then displays this information.

Declaring structure variable

To declare a variable of a structure type in C, you use the struct keyword followed by the structure name and the variable name. Here’s an example:

c
#include <stdio.h>

// Define a structure named 'Person' with two members: 'name' and 'age'
struct Person {
char name[50];
int age;
};

int main() {
// Declare a variable 'person1' of type 'struct Person'
struct Person person1;

// Initialize the members of 'person1'
printf("Enter person's name: ");
scanf("%s", person1.name);

printf("Enter person's age: ");
scanf("%d", &person1.age);

// Display the information of 'person1'
printf("\nPerson Information:\n");
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);

return 0;
}

In this program, we define a structure Person with two members: name (a character array) and age (an integer). We then declare a variable person1 of type struct Person and use it to store and display information about a person.

Lab Exercise: Write a program to declare and initialize a structure variable

Here’s a C program that declares and initializes a structure variable:

c
#include <stdio.h>

// Define a structure named 'Point' with two members: 'x' and 'y'
struct Point {
int x;
int y;
};

int main() {
// Declare and initialize a variable 'point1' of type 'struct Point'
struct Point point1 = {10, 20};

// Display the values of 'point1'
printf("Point coordinates: (%d, %d)\n", point1.x, point1.y);

return 0;
}

In this program, we define a structure Point with two members: x and y. We then declare and initialize a variable point1 of type struct Point with the values {10, 20}. Finally, we display the coordinates of point1.

Operations on structures

In C, you can perform various operations on structures, such as initializing structures, accessing structure members, passing structures to functions, and returning structures from functions. Here’s a brief overview of these operations:

  1. Initializing Structures: You can initialize a structure at the time of declaration or later using the dot (.) operator. For example:
    c
    struct Point {
    int x;
    int y;
    };

    struct Point p1 = {10, 20}; // Initializing at declaration
    struct Point p2;
    p2.x = 30; // Initializing later
    p2.y = 40;

  2. Accessing Structure Members: You can access structure members using the dot (.) operator. For example:
    c
    printf("p1.x = %d, p1.y = %d\n", p1.x, p1.y);
  3. Passing Structures to Functions: You can pass structures to functions by value or by reference (using pointers). When passing by value, the entire structure is copied, so changes made to the structure inside the function do not affect the original structure. When passing by reference, changes made to the structure inside the function affect the original structure. For example:
    c
    void display(struct Point p) {
    printf("x = %d, y = %d\n", p.x, p.y);
    }

    void modify(struct Point *p) {
    p->x *= 2;
    p->y *= 2;
    }

    display(p1); // Pass by value
    modify(&p1); // Pass by reference

  4. Returning Structures from Functions: You can return structures from functions. The structure is typically returned by value. For example:
    c
    struct Point add(struct Point p1, struct Point p2) {
    struct Point result;
    result.x = p1.x + p2.x;
    result.y = p1.y + p2.y;
    return result;
    }

    struct Point sum = add(p1, p2);

These are some basic operations you can perform on structures in C. Structures are a powerful feature that allows you to organize and manipulate related data efficiently.

Lab Exercise: Write a program to add two complex numbers using structures

Here’s a C program that adds two complex numbers using structures:

c
#include <stdio.h>

// Define a structure named 'Complex' with two members: 'real' and 'imaginary'
struct Complex {
float real;
float imaginary;
};

// Function to add two complex numbers
struct Complex addComplex(struct Complex num1, struct Complex num2) {
struct Complex result;
result.real = num1.real + num2.real;
result.imaginary = num1.imaginary + num2.imaginary;
return result;
}

int main() {
struct Complex num1, num2, result;

// Input the first complex number
printf("Enter real and imaginary parts of first complex number: ");
scanf("%f %f", &num1.real, &num1.imaginary);

// Input the second complex number
printf("Enter real and imaginary parts of second complex number: ");
scanf("%f %f", &num2.real, &num2.imaginary);

// Add the complex numbers
result = addComplex(num1, num2);

// Display the result
printf("Sum: %.2f + %.2fi\n", result.real, result.imaginary);

return 0;
}

In this program, we define a structure Complex with two members: real (for the real part) and imaginary (for the imaginary part) of a complex number. We then define a function addComplex that takes two Complex structures as input and returns the sum as a Complex structure. Inside the main function, we input two complex numbers, call the addComplex function to add them, and then display the sum.

Pointers to structure: declaring pointer to a structure, accessing structure members using pointer

In C, you can declare a pointer to a structure and access structure members using that pointer. Here’s an example that demonstrates these concepts:

c
#include <stdio.h>

// Define a structure named 'Point' with two members: 'x' and 'y'
struct Point {
int x;
int y;
};

int main() {
// Declare a pointer 'ptr' to a structure of type 'Point'
struct Point *ptr;

// Declare a structure variable 'point1' and initialize it
struct Point point1 = {10, 20};

// Assign the address of 'point1' to 'ptr'
ptr = &point1;

// Access structure members using 'ptr'
printf("x = %d, y = %d\n", ptr->x, ptr->y);

// Modify structure members using 'ptr'
ptr->x = 30;
ptr->y = 40;

// Access modified structure members
printf("Modified x = %d, y = %d\n", ptr->x, ptr->y);

return 0;
}

In this program, we declare a pointer ptr to a structure of type Point. We then declare a structure variable point1 and initialize it with values {10, 20}. We assign the address of point1 to ptr using the address-of operator (&). We can then access and modify structure members using the arrow operator (->) with ptr, which is a pointer to the structure.

Lab Exercise: Write a program to calculate the area of a rectangle using a pointer to a structure

Here’s a C program that calculates the area of a rectangle using a pointer to a structure:

c
#include <stdio.h>

// Define a structure named 'Rectangle' with two members: 'length' and 'width'
struct Rectangle {
float length;
float width;
};

// Function to calculate the area of a rectangle using a pointer to a structure
float calculateArea(struct Rectangle *rect) {
return rect->length * rect->width;
}

int main() {
// Declare a structure variable 'rect' and initialize it
struct Rectangle rect = {5.0, 10.0};

// Declare a pointer 'ptr' to a structure of type 'Rectangle' and assign the address of 'rect' to it
struct Rectangle *ptr = &rect;

// Calculate the area of the rectangle using 'ptr'
float area = calculateArea(ptr);

// Display the area of the rectangle
printf("Area of the rectangle: %.2f\n", area);

return 0;
}

In this program, we define a structure Rectangle with two members: length and width. We then define a function calculateArea that takes a pointer to a Rectangle structure as input and calculates the area of the rectangle using the formula length * width. Inside the main function, we declare a structure variable rect and initialize it with values {5.0, 10.0}. We then declare a pointer ptr to a Rectangle structure and assign the address of rect to it. Finally, we calculate the area of the rectangle using ptr and display the result.

Array of structures

In C, you can create an array of structures to store multiple instances of a structure. Here’s an example that demonstrates how to create and work with an array of structures:

c
#include <stdio.h>

// Define a structure named 'Student' with two members: 'name' and 'roll'
struct Student {
char name[50];
int roll;
};

int main() {
int i, n;

// Input the number of students
printf("Enter the number of students: ");
scanf("%d", &n);

// Declare an array 'students' of 'n' elements of type 'Student'
struct Student students[n];

// Input details of each student
for (i = 0; i < n; i++) {
printf("Enter name of student %d: ", i + 1);
scanf("%s", students[i].name);

printf("Enter roll number of student %d: ", i + 1);
scanf("%d", &students[i].roll);
}

// Display details of all students
printf("\nStudent Details:\n");
for (i = 0; i < n; i++) {
printf("Name: %s, Roll Number: %d\n", students[i].name, students[i].roll);
}

return 0;
}

In this program, we define a structure Student with two members: name (a character array) and roll (an integer). We then declare an array students of n elements of type Student, where n is the number of students input by the user. We use a loop to input the details of each student into the array. Finally, we use another loop to display the details of all students stored in the array.

Lab Exercise: Write a program to store and display information of students using an array of structures

Here’s a C program that stores and displays information of students using an array of structures:

c
#include <stdio.h>

// Define a structure named 'Student' with three members: 'name', 'roll', and 'marks'
struct Student {
char name[50];
int roll;
float marks;
};

int main() {
int i, n;

// Input the number of students
printf("Enter the number of students: ");
scanf("%d", &n);

// Declare an array 'students' of 'n' elements of type 'Student'
struct Student students[n];

// Input details of each student
for (i = 0; i < n; i++) {
printf("\nEnter details of student %d:\n", i + 1);
printf("Enter name: ");
scanf("%s", students[i].name);

printf("Enter roll number: ");
scanf("%d", &students[i].roll);

printf("Enter marks: ");
scanf("%f", &students[i].marks);
}

// Display details of all students
printf("\nStudent Details:\n");
for (i = 0; i < n; i++) {
printf("Name: %s, Roll Number: %d, Marks: %.2f\n", students[i].name, students[i].roll, students[i].marks);
}

return 0;
}

In this program, we define a structure Student with three members: name (a character array), roll (an integer), and marks (a float). We then declare an array students of n elements of type Student, where n is the number of students input by the user. We use a loop to input the details of each student into the array. Finally, we use another loop to display the details of all students stored in the array.

Nested structures

In C, you can define nested structures, which are structures that contain other structures as members. Here’s an example that demonstrates nested structures:

c
#include <stdio.h>

// Define a structure named 'Date' with three members: 'day', 'month', and 'year'
struct Date {
int day;
int month;
int year;
};

// Define a structure named 'Employee' with three members: 'name', 'id', and 'joinDate' (a nested structure)
struct Employee {
char name[50];
int id;
struct Date joinDate;
};

int main() {
// Declare a variable 'employee1' of type 'Employee'
struct Employee employee1;

// Initialize the members of 'employee1'
printf("Enter employee name: ");
scanf("%s", employee1.name);

printf("Enter employee ID: ");
scanf("%d", &employee1.id);

printf("Enter joining date (dd mm yyyy): ");
scanf("%d %d %d", &employee1.joinDate.day, &employee1.joinDate.month, &employee1.joinDate.year);

// Display the information of 'employee1'
printf("\nEmployee Information:\n");
printf("Name: %s\n", employee1.name);
printf("ID: %d\n", employee1.id);
printf("Joining Date: %02d/%02d/%d\n", employee1.joinDate.day, employee1.joinDate.month, employee1.joinDate.year);

return 0;
}

In this program, we define a structure Date with three members: day, month, and year, representing a date. We then define a structure Employee with three members: name (a character array), id (an integer), and joinDate (an instance of the nested structure Date). The joinDate member stores the joining date of the employee.

In the main function, we declare a variable employee1 of type Employee and input the employee’s name, ID, and joining date. We then display the information of employee1, including the joining date stored in the nested Date structure.

Lab Exercise: Write a program to store and display information of employees using nested structures

Here’s a C program that stores and displays information of employees using nested structures:

c
#include <stdio.h>

// Define a structure named 'Date' with three members: 'day', 'month', and 'year'
struct Date {
int day;
int month;
int year;
};

// Define a structure named 'Employee' with four members: 'name', 'id', 'salary', and 'joinDate' (a nested structure)
struct Employee {
char name[50];
int id;
float salary;
struct Date joinDate;
};

int main() {
int i, n;

// Input the number of employees
printf("Enter the number of employees: ");
scanf("%d", &n);

// Declare an array 'employees' of 'n' elements of type 'Employee'
struct Employee employees[n];

// Input details of each employee
for (i = 0; i < n; i++) {
printf("\nEnter details of employee %d:\n", i + 1);
printf("Enter name: ");
scanf("%s", employees[i].name);

printf("Enter ID: ");
scanf("%d", &employees[i].id);

printf("Enter salary: ");
scanf("%f", &employees[i].salary);

printf("Enter joining date (dd mm yyyy): ");
scanf("%d %d %d", &employees[i].joinDate.day, &employees[i].joinDate.month, &employees[i].joinDate.year);
}

// Display details of all employees
printf("\nEmployee Details:\n");
for (i = 0; i < n; i++) {
printf("\nEmployee %d:\n", i + 1);
printf("Name: %s\n", employees[i].name);
printf("ID: %d\n", employees[i].id);
printf("Salary: %.2f\n", employees[i].salary);
printf("Joining Date: %02d/%02d/%d\n", employees[i].joinDate.day, employees[i].joinDate.month, employees[i].joinDate.year);
}

return 0;
}

In this program, we define a structure Date with three members: day, month, and year, representing a date. We then define a structure Employee with four members: name (a character array), id (an integer), salary (a float), and joinDate (an instance of the nested structure Date). The joinDate member stores the joining date of the employee.

We use a loop to input the details of each employee into an array employees of n elements of type Employee, where n is the number of employees input by the user. We then use another loop to display the details of all employees stored in the array, including their names, IDs, salaries, and joining dates.

Passing structures to functions

In C, you can pass structures to functions in several ways:

  1. Passing each member of a structure as a separate argument: You can pass each member of a structure as a separate argument to a function. This approach is suitable for functions that only need to work with specific members of the structure.
  2. Passing a structure variable by value: You can pass a structure variable to a function by value, which means a copy of the entire structure is passed to the function. Any modifications made to the structure inside the function do not affect the original structure.
  3. Passing a structure variable by reference/address: You can pass a structure variable to a function by reference or address using pointers. This allows the function to modify the original structure.

Here’s an example program that demonstrates these concepts:

c
#include <stdio.h>

// Define a structure named 'Point' with two members: 'x' and 'y'
struct Point {
int x;
int y;
};

// Function prototype for passing each member of a structure as separate arguments
void printPoint(int x, int y);

// Function prototype for passing a structure variable by value
void displayPoint(struct Point p);

// Function prototype for passing a structure variable by reference/address
void movePoint(struct Point *p, int dx, int dy);

int main() {
struct Point p = {10, 20};

// Passing each member of a structure as separate arguments
printPoint(p.x, p.y);

// Passing a structure variable by value
displayPoint(p);

// Passing a structure variable by reference/address
movePoint(&p, 5, -5);
printf("After moving: (%d, %d)\n", p.x, p.y);

return 0;
}

// Function definition for passing each member of a structure as separate arguments
void printPoint(int x, int y) {
printf("Point: (%d, %d)\n", x, y);
}

// Function definition for passing a structure variable by value
void displayPoint(struct Point p) {
printf("Point: (%d, %d)\n", p.x, p.y);
}

// Function definition for passing a structure variable by reference/address
void movePoint(struct Point *p, int dx, int dy) {
p->x += dx;
p->y += dy;
}

In this program, we define a structure Point with two members: x and y. We then demonstrate three ways of passing a Point structure to functions: passing each member as separate arguments, passing by value, and passing by reference.

Lab Exercise: Write a program to pass a structure to a function and modify its members

Here’s a C program that demonstrates passing a structure to a function and modifying its members:

c
#include <stdio.h>

// Define a structure named 'Student' with three members: 'name', 'roll', and 'marks'
struct Student {
char name[50];
int roll;
float marks;
};

// Function prototype for modifying a structure member
void modifyStudent(struct Student *s);

int main() {
// Declare a structure variable 'student1' of type 'Student'
struct Student student1 = {"John", 101, 85.5};

// Display initial details of 'student1'
printf("Initial Details:\n");
printf("Name: %s\n", student1.name);
printf("Roll: %d\n", student1.roll);
printf("Marks: %.2f\n", student1.marks);

// Pass 'student1' to the function to modify its members
modifyStudent(&student1);

// Display modified details of 'student1'
printf("\nModified Details:\n");
printf("Name: %s\n", student1.name);
printf("Roll: %d\n", student1.roll);
printf("Marks: %.2f\n", student1.marks);

return 0;
}

// Function definition for modifying a structure member
void modifyStudent(struct Student *s) {
// Modify the 'marks' member of the structure
s->marks += 5.0;
}

In this program, we define a structure Student with three members: name, roll, and marks. We then declare a structure variable student1 of type Student and initialize its members. We pass student1 to the modifyStudent function by reference using a pointer. Inside the modifyStudent function, we modify the marks member of the structure s (which points to student1) by adding 5.0. Finally, we display the modified details of student1.

Typedef and structures

In C, typedef is used to create an alias or synonym for data types, including structures. This can make code more readable and easier to maintain. Here’s an example that demonstrates the use of typedef with structures:

c
#include <stdio.h>

// Define a structure named 'Point' with two members: 'x' and 'y'
struct Point {
int x;
int y;
};

// Define a typedef for the 'Point' structure
typedef struct Point Point;

int main() {
// Declare a variable 'p' of type 'Point' (using the typedef)
Point p = {10, 20};

// Access and display the members of 'p'
printf("Point: (%d, %d)\n", p.x, p.y);

return 0;
}

In this example, we define a structure Point with two members x and y. We then use typedef to create an alias Point for the struct Point type. This allows us to declare variables of type Point without using the struct keyword. The rest of the program demonstrates declaring a variable p of type Point and accessing its members.

Lab Exercise: Write a program to define a typedef for a structure and use it to declare variables

Here’s a C program that defines a typedef for a structure and uses it to declare variables:

c
#include <stdio.h>

// Define a structure named 'Student' with three members: 'name', 'roll', and 'marks'
struct Student {
char name[50];
int roll;
float marks;
};

// Define a typedef for the 'Student' structure
typedef struct Student Student;

int main() {
// Declare variables 'student1' and 'student2' of type 'Student' (using the typedef)
Student student1 = {"John", 101, 85.5};
Student student2 = {"Alice", 102, 90.0};

// Display details of 'student1' and 'student2'
printf("Student 1:\n");
printf("Name: %s\n", student1.name);
printf("Roll: %d\n", student1.roll);
printf("Marks: %.2f\n\n", student1.marks);

printf("Student 2:\n");
printf("Name: %s\n", student2.name);
printf("Roll: %d\n", student2.roll);
printf("Marks: %.2f\n", student2.marks);

return 0;
}

In this program, we define a structure Student with three members name, roll, and marks. We then use typedef to create an alias Student for the struct Student type. This allows us to declare variables student1 and student2 of type Student without using the struct keyword. The rest of the program demonstrates declaring and using variables of the Student type.

Unions

Defining a union

In C, a union is a special data type that allows storing different data types in the same memory location. Unlike structures, where each member has its own memory location, all members of a union share the same memory location. Here’s an example of defining a union:

c
#include <stdio.h>

// Define a union named 'Number' with three members: 'i' (int), 'f' (float), and 'c' (char)
union Number {
int i;
float f;
char c;
};

int main() {
// Declare a variable 'num' of type 'Number' (using the union)
union Number num;

// Assign values to members of the union
num.i = 10;
num.f = 3.14;
num.c = 'A';

// Display the values of all members
printf("Integer: %d\n", num.i);
printf("Float: %f\n", num.f);
printf("Character: %c\n", num.c);

// Display the size of the union
printf("Size of union: %lu bytes\n", sizeof(union Number));

return 0;
}

In this program, we define a union Number with three members: i (an integer), f (a float), and c (a character). We then declare a variable num of type Number and assign different values to each member. Since all members share the same memory location, modifying one member will affect the value of the other members. The sizeof operator is used to determine the size of the union in bytes, which will be the size of the largest member.

Lab Exercise: Write a program to define a union for storing an integer, a float, and a character

Here’s a C program that defines a union for storing an integer, a float, and a character:

c
#include <stdio.h>

// Define a union named 'Data' for storing an integer, a float, and a character
union Data {
int i;
float f;
char c;
};

int main() {
// Declare a variable 'data' of type 'Data' (using the union)
union Data data;

// Assign values to members of the union
data.i = 10;
data.f = 3.14;
data.c = 'A';

// Display the values of all members
printf("Integer: %d\n", data.i);
printf("Float: %f\n", data.f);
printf("Character: %c\n", data.c);

// Display the size of the union
printf("Size of union: %lu bytes\n", sizeof(union Data));

return 0;
}

In this program, we define a union Data with three members: i (an integer), f (a float), and c (a character). We then declare a variable data of type Data and assign different values to each member. The program displays the values of all members and the size of the union in bytes.

Declaring union variable

To declare a variable of a union type, you use the union keyword followed by the union name and the variable name. Here’s an example:

c
#include <stdio.h>

// Define a union named 'Data' for storing an integer, a float, and a character
union Data {
int i;
float f;
char c;
};

int main() {
// Declare a variable 'data' of type 'Data' (using the union)
union Data data;

// Assign values to members of the union
data.i = 10;
data.f = 3.14;
data.c = 'A';

// Display the values of all members
printf("Integer: %d\n", data.i);
printf("Float: %f\n", data.f);
printf("Character: %c\n", data.c);

// Display the size of the union
printf("Size of union: %lu bytes\n", sizeof(union Data));

return 0;
}

In this program, union Data data; declares a variable data of type Data, which is a union that can hold an integer, a float, or a character. The program then assigns different values to each member of the union and displays their values and the size of the union.

Lab Exercise: Write a program to define a union for storing an integer, a float, and a character

Here’s a C program that defines a union for storing an integer, a float, and a character:

c
#include <stdio.h>

// Define a union named 'Data' for storing an integer, a float, and a character
union Data {
int i;
float f;
char c;
};

int main() {
// Declare a variable 'data' of type 'Data' (using the union)
union Data data;

// Assign values to members of the union
data.i = 10;
data.f = 3.14;
data.c = 'A';

// Display the values of all members
printf("Integer: %d\n", data.i);
printf("Float: %f\n", data.f);
printf("Character: %c\n", data.c);

// Display the size of the union
printf("Size of union: %lu bytes\n", sizeof(union Data));

return 0;
}

In this program, we define a union Data with three members: i (an integer), f (a float), and c (a character). We then declare a variable data of type Data and assign different values to each member. The program displays the values of all members and the size of the union in bytes.

Operations on union

In C, unions are primarily used for storing different types of data in the same memory location. Unlike structures, where each member has its own memory location, all members of a union share the same memory location. This means that modifying one member of a union can affect the values of other members.

Here’s an example that demonstrates operations on a union:

c
#include <stdio.h>

// Define a union named 'Number' with three members: 'i' (int), 'f' (float), and 'c' (char)
union Number {
int i;
float f;
char c;
};

int main() {
// Declare a variable 'num' of type 'Number' (using the union)
union Number num;

// Assign a value to the integer member 'i' and display it
num.i = 65;
printf("Integer: %d, Character: %c\n", num.i, num.c);

// Assign a value to the character member 'c' and display it
num.c = 'B';
printf("Integer: %d, Character: %c\n", num.i, num.c);

// Assign a value to the float member 'f' and display it
num.f = 3.14;
printf("Integer: %d, Float: %f\n", num.i, num.f);

return 0;
}

In this program, we define a union Number with three members: i (an integer), f (a float), and c (a character). We then declare a variable num of type Number and demonstrate operations on the union. When we assign a value to one member of the union and then access another member, we may see unexpected results because all members share the same memory location.

Lab Exercise: Write a program to add two numbers using a union

Here’s a C program that uses a union to add two numbers (integer and float) together:

c
#include <stdio.h>

// Define a union named 'Number' with two members: 'i' (int) and 'f' (float)
union Number {
int i;
float f;
};

int main() {
// Declare a variable 'num' of type 'Number' (using the union)
union Number num;

// Input two numbers (integer and float) from the user
printf("Enter an integer: ");
scanf("%d", &num.i);

printf("Enter a float: ");
scanf("%f", &num.f);

// Add the integer and float together and display the result
float sum = num.i + num.f;
printf("Sum: %.2f\n", sum);

return 0;
}

In this program, we define a union Number with two members: i (an integer) and f (a float). We then declare a variable num of type Number and use it to store an integer and a float input by the user. Finally, we add the integer and float together and display the result.

Pointers to union

In C, you can use pointers to access members of a union. Here’s an example that demonstrates declaring a pointer to a union and accessing union members using the pointer:

c
#include <stdio.h>

// Define a union named 'Number' with two members: 'i' (int) and 'f' (float)
union Number {
int i;
float f;
};

int main() {
// Declare a variable 'num' of type 'Number' (using the union)
union Number num;

// Declare a pointer 'ptr' to 'Number' union
union Number *ptr;

// Initialize the pointer to point to 'num'
ptr = &num;

// Assign values to 'num' using pointer 'ptr'
ptr->i = 10;
printf("Integer: %d\n", ptr->i);

ptr->f = 3.14;
printf("Float: %f\n", ptr->f);

return 0;
}

In this program, we define a union Number with two members: i (an integer) and f (a float). We then declare a variable num of type Number and a pointer ptr to Number. We initialize ptr to point to num using the address-of operator &. We can then use ptr to access and modify the members of num using the arrow operator ->.

Lab Exercise: Write a program to access union members using a pointer to a union

Here’s a C program that demonstrates accessing union members using a pointer to a union:

c
#include <stdio.h>

// Define a union named 'Number' with two members: 'i' (int) and 'f' (float)
union Number {
int i;
float f;
};

int main() {
// Declare a variable 'num' of type 'Number' (using the union)
union Number num;

// Declare a pointer 'ptr' to 'Number' union
union Number *ptr;

// Initialize the pointer to point to 'num'
ptr = &num;

// Assign values to 'num' using pointer 'ptr'
ptr->i = 10;
printf("Integer: %d\n", ptr->i);

ptr->f = 3.14;
printf("Float: %f\n", ptr->f);

return 0;
}

In this program, we define a union Number with two members: i (an integer) and f (a float). We then declare a variable num of type Number and a pointer ptr to Number. We initialize ptr to point to num using the address-of operator &. We can then use ptr to access and modify the members of num using the arrow operator ->.

Array of union

In C, you can create an array of unions, where each element of the array is a union. Here’s an example that demonstrates how to create and use an array of unions:

c
#include <stdio.h>

// Define a union named 'Number' with two members: 'i' (int) and 'f' (float)
union Number {
int i;
float f;
};

int main() {
// Declare an array 'nums' of type 'Number' with 5 elements
union Number nums[5];

// Assign values to elements of the array
for (int i = 0; i < 5; i++) {
nums[i].i = i + 1;
nums[i].f = (float)(i + 1) * 1.5;
}

// Display the values of elements in the array
for (int i = 0; i < 5; i++) {
printf("Element %d: Integer = %d, Float = %f\n", i + 1, nums[i].i, nums[i].f);
}

return 0;
}

In this program, we define a union Number with two members: i (an integer) and f (a float). We then declare an array nums of type Number with 5 elements. We assign values to each element of the array, where the integer member i is assigned values 1, 2, 3, 4, 5, and the float member f is assigned values 1.5, 3.0, 4.5, 6.0, 7.5 respectively. Finally, we display the values of each element in the array.

Lab Exercise: Write a program to store and display information of employees using an array of unions

Here’s a C program that demonstrates storing and displaying information of employees using an array of unions:

c
#include <stdio.h>
#include <string.h>

// Define a union named 'EmployeeInfo' for storing information of an employee
union EmployeeInfo {
char name[50];
int emp_id;
float salary;
};

int main() {
// Declare an array 'employees' of type 'EmployeeInfo' with 3 elements
union EmployeeInfo employees[3];

// Assign values to elements of the array
strcpy(employees[0].name, "John Doe");
employees[0].emp_id = 101;
employees[0].salary = 50000.0;

strcpy(employees[1].name, "Alice Smith");
employees[1].emp_id = 102;
employees[1].salary = 60000.0;

strcpy(employees[2].name, "Bob Johnson");
employees[2].emp_id = 103;
employees[2].salary = 55000.0;

// Display the information of employees
printf("Employee 1:\n");
printf("Name: %s\n", employees[0].name);
printf("Employee ID: %d\n", employees[0].emp_id);
printf("Salary: %.2f\n\n", employees[0].salary);

printf("Employee 2:\n");
printf("Name: %s\n", employees[1].name);
printf("Employee ID: %d\n", employees[1].emp_id);
printf("Salary: %.2f\n\n", employees[1].salary);

printf("Employee 3:\n");
printf("Name: %s\n", employees[2].name);
printf("Employee ID: %d\n", employees[2].emp_id);
printf("Salary: %.2f\n\n", employees[2].salary);

return 0;
}

In this program, we define a union EmployeeInfo with three members: name (a character array for storing the name of the employee), emp_id (an integer for storing the employee ID), and salary (a float for storing the salary of the employee). We then declare an array employees of type EmployeeInfo with 3 elements and assign values to each element of the array. Finally, we display the information of each employee.

Nested union

In C, you can nest unions inside other structures or unions. Here’s an example that demonstrates a nested union:

c
#include <stdio.h>

// Define a union named 'Address' with two members: 'city' and 'pin'
union Address {
char city[50];
int pin;
};

// Define a structure named 'Employee' with three members: 'name', 'id', and nested union 'address'
struct Employee {
char name[50];
int id;
union Address address;
};

int main() {
// Declare a variable 'emp' of type 'Employee' (using the structure)
struct Employee emp;

// Assign values to members of the structure
strcpy(emp.name, "John Doe");
emp.id = 101;
strcpy(emp.address.city, "New York");
emp.address.pin = 12345;

// Display the information of the employee
printf("Employee Name: %s\n", emp.name);
printf("Employee ID: %d\n", emp.id);
printf("Employee Address: %s, PIN: %d\n", emp.address.city, emp.address.pin);

return 0;
}

In this program, we define a union Address with two members: city (a character array for storing the city name) and pin (an integer for storing the PIN code). We then define a structure Employee with three members: name (a character array for storing the name of the employee), id (an integer for storing the employee ID), and a nested union address of type Address. Inside the main function, we declare a variable emp of type Employee and assign values to its members. Finally, we display the information of the employee, including the nested union address.

Lab Exercise: Write a program to store and display information of employees using nested structures

Here’s a C program that demonstrates storing and displaying information of employees using nested structures:

c
#include <stdio.h>
#include <string.h>

// Define a structure named 'Address' for storing the address of an employee
struct Address {
char city[50];
int pin;
};

// Define a structure named 'Employee' for storing information of an employee
struct Employee {
char name[50];
int id;
struct Address address;
};

int main() {
// Declare an array 'employees' of type 'Employee' with 3 elements
struct Employee employees[3];

// Assign values to elements of the array
strcpy(employees[0].name, "John Doe");
employees[0].id = 101;
strcpy(employees[0].address.city, "New York");
employees[0].address.pin = 12345;

strcpy(employees[1].name, "Alice Smith");
employees[1].id = 102;
strcpy(employees[1].address.city, "Los Angeles");
employees[1].address.pin = 67890;

strcpy(employees[2].name, "Bob Johnson");
employees[2].id = 103;
strcpy(employees[2].address.city, "Chicago");
employees[2].address.pin = 54321;

// Display the information of employees
for (int i = 0; i < 3; i++) {
printf("Employee %d:\n", i + 1);
printf("Name: %s\n", employees[i].name);
printf("Employee ID: %d\n", employees[i].id);
printf("City: %s, PIN: %d\n\n", employees[i].address.city, employees[i].address.pin);
}

return 0;
}

In this program, we define a structure Address for storing the address of an employee, which includes city (a character array for storing the city name) and pin (an integer for storing the PIN code). We then define a structure Employee for storing information of an employee, which includes name (a character array for storing the name of the employee), id (an integer for storing the employee ID), and address (a nested structure of type Address for storing the address of the employee).

We declare an array employees of type Employee with 3 elements and assign values to each element of the array. Finally, we display the information of each employee, including their name, ID, city, and PIN code.

Typedef and union

In C, you can use typedef to create a new type name for a union. This can make the code more readable and easier to maintain. Here’s an example that demonstrates typedef with a union:

c
#include <stdio.h>

// Define a union named 'Number' with two members: 'i' (int) and 'f' (float)
typedef union {
int i;
float f;
} Number;

int main() {
// Declare a variable 'num' of type 'Number' (using the typedef)
Number num;

// Assign values to the union members
num.i = 10;
printf("Integer: %d\n", num.i);

num.f = 3.14;
printf("Float: %f\n", num.f);

return 0;
}

In this program, we use typedef to create a new type name Number for the union. This allows us to declare variables of type Number without using the union keyword. The rest of the program demonstrates declaring a variable num of type Number and assigning values to its members.

Lab Exercise: Write a program to define a typedef for a union and use it to declare variables

Here’s a C program that defines a typedef for a union and uses it to declare variables:

c
#include <stdio.h>

// Define a union named 'Data' with two members: 'i' (int) and 'f' (float)
typedef union {
int i;
float f;
} Data;

int main() {
// Declare variables 'num1' and 'num2' of type 'Data' (using the typedef)
Data num1, num2;

// Assign values to the union members
num1.i = 10;
printf("num1 Integer: %d\n", num1.i);

num2.f = 3.14;
printf("num2 Float: %f\n", num2.f);

return 0;
}

In this program, we define a typedef for a union named Data with two members: i (an integer) and f (a float). We then declare two variables num1 and num2 of type Data using the typedef. We assign values to the members of each variable and print them to the console.

Enumerations

Enumerations in C are used to define a set of named integer constants. Each constant in the enumeration list is assigned a value, starting from 0 by default, and incremented by 1 for each successive constant unless explicitly specified. Here’s an example of how enumerations can be used:

c
#include <stdio.h>

// Define an enumeration named 'Weekday' with constants for each day of the week
enum Weekday {
MONDAY, // 0
TUESDAY, // 1
WEDNESDAY, // 2
THURSDAY, // 3
FRIDAY, // 4
SATURDAY, // 5
SUNDAY // 6
};

int main() {
// Declare a variable 'day' of type 'Weekday' (using the enumeration)
enum Weekday day;

// Assign a value to 'day'
day = WEDNESDAY;

// Use 'day' in a switch statement
switch (day) {
case MONDAY:
printf("It's Monday!\n");
break;
case WEDNESDAY:
printf("It's Wednesday!\n");
break;
default:
printf("It's another day.\n");
break;
}

return 0;
}

In this example, we define an enumeration Weekday with constants for each day of the week. We then declare a variable day of type Weekday and assign the constant WEDNESDAY to it. Finally, we use a switch statement to check the value of day and print a message accordingly.

Lab Exercise: Write a program to define an enumeration for days of the week and display the day corresponding to a given number

Here’s a C program that defines an enumeration for days of the week and displays the day corresponding to a given number:

c
#include <stdio.h>

// Define an enumeration named 'Weekday' for days of the week
enum Weekday {
SUNDAY = 1,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
};

int main() {
// Declare a variable 'dayNum' to store the day number
int dayNum;

// Input a day number from the user
printf("Enter a day number (1-7): ");
scanf("%d", &dayNum);

// Check if the input day number is valid and display the corresponding day
switch (dayNum) {
case SUNDAY:
printf("Sunday\n");
break;
case MONDAY:
printf("Monday\n");
break;
case TUESDAY:
printf("Tuesday\n");
break;
case WEDNESDAY:
printf("Wednesday\n");
break;
case THURSDAY:
printf("Thursday\n");
break;
case FRIDAY:
printf("Friday\n");
break;
case SATURDAY:
printf("Saturday\n");
break;
default:
printf("Invalid day number.\n");
break;
}

return 0;
}

In this program, we define an enumeration Weekday for days of the week, starting with SUNDAY = 1. We then input a day number from the user and use a switch statement to check the input day number and display the corresponding day.

Bit-fields

Bit-fields in C allow you to specify the number of bits that should be used to store each member of a structure. This can be useful when you need to optimize memory usage, especially when dealing with constrained environments. Here’s an example of how bit-fields can be used:

c
#include <stdio.h>

// Define a structure named 'Flags' with bit-fields for various flags
struct Flags {
unsigned int flag1 : 1; // 1 bit for flag1
unsigned int flag2 : 2; // 2 bits for flag2
unsigned int flag3 : 3; // 3 bits for flag3
};

int main() {
// Declare a variable 'flags' of type 'Flags' (using the structure)
struct Flags flags;

// Set values to the bit-fields
flags.flag1 = 1;
flags.flag2 = 2;
flags.flag3 = 3;

// Display the values of the bit-fields
printf("Flag1: %u\n", flags.flag1);
printf("Flag2: %u\n", flags.flag2);
printf("Flag3: %u\n", flags.flag3);

// Size of the structure
printf("Size of Flags: %lu bytes\n", sizeof(struct Flags));

return 0;
}

In this example, we define a structure Flags with three bit-fields: flag1, flag2, and flag3, which are 1, 2, and 3 bits wide, respectively. We then declare a variable flags of type Flags and set values to the bit-fields. Finally, we display the values of the bit-fields and the size of the structure.

Lab Exercise: Write a program to demonstrate the use of bit-fields to store and manipulate binary values

Here’s a C program that demonstrates the use of bit-fields to store and manipulate binary values:

c
#include <stdio.h>

// Define a structure named 'Binary' with bit-fields for storing binary values
struct Binary {
unsigned int b0 : 1;
unsigned int b1 : 1;
unsigned int b2 : 1;
unsigned int b3 : 1;
unsigned int b4 : 1;
unsigned int b5 : 1;
unsigned int b6 : 1;
unsigned int b7 : 1;
};

int main() {
// Declare a variable 'binary' of type 'Binary' (using the structure)
struct Binary binary;

// Initialize the bit-fields
binary.b0 = 0;
binary.b1 = 1;
binary.b2 = 0;
binary.b3 = 1;
binary.b4 = 0;
binary.b5 = 1;
binary.b6 = 0;
binary.b7 = 1;

// Display the binary value
printf("Binary value: %u%u%u%u %u%u%u%u\n",
binary.b7, binary.b6, binary.b5, binary.b4,
binary.b3, binary.b2, binary.b1, binary.b0);

return 0;
}

In this program, we define a structure Binary with 8 bit-fields b0 to b7, each representing a single binary digit (0 or 1). We then declare a variable binary of type Binary and initialize its bit-fields to represent the binary value 0101 0101. Finally, we display the binary value by printing the values of the bit-fields in reverse order (from b7 to b0).

Files

Introduction to files

In C, files are used for both input and output operations. The standard library provides functions for working with files, such as fopen, fclose, fscanf, fprintf, fread, and fwrite. Here’s a basic introduction to working with files in C:

  1. Opening a File (fopen): To open a file, you use the fopen function, which takes two arguments: the name of the file and the mode in which to open the file (e.g., “r” for reading, “w” for writing, “a” for appending).
    c
    FILE *file = fopen("example.txt", "w");
  2. Writing to a File (fprintf): To write to a file, you use the fprintf function, which works similar to printf but takes an additional argument for the file pointer.
    c
    fprintf(file, "Hello, world!\n");
  3. Reading from a File (fscanf): To read from a file, you use the fscanf function, which works similar to scanf but takes an additional argument for the file pointer.
    c
    char buffer[255];
    fscanf(file, "%s", buffer);
  4. Closing a File (fclose): It’s important to close a file when you’re done using it to free up system resources. You use the fclose function to close a file.
    c
    fclose(file);

Here’s a complete example that demonstrates writing and reading from a file:

c
#include <stdio.h>

int main() {
FILE *file = fopen("example.txt", "w");

if (file != NULL) {
fprintf(file, "Hello, world!\n");
fclose(file);
}

file = fopen("example.txt", "r");

if (file != NULL) {
char buffer[255];
fscanf(file, "%s", buffer);
printf("Read from file: %s\n", buffer);
fclose(file);
}

return 0;
}

This program writes “Hello, world!” to a file named “example.txt” and then reads it back and prints it to the console.

Lab Exercise: Write a program to create a file and write some text to it

Here’s a simple C program that creates a file named “output.txt” and writes some text to it:

c
#include <stdio.h>

int main() {
FILE *file = fopen("output.txt", "w");

if (file != NULL) {
fprintf(file, "This is some text written to the file.\n");
fprintf(file, "Writing to files in C is easy!\n");
fclose(file);
printf("Text written to file successfully.\n");
} else {
printf("Failed to open file.\n");
}

return 0;
}

This program uses fopen with mode "w" to open the file “output.txt” for writing. It then uses fprintf to write two lines of text to the file. Finally, it closes the file using fclose. If the file cannot be opened, it prints an error message.

Streams

In C, a stream is a flow of data between the program and an external device such as a file or the console. Streams are used for input and output operations. There are three standard streams provided by the C library:

  1. stdin (Standard Input): This stream is used for reading input from the user (e.g., keyboard). It is associated with the file pointer stdin.
  2. stdout (Standard Output): This stream is used for writing output to the console. It is associated with the file pointer stdout.
  3. stderr (Standard Error): This stream is used for writing error messages to the console. It is associated with the file pointer stderr.

You can perform input and output operations on these streams using functions like scanf and printf. Additionally, you can use redirection to change the source or destination of the streams. For example, you can redirect the output of a program to a file using the > operator in the command line:

sh
./program > output.txt

Here’s an example program that demonstrates the use of streams:

c
#include <stdio.h>

int main() {
int num;
printf("Enter a number: ");
scanf("%d", &num);
printf("You entered: %d\n", num);

fprintf(stderr, "This is an error message.\n");

return 0;
}

In this program, scanf reads a number from the standard input (stdin) and printf writes the number to the standard output (stdout). The fprintf function writes an error message to the standard error (stderr).

Lab Exercise: Write a program to read from a file and display its contents on the console

Here’s a C program that reads from a file named “input.txt” and displays its contents on the console:

c
#include <stdio.h>

int main() {
FILE *file = fopen("input.txt", "r");

if (file != NULL) {
char buffer[255];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}
fclose(file);
} else {
printf("Failed to open file.\n");
}

return 0;
}

This program uses fopen with mode "r" to open the file “input.txt” for reading. It then uses a while loop with fgets to read each line from the file and printf to display it on the console. Finally, it closes the file using fclose. If the file cannot be opened, it prints an error message.

I/O using streams: opening a stream, closing stream

In C, you can use streams for input and output operations. The standard library provides functions for opening and closing streams, such as fopen and fclose for files. Here’s a basic example:

  1. Opening a Stream (fopen): To open a file stream for reading or writing, you use the fopen function. It takes two arguments: the name of the file and the mode in which to open the file (e.g., “r” for reading, “w” for writing, “a” for appending).
    c
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
    perror("Failed to open file");
    return 1;
    }
  2. Closing a Stream (fclose): It’s important to close a stream when you’re done using it to free up system resources. You use the fclose function to close a stream.
    c
    if (fclose(file) != 0) {
    perror("Failed to close file");
    return 1;
    }

Here’s a complete example that demonstrates opening and closing a file stream:

c
#include <stdio.h>

int main() {
FILE *file = fopen("example.txt", "w");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

fprintf(file, "Hello, world!\n");

if (fclose(file) != 0) {
perror("Failed to close file");
return 1;
}

return 0;
}

In this example, we use fopen to open the file “example.txt” for writing, write a string to it using fprintf, and then close the file using fclose. If any operation fails, an error message is printed using perror.

Lab Exercise: Write a program to copy the contents of one file to another file

Here’s a C program that copies the contents of one file to another file:

c
#include <stdio.h>

int main() {
FILE *sourceFile = fopen("source.txt", "r");
if (sourceFile == NULL) {
perror("Failed to open source file");
return 1;
}

FILE *destinationFile = fopen("destination.txt", "w");
if (destinationFile == NULL) {
perror("Failed to open destination file");
fclose(sourceFile);
return 1;
}

char buffer[1024];
size_t bytesRead;
while ((bytesRead = fread(buffer, 1, sizeof(buffer), sourceFile)) > 0) {
fwrite(buffer, 1, bytesRead, destinationFile);
}

if (ferror(sourceFile)) {
perror("Error reading from source file");
}

if (fclose(sourceFile) != 0) {
perror("Failed to close source file");
return 1;
}

if (fclose(destinationFile) != 0) {
perror("Failed to close destination file");
return 1;
}

printf("File copied successfully.\n");
return 0;
}

This program opens two files: “source.txt” for reading and “destination.txt” for writing. It then reads data from the source file in chunks of 1024 bytes using fread and writes the data to the destination file using fwrite. Finally, it closes both files and prints a success message. If any operation fails, an error message is printed using perror.

Character input, Character output

Character input and output in C are typically performed using the standard input (stdin) and standard output (stdout). You can use functions like getchar and putchar for character input and output, respectively. Here’s a simple example:

c
#include <stdio.h>

int main() {
char c;

// Character input
printf("Enter a character: ");
c = getchar();

// Character output
printf("You entered: ");
putchar(c);
printf("\n");

return 0;
}

In this example, getchar is used to read a single character from the standard input (stdin), and putchar is used to display the character on the standard output (stdout).

Lab Exercise: Write a program to count the number of characters, words, and lines in a file

Here’s a C program that counts the number of characters, words, and lines in a file:

c
#include <stdio.h>
#include <stdbool.h>

int main() {
FILE *file = fopen("input.txt", "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

int charCount = 0;
int wordCount = 0;
int lineCount = 0;
bool inWord = false;
char c;

while ((c = fgetc(file)) != EOF) {
charCount++;

if (c == '\n') {
lineCount++;
}

if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
inWord = false;
} else if (!inWord) {
inWord = true;
wordCount++;
}
}

if (!feof(file)) {
perror("Error reading file");
fclose(file);
return 1;
}

fclose(file);

printf("Character count: %d\n", charCount);
printf("Word count: %d\n", wordCount);
printf("Line count: %d\n", lineCount);

return 0;
}

In this program, we open a file named “input.txt” for reading and then iterate through each character in the file. We count the number of characters, words, and lines by tracking whitespace characters to determine word boundaries and newline characters to determine line boundaries. Finally, we print the counts to the console.

File position indicator

In C, the file position indicator is a pointer that indicates the current position in a file for reading or writing operations. It keeps track of the byte offset from the beginning of the file. You can move the file position indicator using the fseek function and query its position using the ftell function. Here’s an example:

c
#include <stdio.h>

int main() {
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

// Move the file position indicator to the end of the file
fseek(file, 0, SEEK_END);

// Get the current position of the file position indicator
long fileSize = ftell(file);
if (fileSize == -1) {
perror("ftell failed");
fclose(file);
return 1;
}

printf("File size: %ld bytes\n", fileSize);

fclose(file);
return 0;
}

In this example, we open a file “example.txt” for reading and then use fseek with SEEK_END to move the file position indicator to the end of the file. We then use ftell to get the current position of the file position indicator, which gives us the size of the file in bytes. Finally, we print the file size to the console.

Lab Exercise: Write a program to move the file pointer to a specific position in a file and read/write data from/to that position

Here’s a C program that demonstrates how to move the file pointer to a specific position in a file and read/write data from/to that position:

c
#include <stdio.h>

int main() {
FILE *file = fopen("data.txt", "r+");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

// Move the file pointer to a specific position (e.g., 5th byte)
fseek(file, 4, SEEK_SET);

// Write data at the current position
fprintf(file, "world");

// Move the file pointer to the beginning of the file
fseek(file, 0, SEEK_SET);

// Read data from the file
char buffer[255];
fscanf(file, "%s", buffer);
printf("Read from file: %s\n", buffer);

fclose(file);
return 0;
}

In this example, we open a file “data.txt” for reading and writing ("r+" mode). We then use fseek to move the file pointer to the 5th byte (index 4) in the file. We write “world” at this position using fprintf. Next, we move the file pointer to the beginning of the file and read the data using fscanf. Finally, we print the read data to the console.

End of file and errors

In C, the end-of-file (EOF) indicator is used to indicate that there are no more characters to read from a file. The feof function is used to check if the end of a file has been reached. Additionally, the ferror function is used to check for errors during file operations. Here’s an example that demonstrates their usage:

c
#include <stdio.h>

int main() {
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

int c;
while ((c = fgetc(file)) != EOF) {
putchar(c);
}

if (feof(file)) {
printf("\nEnd of file reached.\n");
} else if (ferror(file)) {
printf("\nError reading file.\n");
}

fclose(file);
return 0;
}

In this example, we open a file “example.txt” for reading and then use a while loop with fgetc to read characters from the file until the end of the file is reached (EOF). After the loop, we use feof to check if the end of the file was reached, and ferror to check if there was an error during the file reading operation. Finally, we close the file using fclose.

Lab Exercise: Write a program to read integers from a file and find their sum

Here’s a C program that reads integers from a file named “numbers.txt” and finds their sum:

c
#include <stdio.h>

int main() {
FILE *file = fopen("numbers.txt", "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

int sum = 0;
int num;
while (fscanf(file, "%d", &num) == 1) {
sum += num;
}

if (!feof(file)) {
perror("Error reading file");
fclose(file);
return 1;
}

fclose(file);

printf("Sum of numbers: %d\n", sum);
return 0;
}

In this program, we open a file “numbers.txt” for reading and then use a while loop with fscanf to read integers from the file. The loop continues as long as fscanf successfully reads an integer (== 1). We add each integer to the sum variable. After the loop, we use feof to check if the end of the file was reached. If there was an error during the file reading operation, feof will return false, and we print an error message using perror. Finally, we close the file and print the sum of the numbers.

Line input and line output

In C, you can read and write lines of text using the fgets and fputs functions, respectively. Here’s an example program that demonstrates reading lines from a file and writing lines to another file:

c
#include <stdio.h>

int main() {
FILE *inputFile = fopen("input.txt", "r");
if (inputFile == NULL) {
perror("Failed to open input file");
return 1;
}

FILE *outputFile = fopen("output.txt", "w");
if (outputFile == NULL) {
perror("Failed to open output file");
fclose(inputFile);
return 1;
}

char buffer[255];
while (fgets(buffer, sizeof(buffer), inputFile) != NULL) {
fputs(buffer, outputFile);
}

fclose(inputFile);
fclose(outputFile);

printf("Lines copied successfully.\n");
return 0;
}

In this example, we open an input file “input.txt” for reading and an output file “output.txt” for writing. We then use a while loop with fgets to read lines from the input file and fputs to write the lines to the output file. Finally, we close both files and print a success message.

Lab Exercise: Write a program to read lines from a file, convert them to uppercase, and write them to another file

Here’s a C program that reads lines from a file named “input.txt”, converts them to uppercase, and writes them to another file named “output.txt”:

c
#include <stdio.h>
#include <ctype.h>

int main() {
FILE *inputFile = fopen("input.txt", "r");
if (inputFile == NULL) {
perror("Failed to open input file");
return 1;
}

FILE *outputFile = fopen("output.txt", "w");
if (outputFile == NULL) {
perror("Failed to open output file");
fclose(inputFile);
return 1;
}

char buffer[255];
while (fgets(buffer, sizeof(buffer), inputFile) != NULL) {
for (int i = 0; buffer[i] != '\0'; i++) {
buffer[i] = toupper(buffer[i]);
}
fputs(buffer, outputFile);
}

fclose(inputFile);
fclose(outputFile);

printf("Lines converted to uppercase and written to output.txt.\n");
return 0;
}

In this program, we open an input file “input.txt” for reading and an output file “output.txt” for writing. We then use a while loop with fgets to read lines from the input file. For each line, we use a for loop to convert each character to uppercase using the toupper function. Finally, we write the modified line to the output file using fputs.

Formatted I/O

Formatted input/output in C is performed using functions like printf and scanf for console output and input, respectively, and fprintf and fscanf for file output and input, respectively. These functions allow you to specify formatting options for the data being read or written. Here’s an example program that demonstrates formatted input/output:

c
#include <stdio.h>

int main() {
int num1 = 10;
float num2 = 3.14159;
char str[] = "hello";

// Formatted console output
printf("Integer: %d\n", num1);
printf("Float: %f\n", num2);
printf("String: %s\n", str);

// Formatted file output
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
perror("Failed to open file");
return 1;
}
fprintf(file, "Integer: %d\n", num1);
fprintf(file, "Float: %f\n", num2);
fprintf(file, "String: %s\n", str);
fclose(file);

// Formatted console input
int inputNum1;
float inputNum2;
char inputStr[255];
printf("Enter an integer, a float, and a string: ");
scanf("%d %f %s", &inputNum1, &inputNum2, inputStr);
printf("You entered: Integer=%d, Float=%f, String=%s\n", inputNum1, inputNum2, inputStr);

return 0;
}

In this program, we demonstrate formatted output using printf for console output and fprintf for file output. We also demonstrate formatted input using scanf for console input. The %d, %f, and %s format specifiers are used to specify the type of data being read or written.

Lab Exercise: Write a program to read student records from a file, calculate their total marks, and write the results to another file

Here’s a C program that reads student records from a file named “input.txt”, calculates their total marks, and writes the results to another file named “output.txt”:

c
#include <stdio.h>

struct Student {
char name[50];
int marks[5];
};

int main() {
FILE *inputFile = fopen("input.txt", "r");
if (inputFile == NULL) {
perror("Failed to open input file");
return 1;
}

FILE *outputFile = fopen("output.txt", "w");
if (outputFile == NULL) {
perror("Failed to open output file");
fclose(inputFile);
return 1;
}

struct Student student;
while (fscanf(inputFile, "%s %d %d %d %d %d",
student.name, &student.marks[0], &student.marks[1], &student.marks[2], &student.marks[3], &student.marks[4]) == 6) {
int totalMarks = 0;
for (int i = 0; i < 5; i++) {
totalMarks += student.marks[i];
}
fprintf(outputFile, "%s %d\n", student.name, totalMarks);
}

fclose(inputFile);
fclose(outputFile);

printf("Student records processed and written to output.txt.\n");
return 0;
}

In this program, we define a struct Student to store the student’s name and marks. We open an input file “input.txt” for reading and an output file “output.txt” for writing. We then use a while loop with fscanf to read student records from the input file, calculate the total marks for each student, and write the results to the output file using fprintf. Finally, we close both files and print a success message.

Block input and output

Block input and output in C can be performed using functions like fread and fwrite for reading and writing blocks of data, respectively. Here’s an example program that demonstrates block input and output:

c
#include <stdio.h>

struct Record {
int id;
char name[50];
float salary;
};

int main() {
// Writing records to a file
struct Record records[] = {
{1, "John Doe", 50000.0},
{2, "Jane Smith", 60000.0},
{3, "Alice Johnson", 70000.0}
};

FILE *outputFile = fopen("records.bin", "wb");
if (outputFile == NULL) {
perror("Failed to open file");
return 1;
}

fwrite(records, sizeof(struct Record), 3, outputFile);
fclose(outputFile);

printf("Records written to file.\n");

// Reading records from a file
struct Record readRecords[3];

FILE *inputFile = fopen("records.bin", "rb");
if (inputFile == NULL) {
perror("Failed to open file");
return 1;
}

fread(readRecords, sizeof(struct Record), 3, inputFile);
fclose(inputFile);

printf("Records read from file:\n");
for (int i = 0; i < 3; i++) {
printf("ID: %d, Name: %s, Salary: %.2f\n", readRecords[i].id, readRecords[i].name, readRecords[i].salary);
}

return 0;
}

In this program, we define a struct Record to represent a record with an ID, name, and salary. We first write an array of Record structures to a binary file “records.bin” using fwrite. We then read the records back from the file into another array using fread and print them to the console.

Lab Exercise: Write a program to read a block of data from a file, modify it, and write it back to the file

Here’s a C program that reads a block of data from a file named “data.bin”, modifies it by adding 10 to each integer in the block, and writes it back to the file:

c
#include <stdio.h>

int main() {
// Reading block of data from file
int data[5];
FILE *file = fopen("data.bin", "rb");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

fread(data, sizeof(int), 5, file);
fclose(file);

// Modifying the data
for (int i = 0; i < 5; i++) {
data[i] += 10;
}

// Writing modified data back to file
file = fopen("data.bin", "wb");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

fwrite(data, sizeof(int), 5, file);
fclose(file);

printf("Data modified and written back to file.\n");

return 0;
}

In this program, we first open the file “data.bin” for reading in binary mode ("rb"). We then use fread to read a block of 5 integers from the file into the data array. We close the file and then modify each integer in the array by adding 10 to it. Finally, we open the file again, this time for writing in binary mode ("wb"), and use fwrite to write the modified data back to the file.

File type

In C, files can be classified into two main types based on the data they contain: text files and binary files.

  1. Text files: Text files contain human-readable characters and are typically used to store textual data such as plain text documents, configuration files, and source code. Text files are stored in a format that can be easily read and understood by humans and can be edited using a text editor. In C, text files are opened using the "r" mode for reading and "w" mode for writing.
  2. Binary files: Binary files contain data in a format that is not human-readable and can include any type of data, including text, images, audio, and executable code. Binary files are used to store data that needs to be read or written in its raw, binary form. In C, binary files are opened using the "rb" mode for reading and "wb" mode for writing.

Here’s a summary of the file modes used in C for text and binary files:

  • Text file modes:
    • "r": Open for reading (file must exist).
    • "w": Open for writing (creates a new file or truncates an existing file).
    • "a": Open for appending (writes to the end of the file).
    • "r+": Open for reading and writing (file must exist).
    • "w+": Open for reading and writing (creates a new file or truncates an existing file).
    • "a+": Open for reading and appending (writes to the end of the file).
  • Binary file modes:
    • "rb": Open for reading in binary mode (file must exist).
    • "wb": Open for writing in binary mode (creates a new file or truncates an existing file).
    • "ab": Open for appending in binary mode (writes to the end of the file).
    • "r+b" or "rb+": Open for reading and writing in binary mode (file must exist).
    • "w+b" or "wb+": Open for reading and writing in binary mode (creates a new file or truncates an existing file).
    • "a+b" or "ab+": Open for reading and appending in binary mode (writes to the end of the file).

Lab Exercise: Write a program to determine the type of a file (text file or binary file)

Determining the type of a file (text file or binary file) can be done by examining its contents. One common approach is to check if the file contains any non-printable characters (characters with ASCII values below 32, except for newline, carriage return, and tab characters), as binary files typically contain such characters. Here’s a C program that demonstrates how to determine the type of a file:

c
#include <stdio.h>
#include <stdbool.h>

bool isBinary(FILE *file) {
int c;
while ((c = fgetc(file)) != EOF) {
if (c < 32 && c != '\n' && c != '\r' && c != '\t') {
return true;
}
}
return false;
}

int main() {
FILE *file = fopen("file.txt", "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

bool binary = isBinary(file);

if (binary) {
printf("The file is a binary file.\n");
} else {
printf("The file is a text file.\n");
}

fclose(file);
return 0;
}

In this program, the isBinary function checks if a file is binary by reading each character from the file and checking if it is a non-printable character (excluding newline, carriage return, and tab characters). If such a character is found, the function returns true, indicating that the file is binary. Otherwise, it returns false, indicating that the file is text. The main function opens a file “file.txt” for reading and then calls isBinary to determine the type of the file. Finally, it prints the result to the console.

Files and command line arguments

Files and command line arguments are two important aspects of C programming for handling input and output. Command line arguments are used to pass information to a program when it is executed from the command line. Files are used for reading and writing data to and from external files. Here’s an example program that demonstrates how to use command line arguments and files:

c
#include <stdio.h>

int main(int argc, char *argv[]) {
// Check if the correct number of command line arguments are provided
if (argc != 3) {
printf("Usage: %s input_file output_file\n", argv[0]);
return 1;
}

// Open the input file for reading
FILE *inputFile = fopen(argv[1], "r");
if (inputFile == NULL) {
perror("Failed to open input file");
return 1;
}

// Open the output file for writing
FILE *outputFile = fopen(argv[2], "w");
if (outputFile == NULL) {
perror("Failed to open output file");
fclose(inputFile);
return 1;
}

// Read from the input file and write to the output file
int c;
while ((c = fgetc(inputFile)) != EOF) {
fputc(c, outputFile);
}

// Close the files
fclose(inputFile);
fclose(outputFile);

printf("File copied successfully.\n");
return 0;
}

In this program, the main function takes two command line arguments: the input file and the output file. It checks if the correct number of arguments are provided and displays a usage message if not. It then opens the input file for reading and the output file for writing. It reads characters from the input file and writes them to the output file until the end of the file is reached. Finally, it closes both files and prints a success message.

Lab Exercise: Write a program that takes a filename as a command line argument and displays its contents

Here’s a C program that takes a filename as a command line argument and displays its contents:

c
#include <stdio.h>

int main(int argc, char *argv[]) {
// Check if a filename is provided as a command line argument
if (argc != 2) {
printf("Usage: %s <filename>\n", argv[0]);
return 1;
}

// Open the file for reading
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}

// Read and display the contents of the file
int c;
while ((c = fgetc(file)) != EOF) {
putchar(c);
}

// Close the file
fclose(file);

return 0;
}

In this program, the main function checks if a filename is provided as a command line argument. If not, it displays a usage message and returns 1. It then opens the file specified by the command line argument for reading. If the file cannot be opened, an error message is displayed, and the program exits with a return code of 1.

The program then reads each character from the file using fgetc and displays it using putchar. This process continues until the end of the file is reached (EOF). Finally, the file is closed using fclose.

Comprehensive bioinformatics lab exercise

Bioinformatics Lab Exercise – DNA Sequence Analysis

Aim: To perform basic DNA sequence analysis using C programming with concepts of strings, pointers, structures, unions, and file handling.

Task Description:

  1. Read a DNA sequence from a file.
  2. Calculate the length of the DNA sequence.
  3. Count the occurrences of each nucleotide (A, T, C, G) in the DNA sequence.
  4. Determine the complementary DNA sequence.
  5. Translate the DNA sequence into a protein sequence using a codon table.

Steps:

  1. Read the DNA sequence from a file into a character array using file handling.
  2. Calculate the length of the DNA sequence using strings.
  3. Count the occurrences of each nucleotide using arrays and pointers.
  4. Determine the complementary DNA sequence by replacing each nucleotide with its complementary base (A → T, T → A, C → G, G → C).
  5. Translate the DNA sequence into a protein sequence using a codon table (you can define a structure or a union for the codon table).
  6. Display the original DNA sequence, its length, nucleotide counts, complementary DNA sequence, and the translated protein sequence.

Sample Codon Table (using a structure):

c
struct CodonTable {
char codon[4];
char amino_acid;
};

struct CodonTable codon_table[] = {
{"TTT", 'F'}, {"TTC", 'F'}, {"TTA", 'L'}, {"TTG", 'L'},
{"TCT", 'S'}, {"TCC", 'S'}, {"TCA", 'S'}, {"TCG", 'S'},
// Complete the table with all codons and their corresponding amino acids
};

Lab Report:

  1. Introduction: Brief overview of DNA sequence analysis and its significance in bioinformatics.
  2. Materials and Methods: Description of the C programming concepts used and the approach for sequence analysis.
  3. Results: Display of the original DNA sequence, its length, nucleotide counts, complementary DNA sequence, and the translated protein sequence.
  4. Discussion: Interpretation of the results, including the importance of understanding DNA sequence information in biological research.
  5. Conclusion: Summary of the lab exercise and its outcomes.

Note: Ensure that the DNA sequence file is provided and contains a valid DNA sequence. The codon table should be complete for accurate translation of the DNA sequence into a protein sequence.

Solution

Here’s a solution for the bioinformatics lab exercise using C programming:

c
#include <stdio.h>
#include <string.h>

// Define a structure for the codon table
struct CodonTable {
char codon[4];
char amino_acid;
};

// Define the codon table
struct CodonTable codon_table[] = {
{"TTT", 'F'}, {"TTC", 'F'}, {"TTA", 'L'}, {"TTG", 'L'},
{"TCT", 'S'}, {"TCC", 'S'}, {"TCA", 'S'}, {"TCG", 'S'},
{"TAT", 'Y'}, {"TAC", 'Y'}, {"TAA", '*'}, {"TAG", '*'},
{"TGT", 'C'}, {"TGC", 'C'}, {"TGA", '*'}, {"TGG", 'W'},
{"CTT", 'L'}, {"CTC", 'L'}, {"CTA", 'L'}, {"CTG", 'L'},
{"CCT", 'P'}, {"CCC", 'P'}, {"CCA", 'P'}, {"CCG", 'P'},
{"CAT", 'H'}, {"CAC", 'H'}, {"CAA", 'Q'}, {"CAG", 'Q'},
{"CGT", 'R'}, {"CGC", 'R'}, {"CGA", 'R'}, {"CGG", 'R'},
{"ATT", 'I'}, {"ATC", 'I'}, {"ATA", 'I'}, {"ATG", 'M'},
{"ACT", 'T'}, {"ACC", 'T'}, {"ACA", 'T'}, {"ACG", 'T'},
{"AAT", 'N'}, {"AAC", 'N'}, {"AAA", 'K'}, {"AAG", 'K'},
{"AGT", 'S'}, {"AGC", 'S'}, {"AGA", 'R'}, {"AGG", 'R'},
{"GTT", 'V'}, {"GTC", 'V'}, {"GTA", 'V'}, {"GTG", 'V'},
{"GCT", 'A'}, {"GCC", 'A'}, {"GCA", 'A'}, {"GCG", 'A'},
{"GAT", 'D'}, {"GAC", 'D'}, {"GAA", 'E'}, {"GAG", 'E'},
{"GGT", 'G'}, {"GGC", 'G'}, {"GGA", 'G'}, {"GGG", 'G'},
};

int main() {
FILE *fp;
char filename[] = "dna_sequence.txt";
char dna_sequence[1000];
int i, length;
int nucleotide_counts[4] = {0}; // A, T, C, G
char complementary_dna[1000];
char protein_sequence[1000];

// Read the DNA sequence from the file
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Error opening file.\n");
return 1;
}
fscanf(fp, "%s", dna_sequence);
fclose(fp);

// Calculate the length of the DNA sequence
length = strlen(dna_sequence);

// Count the occurrences of each nucleotide
for (i = 0; i < length; i++) {
switch (dna_sequence[i]) {
case 'A':
nucleotide_counts[0]++;
complementary_dna[i] = 'T';
break;
case 'T':
nucleotide_counts[1]++;
complementary_dna[i] = 'A';
break;
case 'C':
nucleotide_counts[2]++;
complementary_dna[i] = 'G';
break;
case 'G':
nucleotide_counts[3]++;
complementary_dna[i] = 'C';
break;
default:
break;
}
}
complementary_dna[length] = '\0'; // Add null terminator

// Translate the DNA sequence into a protein sequence
for (i = 0; i < length - 2; i += 3) {
char codon[4];
strncpy(codon, dna_sequence + i, 3);
codon[3] = '\0'; // Add null terminator

char amino_acid = '*'; // Default to stop codon
for (int j = 0; j < sizeof(codon_table) / sizeof(struct CodonTable); j++) {
if (strcmp(codon, codon_table[j].codon) == 0) {
amino_acid = codon_table[j].amino_acid;
break;
}
}
protein_sequence[i / 3] = amino_acid;
}
protein_sequence[length / 3] = '\0'; // Add null terminator

// Display the results
printf("Original DNA sequence: %s\n", dna_sequence);
printf("Length of DNA sequence: %d\n", length);
printf("Nucleotide counts (A T C G): %d %d %d %d\n", nucleotide_counts[0], nucleotide_counts[1], nucleotide_counts[2], nucleotide_counts[3]);
printf("Complementary DNA sequence: %s\n", complementary_dna);
printf("Protein sequence: %s\n", protein_sequence);

return 0;
}

This program reads a DNA sequence from a file, calculates its length, counts the occurrences of each nucleotide, determines the complementary DNA sequence, and translates the DNA sequence into a protein sequence using a codon table. Make sure to create a file named “dna_sequence.txt” containing a valid DNA sequence before running the program.

Shares