Fundamental Concepts of Memory and Pointers in C
Memory and Address
Memory Units
Computer memory serves as the primary storage for data during program execution. When the CPU processes information, it retrieves data from and stores results back into memory. To manage and access this vast storage efficiently, memory is organized into discrete units, analogous to individual rooms in a building.
Each memory unit occupies one byte, which is equivalent to eight binary bits. Every byte is assigned a unique numerical identifier. This identifier is known as an address. In C programming, the term pointer is synonymous with this address.
Memory Addressing Mechanism
Computer hardware components interact via electrical pathways. The CPU locates a specific byte in memory by sending its address via the address bus. To read or write data, the CPU issues a command via the control bus. The data is then transferred between the CPU and memory over the data bus.
For a CPU to access a byte, it must know that byte's precise location. Memory addressing provides this capability. In a 32-bit system, the address bus consists of 32 lines. Each line can transmit a binary 1 or 0 signal, enabling the bus to represent 2^32 unique addresses. When the CPU sends an address, the memory unit at that location responds by placing its data on the data bus for transfer.
Pointer Variables and Address Operations
The Address-of Operator (&)
Variable declaration in C requests a memory allocation.
int primary_value = 10;
This statement allocates four consecutive bytes of memory to store the integer primary_value. Each byte has its own address. The & operator extracts the starting address (the smallest address) of the variable's memory block.
#include <stdio.h>
int main() {
int primary_value = 10;
printf("Address: %p\n", &primary_value);
return 0;
}
Knowing the first byte's address allows access to the entire variable's data.
Pointer Variables and the Dereference Operator
Storing Addresses
An address retrieved by & can be stored in a specialized variable known as a pointer variable.
#include <stdio.h>
int main() {
int primary_value = 10;
int *value_ptr = &primary_value; // Store address in pointer
return 0;
}
A pointer variable holds memory addresses. Its type (e.g., int *) indicates it points to data of a specific type.
Type Decomposition
The declaration int *value_ptr can be interpreted in two parts:
- The
*denotesvalue_ptris a pointer variable. - The
intspecifies it points to an integer.
The Dereference Operator (*)
The dereference operator (*) accesses the value stored at the address held by a pointer.
#include <stdio.h>
int main() {
int primary_value = 10;
int *value_ptr = &primary_value;
*value_ptr = 20; // Changes primary_value to 20
return 0;
}
The expression *value_ptr is equivalent to accessing the variable primary_value directly.
Size of Pointer Variables
A pointer's size is determined by the system's addressing scheme, not the type of data it points to.
- On a 32-bit platform, an address is 32 bits (4 bytes).
- On a 64-bit platform, an address is 64 bits (8 bytes).
#include <stdio.h>
int main() {
printf("%zu\n", sizeof(char*));
printf("%zu\n", sizeof(int*));
printf("%zu\n", sizeof(double*));
return 0;
}
All pointer variables on the same platform will yield the same size from sizeof.
Significance of Pointer Variable Types
Pointer Dereferencing Scope
A pointer's type dictates how many bytes are accessed during dereferencing.
#include <stdio.h>
int main() {
int data = 0x11223344;
int *int_ptr = &data;
*int_ptr = 0; // Modifies all 4 bytes
return 0;
}
#include <stdio.h>
int main() {
int data = 0x11223344;
char *char_ptr = (char*)&data;
*char_ptr = 0; // Modifies only 1 byte
return 0;
}
An int* pointer has permission to manipulate four bytes, while a char* pointer can only affect one byte.
Pointer Arithmetic
Adding an integer to a pointer moves it forward in memory by a number of bytes equal to the size of the data type it points to.
#include <stdio.h>
int main() {
int n = 10;
char *c_ptr = (char*)&n;
int *i_ptr = &n;
printf("c_ptr = %p\n", c_ptr);
printf("c_ptr + 1 = %p\n", c_ptr + 1); // Advances 1 byte
printf("i_ptr = %p\n", i_ptr);
printf("i_ptr + 1 = %p\n", i_ptr + 1); // Advances 4 bytes
return 0;
}
The type of a pointer determines the stride size for increment (+) or decrement (-) operations.