12.6 Funkcje operujące na pamięci

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 znaklen 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 pq; 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:


P92: rotate.cpp     Funkcje operujące na pamięci

      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 sizeshift 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