DevAcademia
C++C#CPythonJava
  • C Basics

  • Introduction to C
  • Getting Started with C
  • C Syntax
  • C Output
  • C Comments
  • C Variables
  • C Data Types
  • C Constants
  • C Operators
  • C Booleans
  • C If...Else Statements
  • C Switch Statement
  • C While Loops
  • C For Loops
  • C Break and Continue
  • C Strings
  • C User Input
  • C Memory Address
  • C Pointers
  • C Files
  • C Functions

  • C Functions
  • C Function Parameters
  • C Scope
  • C Function Declaration
  • C Recursion
  • C Math Functions
  • C Structures

  • C Structures
  • C Structs & Pointers
  • C Unions
  • C Enums

  • C Enums
  • C Memory

  • C Allocate Memory
  • C Access Memory
  • C Reallocate Memory
  • C Deallocate Memory
  • C Structs and Memory
  • C Memory Example
  • C Quiz

  • C Quiz
  • C Basics

  • Introduction to C
  • Getting Started with C
  • C Syntax
  • C Output
  • C Comments
  • C Variables
  • C Data Types
  • C Constants
  • C Operators
  • C Booleans
  • C If...Else Statements
  • C Switch Statement
  • C While Loops
  • C For Loops
  • C Break and Continue
  • C Strings
  • C User Input
  • C Memory Address
  • C Pointers
  • C Files
  • C Functions

  • C Functions
  • C Function Parameters
  • C Scope
  • C Function Declaration
  • C Recursion
  • C Math Functions
  • C Structures

  • C Structures
  • C Structs & Pointers
  • C Unions
  • C Enums

  • C Enums
  • C Memory

  • C Allocate Memory
  • C Access Memory
  • C Reallocate Memory
  • C Deallocate Memory
  • C Structs and Memory
  • C Memory Example
  • C Quiz

  • C Quiz

Loading C tutorial…

Loading content
C MemoryTopic 59 of 64
←PreviousPrevNextNext→

C Access Memory

Introduction to Memory Access

Accessing dynamically allocated memory is a fundamental skill in C programming. Proper memory access ensures data integrity, prevents crashes, and enables efficient manipulation of data structures. Understanding how to safely read from and write to allocated memory is crucial for robust C programs.

Key aspects of memory access:

- Pointer arithmetic and array indexing

- Bounds checking to prevent buffer overflows

- Type safety and proper casting

- Memory alignment considerations

Array Indexing vs Pointer Arithmetic

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

int main(void) {
    int *arr = malloc(5 * sizeof *arr);
    
    if (arr == NULL) {
        printf("Allocation failed!\n");
        return 1;
    }
    
    // Method 1: Array indexing (recommended for clarity)
    for (int i = 0; i < 5; i++) {
        arr[i] = (i + 1) * 10;
    }
    
    printf("Using array indexing: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    // Method 2: Pointer arithmetic
    int *ptr = arr;
    printf("Using pointer arithmetic: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", *ptr);
        ptr++; // Move to next element
    }
    printf("\n");
    
    free(arr);
    return 0;
}
Output
Using array indexing: 10 20 30 40 50
Using pointer arithmetic: 10 20 30 40 50
ℹ️ Note: Array indexing is generally preferred for readability, while pointer arithmetic can be more efficient in some cases.

Bounds Checking and Safety

⚠️ Warning: Always perform bounds checking to prevent buffer overflows/underflows, which can cause crashes or security vulnerabilities.
Example
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const int SIZE = 5;
    int *numbers = malloc(SIZE * sizeof *numbers);
    
    if (numbers == NULL) {
        printf("Allocation failed!\n");
        return 1;
    }
    
    // Safe initialization with bounds checking
    for (int i = 0; i < SIZE; i++) {
        numbers[i] = i * 2;
    }
    
    // SAFE: Check bounds before access
    int index = 3;
    if (index >= 0 && index < SIZE) {
        printf("Safe access: numbers[%d] = %d\n", index, numbers[index]);
    } else {
        printf("Index %d out of bounds!\n", index);
    }
    
    // Attempt invalid access with check
    index = 10;
    if (index >= 0 && index < SIZE) {
        printf("Safe access: numbers[%d] = %d\n", index, numbers[index]);
    } else {
        printf("Index %d out of bounds!\n", index);
    }
    
    free(numbers);
    return 0;
}
Output
Safe access: numbers[3] = 6
Index 10 out of bounds!

Pointer Arithmetic Details

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

int main(void) {
    int *arr = malloc(4 * sizeof *arr);
    
    if (arr == NULL) return 1;
    
    // Initialize array
    for (int i = 0; i < 4; i++) {
        arr[i] = (i + 1) * 100;
    }
    
    // Demonstrate pointer arithmetic
    int *ptr = arr;
    printf("Initial pointer: %p -> %d\n", (void*)ptr, *ptr);
    
    ptr++; // Move to next int (advances by sizeof *ptr bytes)
    printf("After ptr++: %p -> %d\n", (void*)ptr, *ptr);
    
    ptr += 2; // Move forward two ints
    printf("After ptr += 2: %p -> %d\n", (void*)ptr, *ptr);
    
    ptr--; // Move back one int
    printf("After ptr--: %p -> %d\n", (void*)ptr, *ptr);
    
    // Array equivalence: arr[i] == *(arr + i)
    printf("arr[2] = %d, *(arr + 2) = %d\n", arr[2], *(arr + 2));
    
    free(arr);
    return 0;
}
Output
Initial pointer: 0x55a1b2c3d4e0 -> 100
After ptr++: 0x55a1b2c3d4e4 -> 200
After ptr += 2: 0x55a1b2c3d4ec -> 400
After ptr--: 0x55a1b2c3d4e8 -> 300
arr[2] = 300, *(arr + 2) = 300
ℹ️ Note: Pointer arithmetic automatically accounts for the size of the pointed-to type.

Accessing Different Data Types

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

int main(void) {
    // Allocate memory for different types
    int *intArr = malloc(3 * sizeof *intArr);
    double *doubleArr = malloc(3 * sizeof *doubleArr);
    char *charArr = malloc(10 * sizeof *charArr);
    
    if (!intArr || !doubleArr || !charArr) {
        printf("Allocation failed!\n");
        // Free any allocations that succeeded before returning
        free(intArr);
        free(doubleArr);
        free(charArr);
        return 1;
    }
    
    // Access and modify different types
    intArr[0] = 42;
    intArr[1] = 100;
    intArr[2] = 255;
    
    doubleArr[0] = 3.14159;
    doubleArr[1] = 2.71828;
    doubleArr[2] = 1.41421;
    
    snprintf(charArr, 10, "Hello");
    
    printf("Integers: %d, %d, %d\n", intArr[0], intArr[1], intArr[2]);
    printf("Doubles: %.5f, %.5f, %.5f\n", doubleArr[0], doubleArr[1], doubleArr[2]);
    printf("String: %s\n", charArr);
    
    // Demonstrate type-specific pointer arithmetic
    printf("Address differences:\n");
    printf("  int pointers: %td bytes between elements\n", (char*)(&intArr[1]) - (char*)(&intArr[0]));
    printf("  double pointers: %td bytes between elements\n", (char*)(&doubleArr[1]) - (char*)(&doubleArr[0]));
    
    free(intArr);
    free(doubleArr);
    free(charArr);
    
    return 0;
}
Output
Integers: 42, 100, 255
Doubles: 3.14159, 2.71828, 1.41421
String: Hello
Address differences:
  int pointers: 4 bytes between elements
  double pointers: 8 bytes between elements

Common Memory Access Errors

⚠️ Warning: These common errors can cause crashes, data corruption, or security vulnerabilities. Always validate memory access.
Example
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = malloc(3 * sizeof *arr);
    
    if (arr == NULL) return 1;
    
    // ERROR 1: Access before initialization (garbage values)
    // printf("Uninitialized access: %d\n", arr[0]); // UNDEFINED BEHAVIOR!
    
    // ERROR 2: Buffer overflow
    // for (int i = 0; i <= 3; i++) {  // One too many!
    //     arr[i] = i * 10;
    // }
    
    // ERROR 3: Use after free
    free(arr);
    // printf("Use after free: %d\n", arr[0]); // CRASH!
    
    // ERROR 4: Access through NULL pointer
    int *nullPtr = NULL;
    // printf("NULL access: %d\n", *nullPtr); // CRASH!
    
    return 0;
}

Best Practices for Memory Access

  • Always initialize memory before reading from it
  • Perform bounds checking before array access
  • Use array indexing for clarity in most cases
  • Be careful with pointer arithmetic - know what you're doing
  • Avoid accessing memory after it's been freed
  • Never dereference NULL pointers
  • Consider using safe string functions (strncpy, snprintf)
  • Use compiler warnings and static analysis tools
Test your knowledge: C Access Memory
Quiz Configuration
4 of 8 questions
Sequential
Previous allowed
Review enabled
Early close allowed
Estimated time: 5 min
C MemoryTopic 59 of 64
←PreviousPrevNextNext→