0% found this document useful (0 votes)
21 views36 pages

Ip Notes

The document is a comprehensive study guide for C programming, covering key topics such as arrays, pointers, functions, strings, structures, unions, and file handling. It provides detailed explanations, code examples, and best practices for each topic, including array operations, pointer arithmetic, and memory management. Additionally, it highlights common pitfalls and offers insights into using multidimensional arrays and pointers effectively.

Uploaded by

SwethaRouthu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views36 pages

Ip Notes

The document is a comprehensive study guide for C programming, covering key topics such as arrays, pointers, functions, strings, structures, unions, and file handling. It provides detailed explanations, code examples, and best practices for each topic, including array operations, pointer arithmetic, and memory management. Additionally, it highlights common pitfalls and offers insights into using multidimensional arrays and pointers effectively.

Uploaded by

SwethaRouthu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

C Programming Language

JNTUGV B. Tech. R23 Regulations

Units III, IV & V - Comprehensive Study Guide

Table of Contents

UNIT-III: Arrays and Pointers

Arrays: Introduction, Operations, Function Arguments, 2D Arrays, Multidimensional Arrays

Pointers: Concept, Declaration, Address Arithmetic, Dynamic Memory Allocation

UNIT-IV: Functions and Strings

Functions: Declaration, Definition, Categories, Scope, Storage Classes, Recursion

Strings: Fundamentals, Processing, Library Functions

UNIT-V: Structures, Unions, and File Handling

Structures: Nested, Arrays, Self-Referential

Unions, Enums, Typedef, Bit Fields

File Operations: Reading, Writing, Random Access

UNIT-III: ARRAYS AND POINTERS

Arrays

Introduction to Arrays

An array is a collection of elements of the same data type stored in contiguous memory locations. Arrays provide

a way to store multiple values under a single variable name, accessed using an index.
Array Declaration and Initialization

// Declaration
int numbers[5]; // Array of 5 integers

// Declaration with initialization


int scores[5] = {85, 92, 78, 96, 88};

// Size determined by initializer


int grades[] = {90, 85, 78, 92}; // Size is 4

// Partial initialization
int marks[10] = {85, 90}; // First two elements initialized, rest are

Memory Layout:
For int arr[5] = {10, 20, 30, 40, 50};

Memory addresses: 1000, 1004, 1008, 1012, 1016

Values: [10] [20] [30] [40] [50]

Index: 0 1 2 3 4

Operations on Arrays

Basic Array Operations

#include <stdio.h>

int main() {
int arr[5] = {10, 20, 30, 40, 50};
int sum = 0, max, min;

// Accessing elements
printf("First element: %d\n", arr[0]);
printf("Last element: %d\n", arr[4]);

// Calculating sum
for(int i = 0; i < 5; i++) {
sum += arr[i];
}
printf("Sum: %d\n", sum);

// Finding maximum and minimum


max = min = arr[0];
for(int i = 1; i < 5; i++) {
if(arr[i] > max) max = arr[i];
if(arr[i] < min) min = arr[i];
}
printf("Max: %d, Min: %d\n", max, min);

return 0;
}

Output:
First element: 10
Last element: 50
Sum: 150
Max: 50, Min: 10

Array Searching and Sorting

#include <stdio.h>

// Linear Search
int linearSearch(int arr[], int size, int key) {
for(int i = 0; i < size; i++) {
if(arr[i] == key) return i;
}
return -1;
}

// Bubble Sort
void bubbleSort(int arr[], int size) {
for(int i = 0; i < size-1; i++) {
for(int j = 0; j < size-i-1; j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}

int main() {
int numbers[] = {64, 34, 25, 12, 22, 11, 90};
int size = sizeof(numbers) / sizeof(numbers[0]);

printf("Original array: ");


for(int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}

bubbleSort(numbers, size);

printf("\nSorted array: ");


for(int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}

int index = linearSearch(numbers, size, 25);


printf("\nElement 25 found at index: %d\n", index);

return 0;
}

Arrays as Function Arguments

When arrays are passed to functions, they are passed by reference (address of first element), not by value.

#include <stdio.h>

// Method 1: Array parameter


void printArray1(int arr[], int size) {
for(int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

// Method 2: Pointer parameter


void printArray2(int *arr, int size) {
for(int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

// Method 3: Fixed size array (less flexible)


void printArray3(int arr[5]) {
for(int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

// Modifying array elements


void doubleArray(int arr[], int size) {
for(int i = 0; i < size; i++) {
arr[i] *= 2;
}
}

int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = 5;

printf("Original array: ");


printArray1(numbers, size);

doubleArray(numbers, size);

printf("After doubling: ");


printArray2(numbers, size);

return 0;
}

Best Practices for Arrays:

Always pass array size as a separate parameter to functions

Use symbolic constants or macros for array sizes

Initialize arrays when declaring them

Check array bounds to avoid buffer overflow

Use meaningful variable names for array indices

Two-Dimensional Arrays

Two-dimensional arrays are arrays of arrays, commonly used to represent matrices, tables, or grids.

#include <stdio.h>

int main() {
// Declaration and initialization
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

// Alternative initialization
int matrix2[2][3] = {{1, 2, 3}, {4, 5, 6}};

// Accessing elements
printf("Element at [1][2]: %d\n", matrix[1][2]);

// Printing the matrix


printf("Matrix:\n");
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 4; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}

// Row and column sums


printf("\nRow sums: ");
for(int i = 0; i < 3; i++) {
int rowSum = 0;
for(int j = 0; j < 4; j++) {
rowSum += matrix[i][j];
}
printf("%d ", rowSum);
}

printf("\nColumn sums: ");


for(int j = 0; j < 4; j++) {
int colSum = 0;
for(int i = 0; i < 3; i++) {
colSum += matrix[i][j];
}
printf("%d ", colSum);
}

return 0;
}

Matrix Operations

#include <stdio.h>

// Matrix Addition
void addMatrices(int a[][3], int b[][3], int result[][3], int rows, int
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
result[i][j] = a[i][j] + b[i][j];
}
}
}
// Matrix Multiplication
void multiplyMatrices(int a[][3], int b[][3], int result[][3], int r1,
for(int i = 0; i < r1; i++) {
for(int j = 0; j < c2; j++) {
result[i][j] = 0;
for(int k = 0; k < c1; k++) {
result[i][j] += a[i][k] * b[k][j];
}
}
}
}

// Transpose Matrix
void transposeMatrix(int matrix[][3], int result[][3], int rows, int co
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
result[j][i] = matrix[i][j];
}
}
}

int main() {
int mat1[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int mat2[3][3] = {{9, 8, 7}, {6, 5, 4}, {3, 2, 1}};
int result[3][3];

addMatrices(mat1, mat2, result, 3, 3);

printf("Matrix Addition Result:\n");


for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
printf("%4d", result[i][j]);
}
printf("\n");
}

return 0;
}

Multidimensional Arrays

C supports arrays with more than two dimensions. Three-dimensional arrays are commonly used for representing

3D grids or multiple 2D arrays.

#include <stdio.h>

int main() {
// 3D array: [depth][rows][columns]
int cube[2][3][4];
int count = 1;

// Initialize 3D array
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 4; k++) {
cube[i][j][k] = count++;
}
}
}

// Display 3D array
printf("3D Array:\n");
for(int i = 0; i < 2; i++) {
printf("Layer %d:\n", i);
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 4; k++) {
printf("%4d", cube[i][j][k]);
}
printf("\n");
}
printf("\n");
}

return 0;
}

Common Array Pitfalls:

Array bounds violation: Accessing elements beyond array size

Uninitialized arrays: Using arrays without proper initialization

Passing arrays incorrectly: Forgetting to pass size parameter

Index confusion: Using 1-based indexing instead of 0-based

Size miscalculation: Wrong calculation of array size in functions

Pointers

Concept of a Pointer
A pointer is a variable that stores the memory address of another variable. Pointers provide a way to indirectly

access and manipulate data through memory addresses.

Pointer Concept:
Variable 'x' at address 1000 contains value 42

Pointer 'ptr' at address 2000 contains value 1000 (address of x)

*ptr gives us the value 42 (dereferencing)

Declaring and Initializing Pointer Variables

#include <stdio.h>

int main() {
int x = 42;
int y = 100;

// Pointer declaration and initialization


int *ptr = &x; // ptr points to x

// Alternative declaration
int *ptr2;
ptr2 = &y; // ptr2 points to y

printf("Value of x: %d\n", x);


printf("Address of x: %p\n", (void*)&x);
printf("Value stored in ptr: %p\n", (void*)ptr);
printf("Value pointed by ptr: %d\n", *ptr);

// Pointer arithmetic
printf("Size of int: %zu bytes\n", sizeof(int));
printf("Size of pointer: %zu bytes\n", sizeof(ptr));

// Modifying value through pointer


*ptr = 84;
printf("New value of x: %d\n", x);

return 0;
}

Output:
Value of x: 42
Address of x: 0x7fff5fbff6ac
Value stored in ptr: 0x7fff5fbff6ac
Value pointed by ptr: 42
Size of int: 4 bytes
Size of pointer: 8 bytes
New value of x: 84

Pointer Expressions and Address Arithmetic

#include <stdio.h>

int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // Points to first element

printf("Array elements using pointer arithmetic:\n");


for(int i = 0; i < 5; i++) {
printf("arr[%d] = %d, *(ptr+%d) = %d\n",
i, arr[i], i, *(ptr + i));
}

// Pointer increment and decrement


printf("\nPointer increment operations:\n");
ptr = arr;
printf("*ptr = %d\n", *ptr); // 10

ptr++; // Move to next element


printf("*ptr after ptr++: %d\n", *ptr); // 20

ptr += 2; // Move 2 elements forward


printf("*ptr after ptr+=2: %d\n", *ptr); // 40

ptr--; // Move one element back


printf("*ptr after ptr--: %d\n", *ptr); // 30

// Pointer comparison
int *ptr1 = &arr[2];
int *ptr2 = &arr[4];

printf("\nPointer comparison:\n");
printf("ptr1 < ptr2: %d\n", ptr1 < ptr2);
printf("Difference: %ld\n", ptr2 - ptr1);

return 0;
}

Null Pointers and Generic Pointers


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

int main() {
// Null pointer
int *nullPtr = NULL;

printf("Null pointer value: %p\n", (void*)nullPtr);

// Always check for null before dereferencing


if(nullPtr != NULL) {
printf("Value: %d\n", *nullPtr);
} else {
printf("Pointer is NULL, cannot dereference\n");
}

// Generic pointer (void*)


void *genericPtr;
int intVal = 42;
float floatVal = 3.14f;
char charVal = 'A';

// Generic pointer can point to any data type


genericPtr = &intVal;
printf("Generic pointer to int: %d\n", *(int*)genericPtr);

genericPtr = &floatVal;
printf("Generic pointer to float: %.2f\n", *(float*)genericPtr);

genericPtr = &charVal;
printf("Generic pointer to char: %c\n", *(char*)genericPtr);

return 0;
}

Pointers as Function Arguments

#include <stdio.h>

// Pass by value (copy)


void swapByValue(int a, int b) {
int temp = a;
a = b;
b = temp;
printf("Inside swapByValue: a=%d, b=%d\n", a, b);
}
// Pass by reference (using pointers)
void swapByReference(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
printf("Inside swapByReference: a=%d, b=%d\n", *a, *b);
}

// Function to find maximum and minimum


void findMinMax(int arr[], int size, int *min, int *max) {
*min = *max = arr[0];
for(int i = 1; i < size; i++) {
if(arr[i] < *min) *min = arr[i];
if(arr[i] > *max) *max = arr[i];
}
}

int main() {
int x = 10, y = 20;

printf("Before swapByValue: x=%d, y=%d\n", x, y);


swapByValue(x, y);
printf("After swapByValue: x=%d, y=%d\n", x, y);

printf("\nBefore swapByReference: x=%d, y=%d\n", x, y);


swapByReference(&x, &y);
printf("After swapByReference: x=%d, y=%d\n", x, y);

// Using pointers to return multiple values


int numbers[] = {45, 23, 78, 12, 67, 34};
int min, max;

findMinMax(numbers, 6, &min, &max);


printf("\nMinimum: %d, Maximum: %d\n", min, max);

return 0;
}

Pointers and Arrays

Arrays and pointers have a close relationship in C. The array name is essentially a pointer to the first element.

#include <stdio.h>

int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // Same as &arr[0]

printf("Array name and pointer equivalence:\n");


printf("arr = %p\n", (void*)arr);
printf("&arr[0] = %p\n", (void*)&arr[0]);
printf("ptr = %p\n", (void*)ptr);

// Different ways to access array elements


printf("\nDifferent ways to access elements:\n");
for(int i = 0; i < 5; i++) {
printf("arr[%d] = %d, ", i, arr[i]);
printf("*(arr+%d) = %d, ", i, *(arr + i));
printf("ptr[%d] = %d, ", i, ptr[i]);
printf("*(ptr+%d) = %d\n", i, *(ptr + i));
}

// Pointer traversal
printf("\nUsing pointer to traverse array:\n");
ptr = arr;
for(int i = 0; i < 5; i++) {
printf("%d ", *ptr);
ptr++;
}
printf("\n");

return 0;
}

Pointer to Pointer

#include <stdio.h>

int main() {
int x = 100;
int *ptr = &x; // Pointer to int
int **pptr = &ptr; // Pointer to pointer to int

printf("Value relationships:\n");
printf("x = %d\n", x);
printf("*ptr = %d\n", *ptr);
printf("**pptr = %d\n", **pptr);

printf("\nAddress relationships:\n");
printf("Address of x: %p\n", (void*)&x);
printf("Value of ptr: %p\n", (void*)ptr);
printf("Address of ptr: %p\n", (void*)&ptr);
printf("Value of pptr: %p\n", (void*)pptr);
// Modifying value through double pointer
**pptr = 200;
printf("\nAfter **pptr = 200:\n");
printf("x = %d\n", x);

return 0;
}

Practical Example: Dynamic 2D Array

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

int main() {
int rows = 3, cols = 4;
int **matrix;

// Allocate memory for row pointers


matrix = (int**)malloc(rows * sizeof(int*));

// Allocate memory for each row


for(int i = 0; i < rows; i++) {
matrix[i] = (int*)malloc(cols * sizeof(int));
}

// Initialize matrix
int value = 1;
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
matrix[i][j] = value++;
}
}

// Print matrix
printf("Dynamic 2D Array:\n");
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}

// Free memory
for(int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}

Dynamic Memory Allocation

Dynamic memory allocation allows programs to request memory during runtime using malloc(), calloc(),

realloc(), and free() functions.

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

int main() {
int n;

printf("Enter number of elements: ");


scanf("%d", &n);

// malloc() - allocates uninitialized memory


int *arr1 = (int*)malloc(n * sizeof(int));
if(arr1 == NULL) {
printf("Memory allocation failed!\n");
return 1;
}

// calloc() - allocates zero-initialized memory


int *arr2 = (int*)calloc(n, sizeof(int));
if(arr2 == NULL) {
printf("Memory allocation failed!\n");
free(arr1);
return 1;
}

// Initialize arr1
for(int i = 0; i < n; i++) {
arr1[i] = i + 1;
}

printf("arr1 (malloc): ");


for(int i = 0; i < n; i++) {
printf("%d ", arr1[i]);
}

printf("\narr2 (calloc): ");


for(int i = 0; i < n; i++) {
printf("%d ", arr2[i]);
}
// realloc() - resize memory block
arr1 = (int*)realloc(arr1, (n + 5) * sizeof(int));
if(arr1 == NULL) {
printf("Reallocation failed!\n");
free(arr2);
return 1;
}

// Initialize new elements


for(int i = n; i < n + 5; i++) {
arr1[i] = i + 1;
}

printf("\narr1 after realloc: ");


for(int i = 0; i < n + 5; i++) {
printf("%d ", arr1[i]);
}
printf("\n");

// Free allocated memory


free(arr1);
free(arr2);

return 0;
}

Dynamic String Allocation

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

char* createString(const char* source) {


if(source == NULL) return NULL;

int length = strlen(source);


char* newString = (char*)malloc((length + 1) * sizeof(char));

if(newString != NULL) {
strcpy(newString, source);
}

return newString;
}

int main() {
char input[100];
printf("Enter a string: ");
fgets(input, sizeof(input), stdin);

// Remove newline if present


input[strcspn(input, "\n")] = '\0';

char* dynamicString = createString(input);

if(dynamicString != NULL) {
printf("Original: %s\n", input);
printf("Dynamic copy: %s\n", dynamicString);

// Modify dynamic string


strcat(dynamicString, " - Modified");
printf("After modification: %s\n", dynamicString);

free(dynamicString);
}

return 0;
}

Dangling Pointer

A dangling pointer points to memory that has been freed or is no longer valid. This can lead to undefined

behavior and program crashes.

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

void demonstrateDanglingPointer() {
int *ptr = (int*)malloc(sizeof(int));
*ptr = 42;

printf("Value: %d\n", *ptr);

free(ptr); // Memory is freed


// ptr is now a dangling pointer

// Dangerous! Accessing freed memory


// printf("After free: %d\n", *ptr); // Undefined behavior

// Good practice: Set pointer to NULL after freeing


ptr = NULL;

// Safe check before dereferencing


if(ptr != NULL) {
printf("Value: %d\n", *ptr);
} else {
printf("Pointer is NULL\n");
}
}

void demonstrateStackDangling() {
int *ptr;
{
int localVar = 100;
ptr = &localVar;
printf("Inside block: %d\n", *ptr);
}
// localVar is out of scope, ptr is dangling
// printf("Outside block: %d\n", *ptr); // Dangerous!
}

int main() {
printf("Demonstrating dangling pointer after free:\n");
demonstrateDanglingPointer();

printf("\nDemonstrating dangling pointer with local variables:\n");


demonstrateStackDangling();

return 0;
}

Command Line Arguments

Command line arguments allow programs to accept input from the command line when executed.

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

int main(int argc, char *argv[]) {


printf("Program name: %s\n", argv[0]);
printf("Number of arguments: %d\n", argc);

if(argc == 1) {
printf("No command line arguments provided.\n");
printf("Usage: %s <arg1> <arg2> ... <argN>\n", argv[0]);
return 1;
}

printf("Command line arguments:\n");


for(int i = 1; i < argc; i++) {
printf("argv[%d]: %s\n", i, argv[i]);
}

// Example: Simple calculator


if(argc == 4) {
double num1 = atof(argv[1]);
char operator = argv[2][0];
double num2 = atof(argv[3]);
double result;

switch(operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if(num2 != 0) {
result = num1 / num2;
} else {
printf("Error: Division by zero!\n");
return 1;
}
break;
default:
printf("Error: Unknown operator %c\n", operator);
return 1;
}

printf("Result: %.2f %c %.2f = %.2f\n", num1, operator, num2, r


}

return 0;
}

Example Usage:
$ ./program 10.5 + 5.2
Program name: ./program
Number of arguments: 4
Command line arguments:
argv[1]: 10.5
argv[2]: +
argv[3]: 5.2
Result: 10.50 + 5.20 = 15.70
Best Practices for Pointers:

Always initialize pointers before use

Check for NULL before dereferencing pointers

Set pointers to NULL after freeing memory

Use const keyword for read-only data access

Avoid returning addresses of local variables

Free all dynamically allocated memory

Use tools like Valgrind to detect memory leaks

Common Pointer Pitfalls:


Null pointer dereferencing: Accessing NULL pointers

Memory leaks: Forgetting to free allocated memory

Double free: Calling free() twice on same memory

Buffer overflow: Writing beyond allocated memory

Dangling pointers: Using pointers to freed memory

Wild pointers: Using uninitialized pointers

UNIT-IV: FUNCTIONS AND STRINGS

Functions

Introduction to Functions

A function is a self-contained block of code that performs a specific task. Functions promote code reusability,

modularity, and easier maintenance.

Function Declaration, Definition, and Call


#include <stdio.h>

// Function Declaration (Prototype)


int add(int a, int b);
void greet(void);
float calculateArea(float radius);

// Function Definition
int add(int a, int b) {
return a + b;
}

void greet(void) {
printf("Hello, World!\n");
}

float calculateArea(float radius) {


const float PI = 3.14159;
return PI * radius * radius;
}

int main() {
// Function Calls
greet();

int sum = add(10, 20);


printf("Sum: %d\n", sum);

float area = calculateArea(5.0);


printf("Area of circle: %.2f\n", area);

return 0;
}

Output:
Hello, World!
Sum: 30
Area of circle: 78.54

Categories of Functions

1. Functions with No Arguments and No Return Value


void displayMenu(void) {
printf("1. Add\n");
printf("2. Subtract\n");
printf("3. Multiply\n");
printf("4. Divide\n");
printf("5. Exit\n");
}

2. Functions with Arguments but No Return Value

void printPattern(int rows) {


for(int i = 1; i <= rows; i++) {
for(int j = 1; j <= i; j++) {
printf("* ");
}
printf("\n");
}
}

3. Functions with No Arguments but Return Value

int getRandomNumber(void) {
return rand() % 100 + 1; // Random number between 1-100
}

4. Functions with Arguments and Return Value

double power(double base, int exponent) {


double result = 1.0;
for(int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}

Passing Parameters to Functions


Pass by Value

#include <stdio.h>

void passByValue(int x) {
x = 100; // Changes local copy only
printf("Inside function: x = %d\n", x);
}

int main() {
int num = 50;
printf("Before function call: num = %d\n", num);
passByValue(num);
printf("After function call: num = %d\n", num);
return 0;
}

Pass by Reference (using pointers)

#include <stdio.h>

void passByReference(int *x) {


*x = 100; // Changes original value
printf("Inside function: *x = %d\n", *x);
}

int main() {
int num = 50;
printf("Before function call: num = %d\n", num);
passByReference(&num);
printf("After function call: num = %d\n", num);
return 0;
}

Array as Function Parameter

#include <stdio.h>

// Arrays are always passed by reference


void modifyArray(int arr[], int size) {
for(int i = 0; i < size; i++) {
arr[i] *= 2;
}
}

void printArray(const int arr[], int size) {


for(int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

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

printf("Original array: ");


printArray(numbers, size);

modifyArray(numbers, size);

printf("Modified array: ");


printArray(numbers, size);

return 0;
}

Scope of Variables

#include <stdio.h>

int globalVar = 100; // Global scope

void demonstrateScope() {
int localVar = 200; // Local scope
static int staticVar = 300; // Static local scope

printf("Inside function:\n");
printf("Global variable: %d\n", globalVar);
printf("Local variable: %d\n", localVar);
printf("Static variable: %d\n", staticVar);

globalVar++;
localVar++;
staticVar++;
}

int main() {
int localVar = 400; // Different local variable

printf("In main:\n");
printf("Global variable: %d\n", globalVar);
printf("Local variable in main: %d\n", localVar);

demonstrateScope();
demonstrateScope(); // Call again to see static behavior

printf("\nAfter function calls:\n");


printf("Global variable: %d\n", globalVar);
printf("Local variable in main: %d\n", localVar);

return 0;
}

Variable Storage Classes

Storage Class Keyword Scope Lifetime Default Value

Automatic auto Block Within block Garbage

Register register Block Within block Garbage

Static static Block/File Program lifetime 0

External extern Global Program lifetime 0

#include <stdio.h>

// External/Global storage
int globalCounter = 0;

void storageClassDemo() {
// Automatic storage (default for local variables)
auto int autoVar = 10;

// Register storage (hint to compiler)


register int regVar = 20;

// Static storage
static int staticVar = 30;

printf("Auto: %d, Register: %d, Static: %d\n",


autoVar, regVar, staticVar);

autoVar++;
regVar++;
staticVar++;
globalCounter++;
}

int main() {
printf("Storage class demonstration:\n");

for(int i = 0; i < 3; i++) {


printf("Call %d: ", i + 1);
storageClassDemo();
}

printf("Global counter: %d\n", globalCounter);

return 0;
}

Recursion

Recursion is a programming technique where a function calls itself to solve a problem by breaking it into smaller

subproblems.

Basic Recursive Functions

#include <stdio.h>

// Factorial calculation
unsigned long long factorial(int n) {
if(n == 0 || n == 1) {
return 1; // Base case
}
return n * factorial(n - 1); // Recursive case
}

// Fibonacci sequence
int fibonacci(int n) {
if(n <= 1) {
return n; // Base cases: fib(0)=0, fib(1)=1
}
return fibonacci(n - 1) + fibonacci(n - 2);
}

// Power calculation
double power(double base, int exponent) {
if(exponent == 0) {
return 1.0; // Base case
}
if(exponent < 0) {
return 1.0 / power(base, -exponent);
}
return base * power(base, exponent - 1);
}

// Sum of digits
int sumOfDigits(int n) {
if(n == 0) {
return 0; // Base case
}
return (n % 10) + sumOfDigits(n / 10);
}

int main() {
int n = 5;

printf("Factorial of %d: %llu\n", n, factorial(n));

printf("Fibonacci sequence: ");


for(int i = 0; i < 10; i++) {
printf("%d ", fibonacci(i));
}
printf("\n");

printf("2^8 = %.0f\n", power(2, 8));


printf("Sum of digits of 12345: %d\n", sumOfDigits(12345));

return 0;
}

Advanced Recursive Examples

#include <stdio.h>

// Tower of Hanoi
void towerOfHanoi(int n, char from, char to, char aux) {
if(n == 1) {
printf("Move disk 1 from %c to %c\n", from, to);
return;
}

towerOfHanoi(n - 1, from, aux, to);


printf("Move disk %d from %c to %c\n", n, from, to);
towerOfHanoi(n - 1, aux, to, from);
}

// Binary search (recursive)


int binarySearch(int arr[], int left, int right, int target) {
if(left > right) {
return -1; // Element not found
}

int mid = left + (right - left) / 2;

if(arr[mid] == target) {
return mid;
}

if(arr[mid] > target) {


return binarySearch(arr, left, mid - 1, target);
} else {
return binarySearch(arr, mid + 1, right, target);
}
}

// Greatest Common Divisor (GCD)


int gcd(int a, int b) {
if(b == 0) {
return a;
}
return gcd(b, a % b);
}

int main() {
printf("Tower of Hanoi with 3 disks:\n");
towerOfHanoi(3, 'A', 'C', 'B');

int arr[] = {2, 5, 8, 12, 16, 23, 38, 45, 67, 78};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 23;

int result = binarySearch(arr, 0, n - 1, target);


if(result != -1) {
printf("\nElement %d found at index %d\n", target, result);
} else {
printf("\nElement %d not found\n", target);
}

printf("GCD of 48 and 18: %d\n", gcd(48, 18));

return 0;
}

Best Practices for Functions:

Use meaningful function names that describe their purpose

Keep functions small and focused on a single task

Always provide function prototypes


Use const for parameters that shouldn't be modified

Initialize variables before use

Avoid using global variables when possible

Document complex functions with comments

Strings

String Fundamentals

In C, strings are arrays of characters terminated by a null character ('\0'). C doesn't have a built-in string data

type, but provides extensive string manipulation functions.

String Declaration and Initialization

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

int main() {
// Different ways to declare and initialize strings

// Method 1: Character array with explicit size


char str1[20] = "Hello";

// Method 2: Character array without size


char str2[] = "World";

// Method 3: Character array initialized one by one


char str3[] = {'H', 'e', 'l', 'l', 'o', '\0'};

// Method 4: Pointer to string literal


char *str4 = "Programming";

// Method 5: Uninitialized array


char str5[50];
strcpy(str5, "Dynamic");

printf("str1: %s\n", str1);


printf("str2: %s\n", str2);
printf("str3: %s\n", str3);
printf("str4: %s\n", str4);
printf("str5: %s\n", str5);
// String properties
printf("\nString lengths:\n");
printf("Length of str1: %zu\n", strlen(str1));
printf("Size of str1: %zu\n", sizeof(str1));
printf("Length of str2: %zu\n", strlen(str2));
printf("Size of str2: %zu\n", sizeof(str2));

return 0;
}

String Processing without Library Functions

#include <stdio.h>

// Custom string length function


int stringLength(const char *str) {
int length = 0;
while(str[length] != '\0') {
length++;
}
return length;
}

// Custom string copy function


void stringCopy(char *dest, const char *src) {
int i = 0;
while(src[i] != '\0') {
dest[i] = src[i];
i++;
}
dest[i] = '\0';
}

// Custom string concatenation function


void stringConcat(char *dest, const char *src) {
int destLen = stringLength(dest);
int i = 0;

while(src[i] != '\0') {
dest[destLen + i] = src[i];
i++;
}
dest[destLen + i] = '\0';
}

// Custom string comparison function


int stringCompare(const char *str1, const char *str2) {
int i = 0;
while(str1[i] != '\0' && str2[i] != '\0') {
if(str1[i] < str2[i]) return -1;
if(str1[i] > str2[i]) return 1;
i++;
}

if(str1[i] == '\0' && str2[i] == '\0') return 0;


if(str1[i] == '\0') return -1;
return 1;
}

// Reverse a string
void stringReverse(char *str) {
int length = stringLength(str);
for(int i = 0; i < length / 2; i++) {
char temp = str[i];
str[i] = str[length - 1 - i];
str[length - 1 - i] = temp;
}
}

int main() {
char str1[100] = "Hello";
char str2[100] = "World";
char str3[100];

printf("Original strings:\n");
printf("str1: %s (length: %d)\n", str1, stringLength(str1));
printf("str2: %s (length: %d)\n", str2, stringLength(str2));

// String copy
stringCopy(str3, str1);
printf("\nAfter copying str1 to str3: %s\n", str3);

// String concatenation
stringConcat(str1, " ");
stringConcat(str1, str2);
printf("After concatenation: %s\n", str1);

// String comparison
int cmp = stringCompare("apple", "banana");
printf("Comparison result: %d\n", cmp);

// String reversal
char toReverse[] = "Programming";
printf("Before reversal: %s\n", toReverse);
stringReverse(toReverse);
printf("After reversal: %s\n", toReverse);

return 0;
}
String Processing with Library Functions

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

int main() {
char str1[100] = "Hello";
char str2[100] = "World";
char str3[100];
char str4[100] = " Programming in C ";

// Basic string functions


printf("String operations using library functions:\n");

// strlen() - string length


printf("Length of '%s': %zu\n", str1, strlen(str1));

// strcpy() - string copy


strcpy(str3, str1);
printf("Copied string: %s\n", str3);

// strcat() - string concatenation


strcat(str1, " ");
strcat(str1, str2);
printf("Concatenated string: %s\n", str1);

// strcmp() - string comparison


int result = strcmp("apple", "banana");
printf("strcmp('apple', 'banana'): %d\n", result);

// strchr() - find character


char *pos = strchr(str1, 'W');
if(pos != NULL) {
printf("Character 'W' found at position: %ld\n", pos - str1);
}

// strstr() - find substring


char *substr = strstr(str1, "World");
if(substr != NULL) {
printf("Substring 'World' found at position: %ld\n", substr - s
}

// Advanced string functions


printf("\nAdvanced string operations:\n");

// strncpy() - copy n characters


char partial[10];
strncpy(partial, str1, 5);
partial[5] = '\0';
printf("First 5 characters: %s\n", partial);
// strncat() - concatenate n characters
char limited[20] = "Hello";
strncat(limited, str2, 3);
printf("Limited concatenation: %s\n", limited);

// strncmp() - compare n characters


int partialCmp = strncmp("hello", "help", 3);
printf("strncmp('hello', 'help', 3): %d\n", partialCmp);

return 0;
}

String Manipulation Functions

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

// Convert string to uppercase


void toUpperCase(char *str) {
for(int i = 0; str[i]; i++) {
str[i] = toupper(str[i]);
}
}

// Convert string to lowercase


void toLowerCase(char *str) {
for(int i = 0; str[i]; i++) {
str[i] = tolower(str[i]);
}
}

// Remove leading and trailing whitespace


void trim(char *str) {
int start = 0, end = strlen(str) - 1;

// Find first non-whitespace character


while(isspace(str[start])) start++;

// Find last non-whitespace character


while(end >= start && isspace(str[end])) end--;

// Shift string
int i;
for(i = 0; start <= end; i++, start++) {
str[i] = str[start];
}
str[i] = '\0';
}

// Count words in a string


int countWords(const char *str) {
int count = 0;
int inWord = 0;

for(int i = 0; str[i]; i++) {


if(!isspace(str[i])) {
if(!inWord) {
count++;
inWord = 1;
}
} else {
inWord = 0;
}
}
return count;
}

int main() {
char text1[] = "Hello World Programming";
char text2[] = " C Programming Language ";
char text3[] = "The quick brown fox jumps over the lazy dog";

printf("Original: '%s'\n", text1);


toUpperCase(text1);
printf("Uppercase: '%s'\n", text1);

toLowerCase(text1);
printf("Lowercase: '%s'\n", text1);

printf("\nBefore trim: '%s'\n", text2);


trim(text2);
printf("After trim: '%s'\n", text2);

printf("\nWord count in '%s': %d\n", text3, countWords(text3));

return 0;
}
Pointers & Strings

String Names as Pointers:


The name of a character array (string) acts as a constant pointer to
its first element. (e.g., char s[] = "world"; then s is equivalent
to &s[0]).

String Pointers:
A character pointer can point to a string literal or the first
character of a character array.
char *p = "Hello"; (points to a string literal, generally read-only).
char arr[] = "World"; char *p = arr; (points to a modifiable character
array).

Accessing String Characters:


Pointers can be used to traverse and access individual characters with
in a string.

printf("%c", *p); (prints the character at the address p points to).


printf("%c", *(p + i)); (prints the character at i positions after p).

String Manipulation with Pointers:

Functions like strcpy, strcat, strlen, strcmp often utilize pointers for
efficient string manipulation.
Difference between char arr[] and char *ptr for strings:
char arr[] declares a character array where the string content is stored
directly in the array's memory. arr itself is a constant pointer to the
beginning of this array.
char *ptr declares a pointer variable that stores the address of a
string. This string can be a literal (read-only) or another character
array. The pointer ptr can be reassigned to point to different strings.

You might also like