How to Use the mmap Function to Write to the Memory in C
In this article, we’ll learn the mmap()
function, how many parameters it takes, and how to use mmap()
to write to the memory in C programming.
the mmap()
Function in C
We use this function to map the process address space and either the devices or files. The mmap()
function requests writeable anonymous and private mapping of memory’s n
bytes.
The anonymous mapping and private mapping mean it is not backed by the file and is not shared with another process(s). To use the mmap()
, we must include the header file.
#include <sys/mman.h>
It takes six arguments:
void *mmap(void *address, size_t length, int protect, int flags, int filedes,
off_t offset)
Before going into the use of this function, let’s discuss the arguments.
-
address
- It provides the preferred starting address used for mapping. If there is no other mapping, the kernel will pick the nearby page boundary, creating a mapping.Else, the kernel will pick the new address. If the value for this parameter is
NULL
, the kernel will place the mapping where it sees fit. -
length
- The bytes’ number is mapped. -
protect
- It controls what type of access is allowed. For instance, thePROT_READ
for reading access, thePROT_WRITE
for write access, and thePROT_EXEC
for execution. -
flags
- It is used for controlling the map’s nature. Some of the common and useful flags are listed below:MAP_SHARED
- share mapping with other processes.MAP_FIXED
- The system is forced to use the same mapping address given via theaddress
parameter.MAP_ANONYMOUS / MAP_ANON
- It creates anonymous mapping.MAP_PRIVATE
- The mapping would be private and not visible to others while using this flag.
-
filedes
- The file descriptor is supposed to be mapped. -
offset
- The file mapping starts from this offset.
We get 0 if the mmap()
successfully works. Otherwise, MAP_FAILED
is returned.
Use mmap()
to Write to the Memory in C
Let’s understand mmap()
by practicing different examples.
Example Code (for memory allocation
):
#include <stdio.h>
#include <sys/mman.h>
int main() {
int N = 5;
int *ptr = mmap(NULL, N * sizeof(int), PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (ptr == MAP_FAILED) {
printf("Mapping Failed\n");
return 1;
}
for (int i = 0; i < N; i++) ptr[i] = i * 10;
for (int i = 0; i < N; i++) printf("[%d] ", ptr[i]);
printf("\n");
int err = munmap(ptr, 10 * sizeof(int));
if (err != 0) {
printf("Unmapping Failed\n");
return 1;
}
return 0;
}
Output:
[0] [10] [20] [30] [40]
We use the mmap()
function to allocate the memory where we are using the PROT_READ | PROT_WRITE
protections for writing & reading to a mapped region.
We use the MAP_PRIVATE
flag because we don’t want to share the mapping region with other processes and the MAP_ANONYMOUS
because we haven’t mapped the file.
The file descriptor and offset are set to 0
for the same cause.
Example Code (for interprocess communication
):
#include <stdio.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int Number = 5;
int *ptr = mmap(NULL, Number * sizeof(int), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
if (ptr == MAP_FAILED) {
printf("Mapping Failed\n");
return 1;
}
for (int i = 0; i < Number; i++) {
ptr[i] = i + 7;
}
printf("Initial array's values:");
for (int i = 0; i < Number; i++) {
printf(" %d", ptr[i]);
}
printf("\n");
pid_t child_pid = fork();
if (child_pid == 0) {
// child
for (int i = 0; i < Number; i++) {
ptr[i] = ptr[i] * 5;
}
} else {
// parent
waitpid(child_pid, NULL, 0);
printf("\nParent:\n");
printf("Updated array's values:");
for (int i = 0; i < Number; i++) {
printf(" %d", ptr[i]);
}
printf("\n");
}
int err = munmap(ptr, Number * sizeof(int));
if (err != 0) {
printf("Unmapping Failed\n");
return 1;
}
return 0;
}
Output:
Initial array's values: 7 8 9 10 11
Initial array's values: 7 8 9 10 11
Parent:
Updated array's values: 35 40 45 50 55
We initialize the array with some values initially. Then, a child’s process changes the values.
Further, the values are read by the parent process, which was changed by the child process because the mapped memory is being shared with both (child & parent) processes. We are also using the munmap()
to remove the memory mapping.