Implementacja funkcji map();

W tym miejscu zadajemy pytania na temat języka C, dzielimy się swoją wiedzą, udzielamy wsparcia, rozwiązujemy problemy programistyczne.
Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Implementacja funkcji map();

Postautor: Antystatyczny » sobota 25 mar 2017, 13:51

Witam.

W ramach nauki postanowiłem popracować nad implementacją funkcji map. Jest to pierwsza wersja, póki co iteracyjna, bo mam kilka wątpliwości związanych ze zwracanym wskaźnikiem na zaalokowaną pamięć na wyniki. Ok, najpierw kod:

Kod: Zaznacz cały

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

/* typedef funkcji wartosciującej */
typedef int (unaryFuncType)(int obj);

/* Wersja iteracyjna funkcji map. Przyjmuje wskaźnik na kontener, rozmiar kontenera
   oraz  wskaźnik na funkcję wartosciującą. Zwraca wskaźnik na kontener zawierający efekt pracy
   funkcji wartosciującej na każdym elemencie kontenera lub null, gdy nie uda się zaalokować pamięci.*/
int * map_iter(int *src, size_t len, unaryFuncType *fun);

/* Pomocnicza funkcja do pokazywania efektów pracy */
void show_table(int *src, size_t len);

/* Przykladowa funkcja wartosciujaca. Odejmie od kazdego elementu kontenera 511. */
int subtract(int src);

int main(void)
{
   int ADC_Samples[] = { 150, 700, 400, 83, 1563, 18, 950, 1234, 37, 0, 44 };
   int *ptr;

   printf("Zawartosc kontenera  przed wywolaniem funkcji map():\n\n");
   show_table(ADC_Samples, sizeof(ADC_Samples) / sizeof(ADC_Samples[0]));
   ptr = map_iter(ADC_Samples, sizeof(ADC_Samples) / sizeof(ADC_Samples[0]), subtract);

   if (ptr != NULL)
   {
      printf("\nZawartosc kontenera po przejsciu przez map():\n\n");
      show_table(ptr, sizeof(ADC_Samples) / sizeof(ADC_Samples[0]));

      free(ptr);
   }
   else
   {
      printf("Zacznij zbierac znaczki...\n");
   }

   int key = getchar();

   return EXIT_SUCCESS;
}

int * map_iter(int *src, size_t len, unaryFuncType *fun)
{
   int *result = (int) malloc(len * sizeof(int));

   if (result == NULL)
   {
      perror("Memory allocation error\n");
      return NULL;
   }

   for (int i = 0; i < len; ++i)
   {
      result[i] = fun(src[i]);
   }

   return result;
}

void show_table(int *src, size_t len)
{
   for (size_t i = 0; i < len; ++i)
   {
      printf("Wartosc elementu o indeksie %5d wynosi: %6d\n", i, src[i]);
   }
}

int subtract(int src)
{
   return src - 511;
}



Przede wszystkim, czy wskaźnik 'result' nie powinien być static? Mam wrażenie, że nie, bo zwracam adres, a nie wartość... Kolejna sprawa to argument formalny int *src w funkcji map_iter. Powinien być const? Wszak nie zmieniam żadnych wartości w kontenerze źródłowym. A może mam zmieniać? Jeśli nie, dopiszę const do tego argumentu. Męczy mnie również fakt, że zwracam jedynie wskaźnik na kontener, a reszta programu nie ma pojęcia o jego wielkości. Tak ma być? No i na koniec zwalnianie pamięci. Wystarczy zwyczajne free(ptr), czy potrzebne są jakieś dodatkowe zabiegi?

Gdyby były jeszcze jakieś błędy, chętnie się o nich dowiem, by je usunąć.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: Implementacja funkcji map();

Postautor: mokrowski » sobota 25 mar 2017, 15:11

Zacząć trzeba od tego że map jako takie (co do konwencji), modyfikuje zawartość kontenera który otrzymuje. Stąd ja bym nie alokował żadnej pamięci w samej funkcji map. Inaczej pewnie było by w filter bo tam można dyskutować ale nie tego dotyczy pytanie...

No ale jeśli chcesz użyć konwencji innej to:
Przede wszystkim, czy wskaźnik 'result' nie powinien być static? Mam wrażenie, że nie, bo zwracam adres, a nie wartość...

Może nie być static.. Tu nie ma nawet widocznych powodów by był static.
Kolejna sprawa to argument formalny int *src w funkcji map_iter. Powinien być const? Wszak nie zmieniam żadnych wartości w kontenerze źródłowym.

Jeśli nie zmieniasz, dodaj const jako sygnał dla czytelnika że nie będziesz zmieniał.
Męczy mnie również fakt, że zwracam jedynie wskaźnik na kontener, a reszta programu nie ma pojęcia o jego wielkości.

Program poza ma pojęcie i więcej nic z tym nie zrobisz. Jeśli jednak chciałbyś, zwracam wtedy strukturę ze wskaźnikiem na pamięć i polem length lub 2 wskaźnikami gdzie 1 to początek pamięci a 2 to 1 wskaźnik za końcem kontenera.
No i na koniec zwalnianie pamięci. Wystarczy zwyczajne free(ptr), czy potrzebne są jakieś dodatkowe zabiegi?

Jak było malloc() to wystarczy free().
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Implementacja funkcji map();

Postautor: Antystatyczny » niedziela 26 mar 2017, 03:07

Wziąłem sobie do serca sugestie, a efekt jest następujący:

Kod: Zaznacz cały

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

/* typedef funkcji wartosciującej */
typedef int (unaryFuncType)(int obj);

/* Wersja iteracyjna funkcji map. Przyjmuje wskaźnik na kontener, rozmiar kontenera
   oraz  wskaźnik na funkcję wartosciującą. Zwraca wskaźnik na kontener zawierający efekt pracy
   funkcji wartosciującej na każdym elemencie kontenera.*/
int * map_iter(int *src, size_t len, unaryFuncType *fun);

/* Wersja rekurencyjna funkcji map.  */
int * map_r(int *src, size_t len, unaryFuncType *fun);

/* funkcja pomocnicza dla map_r */
void do_map(int *source, size_t length, unaryFuncType *function)
{
   if (length > 0)
   {
      *source = function(*source);
      return do_map(source + 1, --length, function);
   }
}

/* Pomocnicza funkcja do pokazywania efektów pracy */
void show_table(int *src, size_t len);

/* Przykladowa funkcja wartosciujaca. Odejmie od kazdego elementu kontenera 511. */
int subtract(int src);

int main(void)
{
   int ADC_Samples[] = { 150, 700, 400, 83, 1563, 18, 950, 1234, 37, 0, 44 };
   
   printf("Zawartosc kontenera  przed wywolaniem funkcji map():\n\n");
   show_table(ADC_Samples, sizeof(ADC_Samples) / sizeof(ADC_Samples[0]));
      
   printf("\nZawartosc kontenera po przejsciu przez map_r():\n\n");
   show_table(map_r(ADC_Samples, sizeof(ADC_Samples) / sizeof(ADC_Samples[0]), subtract),
      sizeof(ADC_Samples) / sizeof(ADC_Samples[0]));
   
   int key = getchar();

   return EXIT_SUCCESS;
}

int * map_iter(int *src, size_t len, unaryFuncType *fun)
{
   for (int i = 0; i < len; ++i)
   {
      src[i] = fun(src[i]);
   }

   return src;
}

int * map_r(int *src, size_t len, unaryFuncType *fun)
{

   do_map(src, len, fun);
   return src;
}

void show_table(int *src, size_t len)
{
   for (size_t i = 0; i < len; ++i)
   {
      printf("Wartosc elementu o indeksie %5d wynosi: %6d\n", i, src[i]);
   }
}

int subtract(int src)
{
   return src - 511;
}


Dodatkowo dopisałem rekurencyjną wersję pod nazwą map_r. Gdyby ktoś widział jakieś babole, to proszę wytknąć :)
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: Implementacja funkcji map();

Postautor: mokrowski » niedziela 26 mar 2017, 11:35

No i bardzo ok :-) Czas na filter a później króla algorytmów accumulate ? :-)
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Implementacja funkcji map();

Postautor: Antystatyczny » niedziela 26 mar 2017, 11:37

Tak, tak, dzisiaj będę męczył filter z alokacją i realokacją miejsca na dane wynikowe :) A rekurencję dobrze napisałem, czy średnio na jeża?
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.


Wróć do „Pisanie programów w C”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 3 gości