Complete Guide to C Programming Language
www.prepcampus.co
C is a powerful general-purpose programming language created by Dennis Ritchie at Bell Labs in 1972. It is one of the most widely used programming languages and serves as the foundation for many other languages like C++, Java, Python, and JavaScript. C was originally developed to write the UNIX operating system, and its design philosophy emphasizes simplicity, efficiency, and close-to-hardware programming capabilities.
Every C program follows a specific structure that consists of several essential components. Understanding this structure is fundamental to writing C programs. The structure ensures that the program is organized, readable, and follows C language conventions.
// Include the standard input/output library
#include <stdio.h>
// Main function - program entry point
int main() {
// Print "Hello, World!" to the console
printf("Hello, World!\n");
// Return 0 to indicate successful execution
return 0;
}
Data types in C define the type of data that a variable can hold and how much memory space it will occupy. C is a statically-typed language, which means you must declare the data type of a variable before using it. Understanding data types is crucial for efficient memory usage and preventing data loss.
// Variable declaration and initialization with different data types
int age = 25; // Integer variable
float salary = 50000.50; // Single precision float
double pi = 3.14159265359; // Double precision for accuracy
char grade = 'A'; // Character variable
unsigned int count = 1000; // Unsigned integer (only positive)
const int MAX_SIZE = 100; // Constant (read-only)
Control structures in C allow you to control the flow of program execution based on conditions and create repetitive operations. They are fundamental building blocks that enable programs to make decisions and perform tasks repeatedly. Understanding control structures is essential for writing dynamic and interactive programs.
// Example of if-else statement with multiple conditions
int age = 18;
int income = 50000;
if (age >= 18 && income >= 30000) {
printf("You are eligible for a loan\n");
} else if (age >= 18) {
printf("You are an adult but income is too low\n");
} else {
printf("You are a minor\n");
}
// Switch statement for menu selection
int choice = 2;
switch (choice) {
case 1:
printf("Option 1 selected\n");
break;
case 2:
printf("Option 2 selected\n");
break;
case 3:
printf("Option 3 selected\n");
break;
default:
printf("Invalid option\n");
}
// For loop - when you know the number of iterations
for (int i = 0; i < 5; i++) {
printf("Iteration %d\n", i);
}
// While loop - when you don't know the number of iterations
int j = 0;
while (j < 5) {
printf("While iteration %d\n", j);
j++;
}
// Do-while loop - executes at least once
int k = 0;
do {
printf("Do-while iteration %d\n", k);
k++;
} while (k < 3);
Functions in C are blocks of code that perform specific tasks and can be called from other parts of the program. They are fundamental to structured programming and help in organizing code, reducing redundancy, and improving maintainability. Functions allow you to break down complex problems into smaller, manageable pieces.
// Function declaration (prototype)
int add(int a, int b);
void printMessage(char message[]);
// Function definition
int add(int a, int b) {
int result = a + b;
return result;
}
void printMessage(char message[]) {
printf("Message: %s\n", message);
}
// Function calls
int result = add(5, 3);
printMessage("Hello from function!");
// Example of different function types
// Function with arguments and return value
int multiply(int x, int y) {
return x * y;
}
// Function with arguments but no return value
void printResult(int value) {
printf("Result: %d\n", value);
}
// Function without arguments but with return value
int getRandomNumber() {
return rand() % 100;
}
// Function without arguments and no return value
void displayMenu() {
printf("1. Add\n2. Subtract\n3. Multiply\n4. Exit\n");
}
Arrays in C are collections of elements of the same data type stored in contiguous memory locations. They are one of the most fundamental and widely used data structures in C programming. Arrays provide an efficient way to store and access multiple values using a single variable name and an index.
Arrays are stored in memory as a continuous block. For example, if we have an integer array of size 5:
// Method 1: Declaration with size, then assignment
int numbers[5]; // Declares array of 5 integers (uninitialized)
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;
// Method 2: Declaration with initialization
int scores[5] = {85, 92, 78, 96, 88};
// Method 3: Size determined by initializer list
int values[] = {1, 2, 3, 4, 5}; // Size is 5
// Method 4: Partial initialization (remaining elements are 0)
int data[10] = {1, 2, 3}; // First 3 elements set, rest are 0
// Method 5: Character arrays (strings)
char name[20] = "John Doe"; // String literal initialization
char letters[] = {'A', 'B', 'C', '\0'}; // Character array
// Basic array traversal using for loop
int numbers[5] = {10, 20, 30, 40, 50};
// Forward traversal (index 0 to size-1)
for (int i = 0; i < 5; i++) {
printf("Element %d: %d\n", i, numbers[i]);
}
// Backward traversal (index size-1 to 0)
for (int i = 4; i >= 0; i--) {
printf("Element %d: %d\n", i, numbers[i]);
}
// Finding maximum value in array
int max = numbers[0]; // Assume first element is maximum
for (int i = 1; i < 5; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
printf("Maximum value: %d\n", max);
// Calculating sum of array elements
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += numbers[i];
}
printf("Sum of elements: %d\n", sum);
// Searching for an element
int searchValue = 30;
int found = 0; // Flag to indicate if found
int position = -1; // Position where element is found
for (int i = 0; i < 5; i++) {
if (numbers[i] == searchValue) {
found = 1;
position = i;
break; // Exit loop once found
}
}
if (found) {
printf("Element %d found at position %d\n", searchValue, position);
} else {
printf("Element %d not found\n", searchValue);
}
// 2D array declaration and initialization
int matrix[3][4] = {
{1, 2, 3, 4}, // Row 0
{5, 6, 7, 8}, // Row 1
{9, 10, 11, 12} // Row 2
};
// Accessing 2D array elements
printf("Element at [1][2]: %d\n", matrix[1][2]); // Prints 7
// Traversing 2D array (row by row)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n"); // New line after each row
}
// Traversing 2D array (column by column)
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 3; i++) {
printf("%d ", matrix[i][j]);
}
printf("\n"); // New line after each column
}
// Function to print array elements
void printArray(int arr[], int size) {
printf("Array elements: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// Function to find maximum element
int findMax(int arr[], int size) {
int max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
// Function to reverse array elements
void reverseArray(int arr[], int size) {
int start = 0;
int end = size - 1;
while (start < end) {
// Swap elements
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
printArray(numbers, 5);
int maxValue = findMax(numbers, 5);
printf("Maximum value: %d\n", maxValue);
reverseArray(numbers, 5);
printf("After reversing: ");
printArray(numbers, 5);
return 0;
}
Pointers are one of the most powerful and fundamental features of C programming. A pointer is a variable that stores the memory address of another variable. Pointers provide direct access to memory locations, enabling efficient memory manipulation, dynamic memory allocation, and complex data structures. Understanding pointers is crucial for advanced C programming and system-level development.
// Basic pointer declaration and usage
int number = 42; // Integer variable
int *ptr; // Pointer declaration
ptr = &number; // Assigning address of number to ptr
// Accessing values and addresses
printf("Value of number: %d\n", number); // Direct access
printf("Address of number: %p\n", &number); // Address of number
printf("Value pointed by ptr: %d\n", *ptr); // Indirect access
printf("Address stored in ptr: %p\n", ptr); // Address stored in ptr
// Modifying value through pointer
*ptr = 100; // Change value of number through ptr
printf("New value of number: %d\n", number); // Now 100
// Null pointer initialization
int *nullPtr = NULL; // Safe initialization
printf("Null pointer: %p\n", nullPtr);
// Array and pointer relationship
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr; // Array name is a pointer to first element
// Different ways to access array elements
printf("arr[0]: %d\n", arr[0]); // Array notation
printf("*ptr: %d\n", *ptr); // Pointer notation
printf("*(ptr+1): %d\n", *(ptr + 1)); // Pointer arithmetic
printf("ptr[1]: %d\n", ptr[1]); // Pointer with array notation
// Traversing array using pointer
for (int i = 0; i < 5; i++) {
printf("Element %d: %d\n", i, *(ptr + i));
}
// Pointer arithmetic
ptr++; // Move to next element
printf("After ptr++: %d\n", *ptr); // Now points to arr[1]
ptr += 2; // Move 2 elements forward
printf("After ptr+=2: %d\n", *ptr); // Now points to arr[3]
// Double pointer declaration and usage
int value = 42;
int *ptr1 = &value; // Pointer to int
int **ptr2 = &ptr1; // Pointer to pointer to int
// Accessing values through double pointer
printf("Value: %d\n", value); // Direct access
printf("Value through ptr1: %d\n", *ptr1); // Single dereference
printf("Value through ptr2: %d\n", **ptr2); // Double dereference
// Modifying value through double pointer
**ptr2 = 100; // Change value through double pointer
printf("New value: %d\n", value);
// Function that takes a pointer parameter
void modifyValue(int *ptr) {
*ptr = *ptr * 2; // Modify the value pointed to
printf("Inside function: %d\n", *ptr);
}
// Function that returns a pointer
int* getLarger(int *a, int *b) {
return (*a > *b) ? a : b; // Return pointer to larger value
}
int main() {
int x = 10, y = 20;
// Pass address to function
modifyValue(&x);
printf("After function call: %d\n", x);
// Get pointer to larger value
int *larger = getLarger(&x, &y);
printf("Larger value: %d\n", *larger);
return 0;
}
In C programming, strings are arrays of characters terminated by a null character ('\0'). Unlike some other programming languages, C doesn't have a built-in string data type. Instead, strings are implemented as character arrays, which makes string manipulation both powerful and potentially error-prone. Understanding string handling is essential for text processing, user input, and data manipulation.
#include <stdio.h>
#include <string.h>
// Different ways to declare and initialize strings
char str1[50] = "Hello World"; // With explicit size
char str2[] = "Programming"; // Size determined automatically
char str3[20]; // Uninitialized array
// Character-by-character initialization
char str4[] = {'C', ' ', 'L', 'a', 'n', 'g', 'u', 'a', 'g', 'e', '\0'};
// String length calculation
int len1 = strlen(str1); // Length of "Hello World" (11)
int len2 = strlen(str2); // Length of "Programming" (11)
printf("String 1: %s (Length: %d)\n", str1, len1);
printf("String 2: %s (Length: %d)\n", str2, len2);
printf("String 4: %s\n", str4);
// Accessing individual characters
printf("First character of str1: %c\n", str1[0]);
printf("Last character of str1: %c\n", str1[len1 - 1]);
printf("Null terminator: %d\n", str1[len1]);
// String input and output methods
char name[50];
// Method 1: Using scanf (stops at whitespace)
printf("Enter your first name: ");
scanf("%s", name);
printf("Hello, %s!\n", name);
// Method 2: Using gets (deprecated, unsafe)
// gets(name); // Avoid using gets()
// Method 3: Using fgets (safe, includes newline)
printf("Enter your full name: ");
fgets(name, sizeof(name), stdin);
printf("Full name: %s", name);
// Method 4: Using getchar() in a loop
char input[100];
int i = 0;
char ch;
printf("Enter a string (press Enter to finish): ");
while ((ch = getchar()) != '\n' && i < 99) {
input[i++] = ch;
}
input[i] = '\0'; // Add null terminator
printf("You entered: %s\n", input);
// String copying
char source[50] = "Source String";
char dest[50];
strcpy(dest, source); // Copy source to dest
printf("After strcpy: %s\n", dest);
// String concatenation
char str1[50] = "Hello";
char str2[50] = " World";
strcat(str1, str2); // Concatenate str2 to str1
printf("After strcat: %s\n", str1);
// String comparison
char s1[20] = "apple";
char s2[20] = "apple";
char s3[20] = "banana";
int result1 = strcmp(s1, s2); // Compare s1 and s2
int result2 = strcmp(s1, s3); // Compare s1 and s3
if (result1 == 0) {
printf("s1 and s2 are equal\n");
} else {
printf("s1 and s2 are not equal\n");
}
if (result2 < 0) {
printf("s1 comes before s3\n");
} else if (result2 > 0) {
printf("s1 comes after s3\n");
}
// String searching
char text[100] = "This is a sample text for searching";
char *found = strstr(text, "sample"); // Find substring
if (found != NULL) {
printf("Found 'sample' at position: %ld\n", found - text);
} else {
printf("'sample' not found\n");
}
// String tokenization (splitting)
char sentence[100] = "C programming is fun and powerful";
char *token = strtok(sentence, " "); // Split by space
printf("Tokens:\n");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, " "); // Continue with same string
}
// String conversion functions
char numStr[20] = "12345";
int number = atoi(numStr); // String to integer
printf("Converted number: %d\n", number);
float floatNum = atof("123.456"); // String to float
printf("Converted float: %.3f\n", floatNum);
// Number to string conversion
int value = 42;
char strValue[20];
sprintf(strValue, "%d", value); // Integer to string
printf("String value: %s\n", strValue);
// Case conversion
char mixed[50] = "Hello World 123";
printf("Original: %s\n", mixed);
// Convert to uppercase
for (int i = 0; mixed[i] != '\0'; i++) {
if (mixed[i] >= 'a' && mixed[i] <= 'z') {
mixed[i] = mixed[i] - 32; // Convert to uppercase
}
}
printf("Uppercase: %s\n", mixed);
Structures in C are user-defined data types that allow you to group different types of data under a single name. They are fundamental for creating complex data types and are essential for building real-world applications. Structures enable you to organize related data together, making your code more readable, maintainable, and efficient.
// Basic structure definition
struct Student {
int id; // Student ID
char name[50]; // Student name
float marks; // Student marks
char grade; // Student grade
};
// Different ways to declare structure variables
struct Student student1; // Declaration only
struct Student student2 = {101, "John Doe", 85.5, 'A'}; // Declaration with initialization
// Accessing and modifying structure members
student1.id = 102;
strcpy(student1.name, "Jane Smith");
student1.marks = 92.0;
student1.grade = 'A';
// Printing structure members
printf("Student 1: ID=%d, Name=%s, Marks=%.1f, Grade=%c\n",
student1.id, student1.name, student1.marks, student1.grade);
printf("Student 2: ID=%d, Name=%s, Marks=%.1f, Grade=%c\n",
student2.id, student2.name, student2.marks, student2.grade);
// Array of structures
struct Student class[5] = {
{101, "Alice", 85.5, 'A'},
{102, "Bob", 78.0, 'B'},
{103, "Charlie", 92.5, 'A'},
{104, "Diana", 67.0, 'C'},
{105, "Eve", 88.0, 'A'}
};
// Traversing array of structures
for (int i = 0; i < 5; i++) {
printf("Student %d: %s (ID: %d, Marks: %.1f, Grade: %c)\n",
i + 1, class[i].name, class[i].id, class[i].marks, class[i].grade);
}
// Structure pointers
struct Student *ptr = &student1; // Pointer to structure
// Accessing members through pointer (using arrow operator)
printf("Pointer access: ID=%d, Name=%s\n", ptr->id, ptr->name);
// Alternative way using dereference and dot operator
printf("Dereference access: ID=%d, Name=%s\n", (*ptr).id, (*ptr).name);
// Modifying structure through pointer
ptr->marks = 95.0;
printf("Updated marks: %.1f\n", student1.marks);
// Nested structure definition
struct Address {
char street[100];
char city[50];
char state[30];
int zipCode;
};
struct Employee {
int empId;
char name[50];
float salary;
struct Address address; // Nested structure
};
// Creating and initializing nested structure
struct Employee emp = {
1001,
"John Smith",
75000.0,
{"123 Main St", "New York", "NY", 10001}
};
// Accessing nested structure members
printf("Employee: %s\n", emp.name);
printf("Address: %s, %s, %s %d\n",
emp.address.street, emp.address.city, emp.address.state, emp.address.zipCode);
// Modifying nested structure members
strcpy(emp.address.city, "Los Angeles");
emp.address.zipCode = 90210;
printf("Updated address: %s, %s, %s %d\n",
emp.address.street, emp.address.city, emp.address.state, emp.address.zipCode);
// Function that takes structure as parameter (pass by value)
void printStudent(struct Student s) {
printf("Student Details:\n");
printf("ID: %d\n", s.id);
printf("Name: %s\n", s.name);
printf("Marks: %.1f\n", s.marks);
printf("Grade: %c\n", s.grade);
}
// Function that takes structure pointer (pass by reference)
void updateMarks(struct Student *s, float newMarks) {
s->marks = newMarks;
// Update grade based on marks
if (s->marks >= 90) s->grade = 'A';
else if (s->marks >= 80) s->grade = 'B';
else if (s->marks >= 70) s->grade = 'C';
else if (s->marks >= 60) s->grade = 'D';
else s->grade = 'F';
}
// Function that returns a structure
struct Student createStudent(int id, char name[], float marks) {
struct Student newStudent;
newStudent.id = id;
strcpy(newStudent.name, name);
newStudent.marks = marks;
// Determine grade
if (marks >= 90) newStudent.grade = 'A';
else if (marks >= 80) newStudent.grade = 'B';
else if (marks >= 70) newStudent.grade = 'C';
else if (marks >= 60) newStudent.grade = 'D';
else newStudent.grade = 'F';
return newStudent;
}
int main() {
// Using functions with structures
printStudent(student1);
updateMarks(&student1, 95.0);
printf("After update: Marks=%.1f, Grade=%c\n", student1.marks, student1.grade);
struct Student newStudent = createStudent(106, "Frank", 88.5);
printStudent(newStudent);
return 0;
}
File handling in C allows programs to read from and write to files on the disk. This is essential for data persistence, configuration management, and processing large datasets. C provides a comprehensive set of functions for file operations through the standard I/O library, making it possible to create, read, write, and manipulate files efficiently.
#include <stdio.h>
// Writing to a file
FILE *file = fopen("data.txt", "w");
// Check if file opened successfully
if (file == NULL) {
printf("Error opening file!\n");
return 1;
}
// Write data to file
fprintf(file, "Hello, File Handling!\n");
fprintf(file, "This is line 2\n");
fprintf(file, "Line 3 with number: %d\n", 42);
// Close the file
fclose(file);
printf("File written successfully!\n");
// Reading from a file
FILE *readFile = fopen("data.txt", "r");
if (readFile == NULL) {
printf("Error opening file for reading!\n");
return 1;
}
// Read and display file contents
char buffer[100];
printf("File contents:\n");
while (fgets(buffer, sizeof(buffer), readFile) != NULL) {
printf("%s", buffer);
}
fclose(readFile);
// Writing characters to file
FILE *charFile = fopen("characters.txt", "w");
if (charFile == NULL) {
printf("Error opening file!\n");
return 1;
}
// Write individual characters
fputc('H', charFile);
fputc('e', charFile);
fputc('l', charFile);
fputc('l', charFile);
fputc('o', charFile);
fputc('\n', charFile);
fclose(charFile);
// Reading characters from file
FILE *readCharFile = fopen("characters.txt", "r");
if (readCharFile == NULL) {
printf("Error opening file!\n");
return 1;
}
printf("Characters read: ");
int ch;
while ((ch = fgetc(readCharFile)) != EOF) {
printf("%c", ch);
}
printf("\n");
fclose(readCharFile);
// Creating a file with multiple lines
FILE *posFile = fopen("position.txt", "w+");
if (posFile == NULL) {
printf("Error opening file!\n");
return 1;
}
// Write some lines
fprintf(posFile, "Line 1: First line\n");
fprintf(posFile, "Line 2: Second line\n");
fprintf(posFile, "Line 3: Third line\n");
fprintf(posFile, "Line 4: Fourth line\n");
// Get current position
long currentPos = ftell(posFile);
printf("Current position: %ld\n", currentPos);
// Move to beginning of file
rewind(posFile);
printf("After rewind: %ld\n", ftell(posFile));
// Read first line
char line[100];
fgets(line, sizeof(line), posFile);
printf("First line: %s", line);
// Move to specific position (beginning of third line)
fseek(posFile, 30, SEEK_SET); // Move 30 bytes from beginning
fgets(line, sizeof(line), posFile);
printf("Line at position 30: %s", line);
// Move to end of file
fseek(posFile, 0, SEEK_END);
printf("File size: %ld bytes\n", ftell(posFile));
fclose(posFile);
// Structure for binary file operations
struct Person {
int id;
char name[50];
int age;
};
// Writing structures to binary file
FILE *binFile = fopen("people.dat", "wb");
if (binFile == NULL) {
printf("Error opening binary file!\n");
return 1;
}
// Create and write some person records
struct Person people[] = {
{1, "Alice", 25},
{2, "Bob", 30},
{3, "Charlie", 35}
};
fwrite(people, sizeof(struct Person), 3, binFile);
fclose(binFile);
// Reading structures from binary file
FILE *readBinFile = fopen("people.dat", "rb");
if (readBinFile == NULL) {
printf("Error opening binary file for reading!\n");
return 1;
}
struct Person person;
printf("People from binary file:\n");
while (fread(&person, sizeof(struct Person), 1, readBinFile) == 1) {
printf("ID: %d, Name: %s, Age: %d\n", person.id, person.name, person.age);
}
fclose(readBinFile);
// Comprehensive file handling with error checking
void checkFileStatus(FILE *file, const char *operation) {
if (ferror(file)) {
printf("Error during %s operation!\n", operation);
clearerr(file); // Clear error flag
}
if (feof(file)) {
printf("End of file reached during %s operation.\n", operation);
}
}
// Safe file operations
FILE *safeFile = fopen("safe.txt", "w");
if (safeFile == NULL) {
perror("Error opening file"); // Print system error message
return 1;
}
// Write with error checking
fprintf(safeFile, "Safe writing test\n");
checkFileStatus(safeFile, "write");
fclose(safeFile);
// Check if file exists before opening
FILE *testFile = fopen("nonexistent.txt", "r");
if (testFile == NULL) {
perror("File does not exist");
} else {
fclose(testFile);
}
Memory management in C is a critical aspect of programming that involves allocating, using, and deallocating memory dynamically during program execution. Unlike some high-level languages, C gives programmers direct control over memory allocation, which provides flexibility but also requires careful management to avoid memory leaks, buffer overflows, and other memory-related issues.
#include <stdio.h>
#include <stdlib.h>
// Allocating memory for a single integer
int *ptr = (int *)malloc(sizeof(int));
// Check if allocation was successful
if (ptr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
// Use the allocated memory
*ptr = 42;
printf("Value stored: %d\n", *ptr);
// Free the memory when done
free(ptr);
ptr = NULL; // Set pointer to NULL after freeing
// Allocating memory for an array
int size = 5;
int *arr = (int *)malloc(size * sizeof(int));
if (arr == NULL) {
printf("Array allocation failed!\n");
return 1;
}
// Initialize array elements
for (int i = 0; i < size; i++) {
arr[i] = i * 10;
}
// Print array elements
printf("Array elements: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Free array memory
free(arr);
arr = NULL;
// Using calloc for array allocation (initializes to zero)
int *callocArr = (int *)calloc(5, sizeof(int));
if (callocArr == NULL) {
printf("Calloc allocation failed!\n");
return 1;
}
// Calloc initializes all elements to zero
printf("Calloc array (should be all zeros): ");
for (int i = 0; i < 5; i++) {
printf("%d ", callocArr[i]);
}
printf("\n");
// Using realloc to resize memory
int *resizedArr = (int *)realloc(callocArr, 10 * sizeof(int));
if (resizedArr == NULL) {
printf("Realloc failed!\n");
free(callocArr); // Free original memory
return 1;
}
if (resizedArr != callocArr) {
printf("Memory was moved to new location\n");
callocArr = resizedArr; // Update pointer
}
// Initialize new elements
for (int i = 5; i < 10; i++) {
callocArr[i] = i * 10;
}
printf("Resized array: ");
for (int i = 0; i < 10; i++) {
printf("%d ", callocArr[i]);
}
printf("\n");
free(callocArr);
// Structure definition
struct Student {
int id;
char *name; // Dynamic string
float marks;
};
// Allocating memory for a structure
struct Student *student = (struct Student *)malloc(sizeof(struct Student));
if (student == NULL) {
printf("Student allocation failed!\n");
return 1;
}
// Allocating memory for the name string
student->name = (char *)malloc(50 * sizeof(char));
if (student->name == NULL) {
printf("Name allocation failed!\n");
free(student);
return 1;
}
// Initialize structure
student->id = 101;
strcpy(student->name, "John Doe");
student->marks = 85.5;
printf("Student: ID=%d, Name=%s, Marks=%.1f\n",
student->id, student->name, student->marks);
// Free memory in reverse order of allocation
free(student->name); // Free name first
free(student); // Then free structure
// Allocating array of structures
struct Student *students = (struct Student *)calloc(3, sizeof(struct Student));
if (students == NULL) {
printf("Students array allocation failed!\n");
return 1;
}
// Initialize array elements
for (int i = 0; i < 3; i++) {
students[i].id = 100 + i;
students[i].name = (char *)malloc(50);
sprintf(students[i].name, "Student %d", i + 1);
students[i].marks = 70 + i * 5;
}
// Print all students
for (int i = 0; i < 3; i++) {
printf("Student %d: ID=%d, Name=%s, Marks=%.1f\n",
i + 1, students[i].id, students[i].name, students[i].marks);
}
// Free all allocated memory
for (int i = 0; i < 3; i++) {
free(students[i].name);
}
free(students);
// Function to allocate and initialize an integer array
int* createIntArray(int size) {
int *arr = (int *)calloc(size, sizeof(int));
if (arr == NULL) {
printf("Failed to allocate array of size %d\n", size);
return NULL;
}
printf("Successfully allocated array of size %d\n", size);
return arr;
}
// Function to resize an integer array
int* resizeIntArray(int *arr, int oldSize, int newSize) {
int *newArr = (int *)realloc(arr, newSize * sizeof(int));
if (newArr == NULL) {
printf("Failed to resize array from %d to %d\n", oldSize, newSize);
return arr; // Return original array
}
printf("Successfully resized array from %d to %d\n", oldSize, newSize);
return newArr;
}
// Function to safely free memory
void safeFree(void **ptr) {
if (*ptr != NULL) {
free(*ptr);
*ptr = NULL; // Set pointer to NULL after freeing
printf("Memory freed successfully\n");
}
}
int main() {
// Test memory management functions
int *arr = createIntArray(5);
if (arr != NULL) {
// Initialize array
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
// Resize array
arr = resizeIntArray(arr, 5, 10);
if (arr != NULL) {
// Initialize new elements
for (int i = 5; i < 10; i++) {
arr[i] = i * 10;
}
// Print array
printf("Array contents: ");
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Free memory
safeFree((void **)&arr);
}
}
return 0;
}
This section provides practical examples of common programming problems and their solutions in C. These examples demonstrate the application of various C programming concepts including functions, arrays, pointers, control structures, and algorithms. Understanding these examples will help you develop problem-solving skills and become proficient in C programming.
// Recursive factorial function
int factorialRecursive(int n) {
// Base case: factorial of 0 or 1 is 1
if (n <= 1) {
return 1;
}
// Recursive case: n! = n * (n-1)!
return n * factorialRecursive(n - 1);
}
// Iterative factorial function
int factorialIterative(int n) {
int result = 1;
// Calculate factorial using loop
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// Test factorial functions
int main() {
int n = 5;
printf("Factorial of %d (recursive): %d\n", n, factorialRecursive(n));
printf("Factorial of %d (iterative): %d\n", n, factorialIterative(n));
return 0;
}
// Recursive Fibonacci function
int fibonacciRecursive(int n) {
// Base cases
if (n <= 1) {
return n;
}
// Recursive case: F(n) = F(n-1) + F(n-2)
return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
}
// Iterative Fibonacci function
int fibonacciIterative(int n) {
if (n <= 1) {
return n;
}
int prev = 0, current = 1, next;
for (int i = 2; i <= n; i++) {
next = prev + current;
prev = current;
current = next;
}
return current;
}
// Print Fibonacci series
void printFibonacciSeries(int n) {
printf("Fibonacci series up to %d terms: ", n);
for (int i = 0; i < n; i++) {
printf("%d ", fibonacciIterative(i));
}
printf("\n");
}
// Bubble sort implementation
void bubbleSort(int arr[], int n) {
int swapped;
for (int i = 0; i < n - 1; i++) {
swapped = 0; // Flag to optimize
// Compare adjacent elements
for (int j = 0; j < n - i - 1; j++) {
// Swap if current element is greater than next
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = 1;
}
}
// If no swapping occurred, array is sorted
if (swapped == 0) {
break;
}
}
}
// Function to print array
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// Selection sort implementation
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// Find minimum element in unsorted part
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// Swap minimum element with first element
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
// Linear search implementation
int linearSearch(int arr[], int n, int key) {
for (int i = 0; i < n; i++) {
if (arr[i] == key) {
return i; // Return index if found
}
}
return -1; // Return -1 if not found
}
// Binary search implementation (requires sorted array)
int binarySearch(int arr[], int left, int right, int key) {
while (left <= right) {
int mid = left + (right - left) / 2;
// If element is found at mid
if (arr[mid] == key) {
return mid;
}
// If element is greater than mid, ignore left half
if (arr[mid] < key) {
left = mid + 1;
}
// If element is smaller than mid, ignore right half
else {
right = mid - 1;
}
}
return -1; // Element not found
}
// Custom string length function
int stringLength(const char *str) {
int length = 0;
// Count characters until null terminator
while (str[length] != '\0') {
length++;
}
return length;
}
// String copy function
void stringCopy(char *dest, const char *src) {
int i = 0;
// Copy characters until null terminator
while (src[i] != '\0') {
dest[i] = src[i];
i++;
}
dest[i] = '\0'; // Add null terminator
}
// String reverse function
void stringReverse(char *str) {
int length = stringLength(str);
int start = 0;
int end = length - 1;
// Swap characters from start and end
while (start < end) {
char temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}
// Find maximum element in array
int findMax(int arr[], int n) {
int max = arr[0]; // Assume first element is maximum
for (int i = 1; i < n; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
// Find minimum element in array
int findMin(int arr[], int n) {
int min = arr[0]; // Assume first element is minimum
for (int i = 1; i < n; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
// Calculate sum of array elements
int arraySum(int arr[], int n) {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += arr[i];
}
return sum;
}
// Calculate average of array elements
float arrayAverage(int arr[], int n) {
int sum = arraySum(arr, n);
return (float)sum / n;
}
#include <stdio.h>
// Function declarations
void printArray(int arr[], int size);
void bubbleSort(int arr[], int n);
int linearSearch(int arr[], int n, int key);
int findMax(int arr[], int n);
int findMin(int arr[], int n);
float arrayAverage(int arr[], int n);
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Original array: ");
printArray(arr, n);
printf("Maximum element: %d\n", findMax(arr, n));
printf("Minimum element: %d\n", findMin(arr, n));
printf("Average: %.2f\n", arrayAverage(arr, n));
bubbleSort(arr, n);
printf("Sorted array: ");
printArray(arr, n);
int searchKey = 22;
int result = linearSearch(arr, n, searchKey);
if (result != -1) {
printf("Element %d found at index %d\n", searchKey, result);
} else {
printf("Element %d not found\n", searchKey);
}
return 0;
}