Chapter 4: Pointers and Data Structures in C

📚 Pointers in C and Their Role in Data Structures

🎯 Learning Objectives

By the end of this lesson, students will be able to:

  • Understand what a pointer is and how it works in C.
  • Use pointers to manipulate variables, arrays, and structures.
  • Apply pointers in the implementation of common data structures
  • Recognize why pointers are essential efficient data handling and peripherals access.

1️⃣ — Understanding Pointers

1.1 What is a Pointer?

  • A pointer is a variable that stores the memory address of another variable.
  • Syntax:
int *ptr; // pointer to an int
char *cptr; // pointer to a char

1.2 Basic Example

int main() {
    int x = 10;
    int *p = &x; // p stores the address of x

    *p += 5;    //adds 5 to x via dereferencing
    p++;        //increases the memory address by 1 (danger!!!)

    printf("Value of x: %d\n", x);
    printf("Address of x: %p\n", (void*)&x);
    printf("Value via pointer: %d\n", *p); // dereferencing
    return 0;
}

Key Concepts:

  • & → address-of operator.

printf("Address of x: %p\n", (void*)&x); //Prints the adress of x

  • * → dereference operator (access value at the address).

*p += 5; //adds 5 to x via dereferencing

2️⃣ — Pointers with Arrays and Strings

2.1 Arrays and Pointers

  • Array name acts like a pointer to its first element.
int arr[3] = {1, 2, 3};
int *p = arr; // same as &arr[0]
printf("%d", *(p+1)); // prints 2

2.2 Strings

char *str = "Hello";
printf("%c", *(str+1)); // prints 'e'

3️⃣ — Pointers and Structures

Pointers allow efficient manipulation of large structures without copying them. Example:

struct Person 
{
    char name[30];
    int age;
};

int main() {
    struct Person p1 = {"Alice", 25};
    struct Person *ptr = &p1;

    printf("%s is %d years old.\n", ptr->name, ptr->age);
    return 0;
}
  • Use -> to access members via a pointer.

4️⃣ — Pointers in Embedded Context

In embedded systems, pointers are the bridge between C code and hardware. Every peripheral (GPIO, UART, TIM, ADC, etc.) lives at a fixed memory address. The STM32 CMSIS headers map these addresses to structs so you can do:

GPIOA->ODR = 0x01; // Set PA0 high

Here:

  • GPIOA is a pointer to a GPIO_TypeDef struct.

  • -> dereferences the pointer to access a register field ODR

5️⃣ How the STM32 Defines Peripherals

From the STM32G0xx CMSIS header (stm32g0b1xx.h):

#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)

  • GPIOA_BASE is the memory address of the GPIOA registers (e.g., 0x50000000).

  • GPIO_TypeDef is a struct describing the layout of the GPIO registers:

typedef struct
{
  __IO uint32_t MODER;   // Mode register
  __IO uint32_t OTYPER;  // Output type
  __IO uint32_t OSPEEDR; // Output speed
  __IO uint32_t PUPDR;   // Pull-up/pull-down
  __IO uint32_t IDR;     // Input data
  __IO uint32_t ODR;     // Output data
  __IO uint32_t BSRR;    // Bit set/reset
  __IO uint32_t LCKR;    // Lock
  __IO uint32_t AFR[2];  // Alternate function
  __IO uint32_t BRR;     // Bit reset
} GPIO_TypeDef;
  • __IO is a macro for volatile, telling the compiler these values can change at any time (hardware updates them).