Standardowa biblioteka w nagłówku cstring (lub string.h) dostarcza wielu funkcji użytecznych do manipulowania zawartością pamięci. Niektóre z nich to:
void* memcpy(void* target, const void* source, size_t len) — kopiuje len bajtów od pozycji wskazywanej przez source do obszaru pamięci rozpoczynającego się od adresu w target; zwraca target. Obszar źródłowy i docelowy nie mogą się przekrywać. Tak więc jeśli chcemy przekopiować tablicę liczb całkowitych tab o wymiarze size do nowo utworzonej tablicy t, możemy to zrobić tak
int* t = new int[size]; memcpy(t,tab,size*sizeof(int));
co jest dla długich tablic znaczenie szybsze niż kopiowanie
w pętli element po elemencie.
Zauważmy, że kopiowanie jest „z prawa na lewo” —
pierwszy argument wskazuje miejsce przeznaczenia, a drugi
obszar źródłowy!
void* memmove(void* target, const void* source, size_t len) — jest podobna do memcpy, ale obszar docelowy może się częściowo pokrywać z obszarem źródłowym; jest wolniejsza od funkcji memcpy.
void* memchr(const void* str, int znak, size_t len) — poszukuje bajtu (znaku) będącego najmłodszym bajtem argumentu znak w len bajtach poczynając od pozycji w pamięci wskazywanej przez str. Zwraca wskaźnik do znalezionego bajtu (znaku) lub wskaźnik pusty (NULL), jeśli poszukiwanie nie zakończyło się sukcesem.
int memcmp(const void* p, const void* q, size_t len) — porównuje leksykograficznie pierwsze len bajtów ciągów bajtów rozpoczynających się na pozycjach wskazywanych przez p i q; zwraca całkowitą wartość ujemną jeśli ciąg wskazywany przez p jest leksykograficznie wcześniejszy niż ciąg wskazywany przez q, 0 jeśli ciągi są identyczne, oraz całkowitą wartość dodatnią jeśli p jest leksykograficznie późniejsze niż q.
void* memset(void* p, int znak, size_t len) — wypełnia len bajtów pamięci najmłodszym bajtem wartości znak poczynając od pozycji wskazywanej przez wskaźnik p. Zwraca p.
Poniższy prosty programik demonstruje użycie tych funkcji:
1. #include <iostream> 2. #include <cstring> // memcpy, memmove 3. using namespace std; 4. 5. template <typename T> 6. T* rotate_left(T arr[], size_t size, size_t shift) { 7. 8. if ((shift %= size) == 0) return arr; ➊ 9. 10. T* aux = new T[shift]; 11. 12. memcpy(aux,arr,shift*sizeof(T)); ➋ 13. memmove(arr,arr+shift,(size-shift)*sizeof(T)); 14. memcpy(arr+size-shift,aux,shift*sizeof(T)); 15. 16. delete [] aux; 17. return arr; 18. } 19. 20. template <typename T> 21. void writeArr(const char* mes, const T arr[], size_t size) { 22. cout << mes << ": " << "[ "; 23. for (size_t i = 0; i < size; ++i) 24. cout << arr[i] << " "; 25. cout << "]" << endl; 26. } 27. 28. int main() { 29. char arrc[] = {'a','b','c','d','e','f'}; 30. writeArr("tab. znakow",arrc,6); 31. rotate_left(arrc,6,8); 32. writeArr(" rot. o 8",arrc,6); 33. rotate_left(arrc,6,1); 34. writeArr(" potem o 1",arrc,6); 35. 36. cout << endl; 37. 38. int arri[] = {1,2,3,4,5,6,7,8,9}; 39. writeArr("tab. int'ow",arri,9); 40. rotate_left(arri,9,7); 41. writeArr(" rot. o 7",arri,9); 42. }
Funkcja rotate_left przesuwa elementy tablicy o wymiarze size o shift pozycji w lewo w taki sposób, że elementy „wychodzące” z lewej strony pojawiają się po prawej (rotacja). Aby zabezpieczyć się przed przypadkiem shift > size w linii ➊ brana jest reszta z dzielenia shift przez size. W linii ➋ kopiujemy shift pierwszych elementów do tablicy pomocniczej, następnie przesuwamy pozostałe elementy w lewo za pomocą memmove, po czym wstawiamy (kopiujemy) zapamiętane elementy po prawej stronie tablicy (nie zapominając o usunięciu tablicy pomocniczej). Wydruk z tego programu:
tab. znakow: [ a b c d e f ] rot. o 8: [ c d e f a b ] potem o 1: [ d e f a b c ] tab. int'ow: [ 1 2 3 4 5 6 7 8 9 ] rot. o 7: [ 8 9 1 2 3 4 5 6 7 ]
T.R. Werner, 21 lutego 2016; 20:17