Data manipulation

Non-string array manipulation

The 2 precedent pages presented the functions, declared in the header <string.h>, which work on null-terminated strings. Here, we will see the functions, declared in the same header, that work on arrays of any kind (Does not have to end with the value 0 (null-character)).

Copying data

The function memcpy, which header is void* memcpy(void* dest, const void* src, size_t size), copies the amount of bytes received in last argument, from the address pointed by the second argument to the memory address pointed by the first parameter. Its returns the first argument back. That function simply copy bytes, the type of the data does not matter. It could be an array of float, int, char or even objects.

Note that the destination range and the source range must not overlap.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <string.h> #include <stdio.h> int main() { int values[] = {1, 2, 3, 4, 5}; int copy[5]; // Copies the bytes of 5 int from 'values' to 'copy'. memcpy(copy, values, sizeof(int)*5); // Prints the copied values. for(int c= 0; c < 5; c++) printf("%d ", copy[c]); return 0; }

Here is an other example, where we copy an array of objects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <string.h> #include <stdio.h> struct FloatInt { float f = 0; int i = 0; }; int main() { struct FloatInt array[5]; array[2].f = 0.5; char copy[sizeof(FloatInt) * 5]; // Copies the bytes of 5 objects of type FloatInt from 'array' to 'copy'. memcpy(copy, array, sizeof(FloatInt)*5); // We use 'copy' as an array of FloatInt objects. FloatInt *ptr = (struct FloatInt*)&copy; // Verifies that ptr[2].f equals 0.5. printf("ptr[2] == %f.\n", ptr[2].f); return 0; }

Copying overlapping data

The function which header is void* memmove(void* dest, const void* src, size_t size) is similar to the function memcpy, except that the range of the data to copy (the source) is allowed to overlap with the range of the destination. That function guarantees that the data to copy will not be overwritten before it is copied. For that reason, it might be a bit slower than the function memcpy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <string.h> #include <stdio.h> int main() { int array[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; /* Copies the first 9 elements of 'array', at the location of its fourth element, using memmove. */ memmove(&array[3], array, sizeof(int) * 9); // Prints the content of array. for(unsigned c = 0; c < 12; c++) printf("%d ", array[c]); putchar('\n'); // Newline. /* "1 2 3 1 2 3 4 5 6 7 8 9" is printed in the console. If the bytes were copied, one by one, from the start of the source to the start of the destination, therefore overwriting a part of the source before it is completely copied, the result would have been: "1 2 3 1 2 3 1 2 3 1 2 3" The function memmove guarantees that the result above does not happen. With memcpy, it may or may not happen. */ return 0; }

Comparing two block of data

The function memcmp, which header is int memcmp(const void* ptr, const void* ptr2, size_t size), compares the blocks of memory, with a size specified by the last parameter, and starting at the locations pointed by the first two arguments. If the bytes of both blocks are equal, 0 is returned. If they are not equal and the first different byte has a lower value in the array pointed by the first argument, a negative number is returned. The valued returned is positive if the first different byte has a lower value in the second block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <string.h> #include <stdio.h> int main() { char array[] = {1, 2, 3, 4, 5, 6}; char array2[] = {1, 2, 3, 5, 6, 7}; int compResult = memcmp(array, array2, sizeof(array)); /* The first different byte is at index 3 (4 vs 5). 4 is the value of the byte at index 3 of the first array and it is lower than 5, which is the value of the byte at index 3 of the second array. A negative number is then returned by memcmp. */ if(compResult == 0) puts("The data of both arrays is equal."); else if(compResult < 0) puts("The first different byte has a lower value in the first array."); else puts("The first different byte has a lower value in the second array."); int array3[] = {234, 754, 373}; int array4[] = {234, 754, 373}; if(memcmp(array3, array4, sizeof(array3)) == 0) puts("The data of both arrays is equal."); else puts("The data inside the two arrays is different."); int array5[] = {234, 22, 373}; int array6[] = {234, 754, 373}; if(memcmp(array5, array6, sizeof(array5)) == 0) puts("The data of both arrays is equal."); else puts("The data inside the two arrays is different."); return 0; }

Searching, inside a block of memory, for a byte with a specific value

The function which header is void* memchr(const void* ptr, int value, size_t size) searches inside the block of memory pointed by the first argument, of a size, in bytes, specified by the last argument, for a byte with the same value as the one given as second argument. A pointer to the first byte, with the specified value, found, is returned. If there is no byte with that value inside the block of memory, a null-pointer is returned.

Note that the function header above is the one defined in C. In C++, the two following versions (overloads) are defined instead:

const void* memchr(const void* ptr, int value, size_t size) void* memchr(void* ptr, int value, size_t size)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <string.h> #include <stdio.h> int main() { char buffer[] = {0, 23, 0, 5, 6, 0, 9, 0, 2}; // Retrieves a pointer to the first byte, inside the array 'buffer', found with the value 0. char *ptr = (char*)memchr(buffer, 0, sizeof(buffer)); // As long as a byte with the value 0 has been found inside tha array 'buffer'. while(ptr != 0) { // Replaces the value of the byte which equals 0, by 1. *ptr = 1; // Retrieves a pointer to the first byte, inside the array 'buffer', found with the value 0. ptr = (char*)memchr(buffer, 0, sizeof(buffer)); } // Prints the content of the array 'buffer', to the console. for(unsigned c = 0; c < sizeof(buffer); c++) printf("%d ", buffer[c]); putchar('\n'); /* "1 23 1 5 6 1 9 1 2" is written to the console. */ return 0; }

Note that in the example above, we output the elements of type char with the function printf using the integer qualifier "%d", because if we had used the char qualifier "%c" instead, the characters assigned to their values, using the ASCII encoding, would have been outputted instead of their numerical values.

Filling a memory space with a value

The function memset, which header is void* memset(void* ptr, int value, size_t num), sets all the bytes inside the memory block of the size specified by the last argument and starting at the address pointed by the first argument, to the value given in second argument. It returns back the first argument.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <string.h> #include <stdio.h> int main() { char str[] = "My password is l3/9cn$W."; /* Replaces the 8 bytes representing the password by the ASCII value of the asterisk character '*'. */ memset(&str[15], '*', 8); // Prints the now hidden password. puts(str); return 0; }

Here is an other example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <string.h> #include <stdio.h> int main() { unsigned short array[6]; /* Fills the array 'array' with zeros, so all its bits are unset (Equal to 0). Therefore, all the elements of the array are set to their smallest value. */ memset(array, 0, sizeof(array)); // Prints the elements of the array 'array'. puts("The elements of the array:"); for(unsigned c=0; c < 6; c++) printf("%hu\n", array[c]); /* Sets each byte of the array 'array' to 255, so all its bits are set (Equal to 1). Therefore, all the elements of the array are set to their biggest value. */ memset(array, 255, sizeof(array)); // Prints the elements of the array 'array'. puts("The elements of the array:"); for(unsigned c=0; c < 6; c++) printf("%hu\n", array[c]); return 0; }