Common Mistakes in Embedded C Development - Pointers Done Wrong

Ilya KatlinskiIlya Katlinski
3 min read

Article photo by Jorge Ramirez on Unsplash

📘 Introduction

This is Part 2 of our 4-part series on memory mistakes in Embedded C. In Part 1, we discussed stack overflows and how modern C practices can prevent them.

Today, we’ll take on unsafe pointer usage, one of the most common (and dangerous) issues in low-level C, especially in the context of hardware drivers, buffers, and data parsing in embedded systems.

🧠 Unsafe Use of Pointers

🐞 The Problem

Pointers are one of C’s most powerful features, and also one of its most dangerous. Beginners often use them without fully understanding ownership, memory layout, or lifetime. This leads to:

  • Dereferencing null or invalid pointers

  • Using freed or uninitialized memory

  • Memory leaks or crashes

  • Data corruption from unexpected aliasing

Let’s walk through a realistic example from an embedded IoT application. Suppose you’re reading sensor data and preparing it for a cloud payload handler:

void prepareData(float* temperature) {
    *temperature = readSensor(); // OK if 'temperature' is valid
}

void logAndSend() {
    float* temp = NULL;
    prepareData(temp); // ⛔️ temp is null → crash!
    sendToCloud(temp);
}

This code compiles fine, but dereferencing a null pointer inside prepareData() will crash the device at runtime.

Or another classic mistake is returning a pointer to a local stack variable:

char* getDeviceID() {
    char id[32]; // ⛔️ local variable
    snprintf(id, sizeof(id), "dev-%04X", getChipID());
    return id; // INVALID after function returns
}

✅ Solution 1: Use Proper Ownership – Allocate Before Passing

Always make sure that pointers point to valid memory before you pass them to functions.

void prepareData(float* temperature) {
    *temperature = readSensor();
}

void logAndSend() {
    float temp = 0.0f;
    prepareData(&temp); // ✅ address of valid memory
    sendToCloud(&temp);
}

✅ Solution 2: Avoid Returning Pointers to Local Variables

Return static memory, or require the caller to provide a buffer:

void getDeviceID(char* out, size_t size) {
    snprintf(out, size, "dev-%04X", getChipID());
}

✅ Solution 3: Mark Pointer Ownership with const

If a function only reads from a pointer, mark it as const. This helps:

  • Prevent bugs from accidental modification

  • Signal to other developers that ownership doesn’t transfer

void sendToCloud(const float* value) {
    mqttSend("sensor/temp", valueToStr(*value));
}

✅ Solution 4: Use Static Analysis and Compiler Warnings

Let your tools catch pointer issues early.

Use strict compiler warnings for C:

gcc -Wall -Wextra -Werror -O2 -std=c11 main.c

With the below code

#include <stdio.h>

int main() {
    int *ptr;                // Uninitialized pointer
    printf("%d\n", *ptr);    // 🚨 Undefined behavior
    return 0;
}

You will get the following output:

main.c:5:21: error: variable 'ptr' is uninitialized when used here [-Werror,-Wuninitialized]
    5 |     printf("%d\n", *ptr);    // 🚨 Undefined behavior
      |                     ^~~
main.c:4:13: note: initialize the variable 'ptr' to silence this warning
    4 |     int *ptr;                // Uninitialized pointer
      |             ^
      |              = NULL
1 error generated.

Use static analysers for deeper inspection:

💡 Takeaway

Pointer safety in embedded C isn’t optional; it’s critical. You don’t get exceptions, memory protection, or guard rails like in modern languages.

To stay safe:

  • Don’t dereference null or invalid pointers

  • Don’t return pointers to local variables

  • Always check pointer inputs (defensive programming)

  • Use const to clarify ownership

  • Turn on all warnings and use static analysis tools


At Itransition, we build IoT solutions with all these challenges in mind, ensuring our clients receive reliable, scalable systems with minimal maintenance overhead. Learn more about our approach at https://www.itransition.com/iot.

0
Subscribe to my newsletter

Read articles from Ilya Katlinski directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ilya Katlinski
Ilya Katlinski