C Memory Address
Introduction to Memory Addresses
In C programming, every variable is stored in a specific memory location. A memory address is the location where a variable is stored in the computer's memory.
Understanding memory addresses is fundamental to working with pointers, dynamic memory allocation, and low-level programming in C.
Address-of Operator (&)
The address-of operator (&) is used to get the memory address of a variable. It returns the location where the variable is stored in memory.
Syntax: &variableName
#include <stdio.h>
int main(void) {
int num = 42;
float pi = 3.14f;
char letter = 'A';
printf("Address of num: %p\n", (void*)&num);
printf("Address of pi: %p\n", (void*)&pi);
printf("Address of letter: %p\n", (void*)&letter);
return 0;
}
Address of num: 0x7ffd4a5b6a4c Address of pi: 0x7ffd4a5b6a48 Address of letter: 0x7ffd4a5b6a47
Printing Addresses Correctly
Use printf with the %p format specifier to print addresses, and cast the pointer to (void*) to match the required type.
Example: printf("%p", (void*)&x);
#include <stdio.h>
int main(void) {
int x = 10, y = 20;
printf("&x=%p, &y=%p\n", (void*)&x, (void*)&y);
return 0;
}
&x=0x7ffcc1a2f730, &y=0x7ffcc1a2f734
Pointer Variables
Pointers are variables that store memory addresses. They are declared using the asterisk (*) symbol and must match the type of the variable whose address they store.
Syntax: dataType *pointerName;
#include <stdio.h>
int main(void) {
int num = 42;
int *numPtr = # // Pointer to integer
printf("Address of num: %p\n", (void*)&num);
printf("Value of numPtr: %p\n", (void*)numPtr);
printf("Value at address stored in numPtr: %d\n", *numPtr);
return 0;
}
Address of num: 0x7ffc5d7d7a4c Value of numPtr: 0x7ffc5d7d7a4c Value at address stored in numPtr: 42
Pointer Arithmetic
Pointer arithmetic allows you to perform arithmetic operations on pointers. When you add to or subtract from a pointer, it moves by the size of the data type it points to.
This is particularly useful for array manipulation and memory management.
#include <stdio.h>
int main(void) {
int numbers[] = {10, 20, 30, 40, 50};
int *ptr = numbers;
for (int i = 0; i < 5; i++) {
printf("numbers[%d] = %d ", i, *(ptr + i));
}
printf("\n");
return 0;
}
numbers[0] = 10 numbers[1] = 20 numbers[2] = 30 numbers[3] = 40 numbers[4] = 50
Pointers and Arrays
In C, arrays and pointers are closely related. The name of an array decays to a pointer to its first element in most expressions, and array indexing can be done using pointer arithmetic.
Note: An array name is not a modifiable pointer; you cannot assign to it.
#include <stdio.h>
int main(void) {
int arr[3] = {1, 2, 3};
int *ptr = arr;
printf("arr[0] = %d, *(ptr) = %d\n", arr[0], *ptr);
printf("arr[1] = %d, *(ptr+1) = %d\n", arr[1], *(ptr+1));
printf("arr[2] = %d, ptr[2] = %d\n", arr[2], ptr[2]);
return 0;
}
arr[0] = 1, *(ptr) = 1 arr[1] = 2, *(ptr+1) = 2 arr[2] = 3, ptr[2] = 3
Pointers to Pointers
C allows pointers to point to other pointers, creating multiple levels of indirection. This is useful for dynamic multi-dimensional arrays and complex data structures.
#include <stdio.h>
int main(void) {
int value = 42;
int *ptr = &value;
int **pptr = &ptr;
printf("Value = %d\n", value);
printf("*ptr = %d\n", *ptr);
printf("**pptr = %d\n", **pptr);
return 0;
}
Value = 42 *ptr = 42 **pptr = 42
Void Pointers
A void pointer (void *) is a special type of pointer that can point to objects of any data type. However, it must be cast to the appropriate type before dereferencing.
You cannot perform portable pointer arithmetic on void* because it has no element size in standard C.
#include <stdio.h>
int main(void) {
int num = 42;
void *voidPtr = #
printf("Value through void pointer: %d\n", *(int *)voidPtr);
return 0;
}
Value through void pointer: 42
NULL Pointers
A NULL pointer is a pointer that doesn't point to any valid memory location. It's a good practice to initialize pointers to NULL when they're not pointing to anything valid.
Dereferencing a NULL pointer results in undefined behavior, typically a program crash.
#include <stdio.h>
int main(void) {
int *ptr = NULL;
if (ptr == NULL) {
printf("Pointer is NULL\n");
}
return 0;
}
Pointer is NULL
Best Practices
1. Always initialize pointers when they are declared.
2. Use NULL for pointers that don't point to anything valid.
3. Always check for NULL before dereferencing pointers.
4. Be careful with pointer arithmetic and keep it within the same array/object.
5. Use the const qualifier with pointers when appropriate.
6. Print addresses with printf("%p", (void*)ptr) — cast to (void*) for correctness.
7. Avoid dangling pointers: after freeing dynamically allocated memory, set the pointer to NULL.