// Gracias Dennis Ritchie...
Understanding malloc() and free() is fundamental to C programming. These functions give you direct control over memory allocation, a power that comes with great responsibility.
// Always check malloc return value
void* ptr = malloc(sizeof(int) * 100);
if (ptr == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return -1;
}
// Use the memory
free(ptr);
ptr = NULL; // Avoid dangling pointers
The beauty of C lies in this explicit control. Every byte allocated must be freed, teaching discipline and awareness that higher-level languages abstract away.
Read Full Article →Pointers are what make C incredibly powerful and efficient. Understanding pointer arithmetic unlocks the ability to manipulate memory directly and write highly optimized code.
int arr[] = {10, 20, 30, 40};
int *p = arr;
// These are equivalent
printf("%d\n", arr[2]);
printf("%d\n", *(p + 2));
printf("%d\n", *(arr + 2));
// Pointer arithmetic scales by type size
printf("Address: %p\n", (void*)(p + 1)); // +4 bytes on 32-bit
Dennis Ritchie designed C with the philosophy that programmers should have complete control over the machine. Pointers embody this principle perfectly.
Read Full Article →After 20 years in embedded software engineering, I can confidently say that C remains the king of embedded systems. Its minimal abstraction and predictable behavior make it irreplaceable.
// Direct hardware register manipulation
#define GPIO_BASE 0x40020000
#define GPIO_MODER ((volatile uint32_t*)(GPIO_BASE + 0x00))
// Set pin 5 to output mode
*GPIO_MODER &= ~(0x3 << 10);
*GPIO_MODER |= (0x1 << 10);
// This level of control is why C dominates embedded
When you're working with microcontrollers and real-time systems, you need to know exactly what your code is doing at the hardware level. C gives you that transparency.
Read Full Article →Understanding how the compiler aligns struct members can save memory and prevent subtle bugs, especially in embedded systems where every byte counts.
// Inefficient layout (11 bytes, padded to 12)
struct Bad {
char a; // 1 byte
int b; // 4 bytes (3 bytes padding before)
char c; // 1 byte (3 bytes padding after)
};
// Efficient layout (9 bytes, padded to 8)
struct Good {
int b; // 4 bytes
char a; // 1 byte
char c; // 1 byte (2 bytes padding after)
};
Reordering struct members by size (largest first) minimizes padding and can significantly reduce memory usage in large data structures.
Read Full Article →