Ip Notes
Ip Notes
Table of Contents
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
// Partial initialization
int marks[10] = {85, 90}; // First two elements initialized, rest are
Memory Layout:
For int arr[5] = {10, 20, 30, 40, 50};
Index: 0 1 2 3 4
Operations on Arrays
#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);
return 0;
}
Output:
First element: 10
Last element: 50
Sum: 150
Max: 50, Min: 10
#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]);
bubbleSort(numbers, size);
return 0;
}
When arrays are passed to functions, they are passed by reference (address of first element), not by value.
#include <stdio.h>
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = 5;
doubleArray(numbers, size);
return 0;
}
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]);
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];
return 0;
}
Multidimensional Arrays
C supports arrays with more than two dimensions. Three-dimensional arrays are commonly used for representing
#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;
}
Pointers
Concept of a Pointer
A pointer is a variable that stores the memory address of another variable. Pointers provide a way to indirectly
Pointer Concept:
Variable 'x' at address 1000 contains value 42
#include <stdio.h>
int main() {
int x = 42;
int y = 100;
// Alternative declaration
int *ptr2;
ptr2 = &y; // ptr2 points to y
// Pointer arithmetic
printf("Size of int: %zu bytes\n", sizeof(int));
printf("Size of pointer: %zu bytes\n", sizeof(ptr));
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
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // Points to first element
// 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;
}
int main() {
// Null pointer
int *nullPtr = NULL;
genericPtr = &floatVal;
printf("Generic pointer to float: %.2f\n", *(float*)genericPtr);
genericPtr = &charVal;
printf("Generic pointer to char: %c\n", *(char*)genericPtr);
return 0;
}
#include <stdio.h>
int main() {
int x = 10, y = 20;
return 0;
}
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]
// 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;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
int **matrix;
// 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 allows programs to request memory during runtime using malloc(), calloc(),
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int n;
// Initialize arr1
for(int i = 0; i < n; i++) {
arr1[i] = i + 1;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
if(newString != NULL) {
strcpy(newString, source);
}
return newString;
}
int main() {
char input[100];
printf("Enter a string: ");
fgets(input, sizeof(input), stdin);
if(dynamicString != NULL) {
printf("Original: %s\n", input);
printf("Dynamic copy: %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
#include <stdio.h>
#include <stdlib.h>
void demonstrateDanglingPointer() {
int *ptr = (int*)malloc(sizeof(int));
*ptr = 42;
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();
return 0;
}
Command line arguments allow programs to accept input from the command line when executed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
if(argc == 1) {
printf("No command line arguments provided.\n");
printf("Usage: %s <arg1> <arg2> ... <argN>\n", argv[0]);
return 1;
}
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;
}
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:
Functions
Introduction to Functions
A function is a self-contained block of code that performs a specific task. Functions promote code reusability,
// Function Definition
int add(int a, int b) {
return a + b;
}
void greet(void) {
printf("Hello, World!\n");
}
int main() {
// Function Calls
greet();
return 0;
}
Output:
Hello, World!
Sum: 30
Area of circle: 78.54
Categories of Functions
int getRandomNumber(void) {
return rand() % 100 + 1; // Random number between 1-100
}
#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;
}
#include <stdio.h>
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;
}
#include <stdio.h>
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
modifyArray(numbers, size);
return 0;
}
Scope of Variables
#include <stdio.h>
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
return 0;
}
#include <stdio.h>
// External/Global storage
int globalCounter = 0;
void storageClassDemo() {
// Automatic storage (default for local variables)
auto int autoVar = 10;
// Static storage
static int staticVar = 30;
autoVar++;
regVar++;
staticVar++;
globalCounter++;
}
int main() {
printf("Storage class demonstration:\n");
return 0;
}
Recursion
Recursion is a programming technique where a function calls itself to solve a problem by breaking it into smaller
subproblems.
#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;
return 0;
}
#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;
}
if(arr[mid] == target) {
return mid;
}
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;
return 0;
}
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
#include <stdio.h>
#include <string.h>
int main() {
// Different ways to declare and initialize strings
return 0;
}
#include <stdio.h>
while(src[i] != '\0') {
dest[destLen + i] = src[i];
i++;
}
dest[destLen + i] = '\0';
}
// 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 ";
return 0;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// Shift string
int i;
for(i = 0; start <= end; i++, start++) {
str[i] = str[start];
}
str[i] = '\0';
}
int main() {
char text1[] = "Hello World Programming";
char text2[] = " C Programming Language ";
char text3[] = "The quick brown fox jumps over the lazy dog";
toLowerCase(text1);
printf("Lowercase: '%s'\n", text1);
return 0;
}
Pointers & Strings
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).
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.