C Programming for Problem Solving: A Comprehensive Guide
March 30, 2024Table 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:
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:
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
:
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:
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:
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:
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:
- 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. - String Manipulation: Functions like
strcpy
(string copy),strcat
(string concatenation), andstrcmp
(string comparison) all require null-terminated strings to work correctly. These functions assume that the strings end with a null character. - 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. - 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:
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:
- strlen: Calculates the length of a string.c
size_t strlen(const char *str);
- strcpy: Copies a string.c
char *strcpy(char *dest, const char *src);
- strcat: Concatenates two strings.c
char *strcat(char *dest, const char *src);
- strcmp: Compares two strings.c
int strcmp(const char *str1, const char *str2);
- strchr: Finds the first occurrence of a character in a string.c
char *strchr(const char *str, int c);
- strstr: Finds the first occurrence of a substring in a string.c
char *strstr(const char *haystack, const char *needle);
- strtok: Splits a string into tokens based on a delimiter.c
char *strtok(char *str, const char *delim);
- sprintf: Formats a string into a buffer.c
int sprintf(char *str, const char *format, ...);
- 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:
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:
- 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 typeint
. The variablex
is not yet initialized and may contain garbage value if used without initialization. - 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 value5
. 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:
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:
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:
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:
- 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
- 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
- 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
- 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
- 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:
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:
- 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
- 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
- Array Indexing: Array indexing is a shorthand notation for pointer arithmetic.
arr[i]
is equivalent to*(arr + i)
:cint x = arr[2]; // Equivalent to *(arr + 2)
- 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;
}
- 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:cint 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:
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.
- 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, andmatrix[0]
refers to the first row of the matrix. - 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. - 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 toptr
. - 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 toarr
.
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:
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:
- 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:
cint *ptr = (int *)malloc(5 * sizeof(int));
- 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:
cint *ptr = (int *)calloc(5, sizeof(int));
- 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:
cptr = (int *)realloc(ptr, 10 * sizeof(int));
- free: Frees a block of memory previously allocated with
malloc
,calloc
, orrealloc
.cvoid free(void *ptr);
Example:
cfree(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:
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:
// 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:
// 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:
// 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:
// 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:
- Initializing Structures: You can initialize a structure at the time of declaration or later using the dot (
.
) operator. For example:cstruct Point {
int x;
int y;
};struct Point p1 = {10, 20}; // Initializing at declaration
struct Point p2;
p2.x = 30; // Initializing later
p2.y = 40;
- Accessing Structure Members: You can access structure members using the dot (
.
) operator. For example:cprintf("p1.x = %d, p1.y = %d\n", p1.x, p1.y);
- 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
- 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:
// 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:
// 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:
// 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 = ▭
// 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:
// 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:
// 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:
// 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:
// 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:
- 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.
- 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.
- 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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 = #
// 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:
// 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 = #
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
// 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:
- Opening a File (
fopen
): To open a file, you use thefopen
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).cFILE *file = fopen("example.txt", "w");
- Writing to a File (
fprintf
): To write to a file, you use thefprintf
function, which works similar toprintf
but takes an additional argument for the file pointer.cfprintf(file, "Hello, world!\n");
- Reading from a File (
fscanf
): To read from a file, you use thefscanf
function, which works similar toscanf
but takes an additional argument for the file pointer.cchar buffer[255];
fscanf(file, "%s", buffer);
- Closing a File (
fclose
): It’s important to close a file when you’re done using it to free up system resources. You use thefclose
function to close a file.cfclose(file);
Here’s a complete example that demonstrates writing and reading from a file:
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:
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:
- stdin (Standard Input): This stream is used for reading input from the user (e.g., keyboard). It is associated with the file pointer
stdin
. - stdout (Standard Output): This stream is used for writing output to the console. It is associated with the file pointer
stdout
. - 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:
./program > output.txt
Here’s an example program that demonstrates the use of streams:
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:
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:
- Opening a Stream (
fopen
): To open a file stream for reading or writing, you use thefopen
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).cFILE *file = fopen("example.txt", "w");
if (file == NULL) {
perror("Failed to open file");
return 1;
}
- Closing a Stream (
fclose
): It’s important to close a stream when you’re done using it to free up system resources. You use thefclose
function to close a stream.cif (fclose(file) != 0) {
perror("Failed to close file");
return 1;
}
Here’s a complete example that demonstrates opening and closing a file stream:
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:
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:
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:
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:
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:
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:
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:
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:
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”:
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:
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”:
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:
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:
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.
- 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. - 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:
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:
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:
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:
- Read a DNA sequence from a file.
- Calculate the length of the DNA sequence.
- Count the occurrences of each nucleotide (A, T, C, G) in the DNA sequence.
- Determine the complementary DNA sequence.
- Translate the DNA sequence into a protein sequence using a codon table.
Steps:
- Read the DNA sequence from a file into a character array using file handling.
- Calculate the length of the DNA sequence using strings.
- Count the occurrences of each nucleotide using arrays and pointers.
- Determine the complementary DNA sequence by replacing each nucleotide with its complementary base (A → T, T → A, C → G, G → C).
- Translate the DNA sequence into a protein sequence using a codon table (you can define a structure or a union for the codon table).
- Display the original DNA sequence, its length, nucleotide counts, complementary DNA sequence, and the translated protein sequence.
Sample Codon Table (using a structure):
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:
- Introduction: Brief overview of DNA sequence analysis and its significance in bioinformatics.
- Materials and Methods: Description of the C programming concepts used and the approach for sequence analysis.
- Results: Display of the original DNA sequence, its length, nucleotide counts, complementary DNA sequence, and the translated protein sequence.
- Discussion: Interpretation of the results, including the importance of understanding DNA sequence information in biological research.
- 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:
// 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.