Implementacja funkcji filter();

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 filter();

Postautor: Antystatyczny » niedziela 26 mar 2017, 21:02

Witam.

Nauki ciąg dalszy... Tym razem zadaniem domowym była implementacja funkcji filtrującej kontener z danymi. Funkcja przyjmuje wskaźnik na kontener, jego rozmiar oraz wskaźnik na funkcję filtrującą. Funkcja zwraca wskaźnik na zaalokowaną pamięć z przefiltrowanymi danymi oraz ilość elementów tychże danych. W kodzie obecne są dwie wersje funkcji filtrującej, czyli iteracyjna i rekurencyjna. Nie jestem pewien, czy w bezpieczny sposób użyłem realloc, ale to już ocenią mądrzejsi ode mnie. Oto kod:

Kod: Zaznacz cały

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

/* typedef funkcji wartościującej */
typedef bool (PredicateType)(const int src);

/* typedef rezultatu zwracanego przez filtr */
typedef struct
{
   int * output;
   size_t size;
}FilterOutputType;

/* Przykładowa funkcja wartościująca */
bool isGreaterThan200(int src)
{
   return (src > 200);
}

/* Filtr - wersja iteracyjna */
FilterOutputType  filter(const int *src, size_t size, PredicateType *predicate)
{
   FilterOutputType out =
   {
      .output = NULL,
      .size = 0
   };

   out.output = (int*) malloc(size * sizeof(src[0]));

   if (out.output == NULL)
   {
      perror("Memory allocation error\n");

      return out;
   }

   for (size_t i = 0; i < size; ++i)
   {
      if (predicate(src[i]) == false)
      {
         out.output[out.size++] = src[i];
      }
   }

   if (out.size < size)
   {
      realloc(out.output, out.size * sizeof(src[0]));//moze jakas kontrola alokacji?
   }

   return out;
}

/* Funkcja pomocnicza dla filter_r */

void do_filter(const int *src, int *dst, size_t size, size_t *count, PredicateType *fun)
{
   if (size > 0)
   {
      if (fun(*src) == false)
      {
         *dst = *src;
         dst++;
         *count = *count + 1;
      }

      do_filter(src + 1, dst, --size, count, fun);
   }
}

/*  Filtr - wersja rekurencyjna */
FilterOutputType  filter_r(const int *src, size_t size, PredicateType *predicate)
{
   FilterOutputType out =
   {
      .output = NULL,
      .size = 0
   };

   out.output = (int*) malloc(size * sizeof(src[0]));

   if (out.output == NULL)
   {
      perror("Memory allocation error\n");

      return out;
   }

   /* czary mary, czyli  wywołanie funkcji rekurencyjnej */
   do_filter(src, out.output, size, &out.size, predicate);
   
   if (out.size < size)
   {
      realloc(out.output, out.size * sizeof(src[0]));//moze jakas kontrola alokacji?
   }

   return out;
}

/* Pomocnicza funkcja do prezentacji danych */
void showData(const int *src, const size_t size)
{
   printf("\n\tCalkowita ilosc elementow wynosi %d\n\n", size);

   for (size_t i = 0; i < size; ++i)
   {
      printf("Wartosc elementu o indeksie %6d wynosi %6d\n", i, src[i]);
   }
}

int main(void)
{
   /* Jakieś tam dane... */
   int samples[] = { 100, 200, 300, -1000, 23, 750, 13456, 0, -32767, 200, 13, 80 };
   FilterOutputType result;


   /* Prezentacja danych wejsciowych */
   showData(samples, sizeof(samples) / sizeof(samples[0]));

   /* filtr iteracyjny usunie wszystkie elementy o wartosci powyzej 200 */
   result = filter(samples, sizeof(samples) / sizeof(samples[0]), isGreaterThan200);

   /* Prezentacja danych wyjsciowych */
   printf("\n\n\t Dane po przejsciu przez filtr iteracyjny:\n");
   showData(result.output, result.size);

   free(result.output);

   /* filtr rekurencyjny usunie wszystkie elementy o wartosci powyzej 200 */
   result = filter_r(samples, sizeof(samples) / sizeof(samples[0]), isGreaterThan200);

   /* Ponowna prezentacja danych wyjsciowych */
   printf("\n\n\t Dane po przejsciu przez filtr rekurencyjny:\n");
   showData(result.output, result.size);

   free(result.output);

   int key = getchar();
   return EXIT_SUCCESS;
}


Śmiało wytykać błędy :)

Pozdrawiam.
"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 filter();

Postautor: mokrowski » niedziela 26 mar 2017, 22:33

Co do zasady działania, filtr umieszcza te elementy w kontenerze wynikowym dla których predykat dał odpowiedź true. U Ciebie było odwrotnie co poprawiłem. Usunięte jest także użycie nagłówka <malloc.h>. Ja nawet takiego nie mam. Co to jest? Jeśli deklaracje funkcji malloc() to są w <stdlib.h>.
Dodałem także małą obsługę błędów dla realloc().
Oto poprawiony kod:

Kod: Zaznacz cały

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

/* typedef funkcji wartościującej */
typedef bool (PredicateType)(const int src);

/* typedef rezultatu zwracanego przez filtr */
typedef struct
{
   int * output;
   size_t size;
} FilterOutputType;

/* Przykładowa funkcja wartościująca */
bool isGreaterThan200(int src)
{
   return (src > 200);
}

/* Filtr - wersja iteracyjna */
FilterOutputType  filter(const int *src, size_t size, PredicateType *predicate)
{
   FilterOutputType out =
   {
      .output = NULL,
      .size = 0
   };

   out.output = (int*) malloc(size * sizeof(src[0]));

   if (out.output == NULL)
   {
      perror("Memory allocation error\n");

      return out;
   }

   for (size_t i = 0; i < size; ++i)
   {
      if (predicate(src[i]) == true)
      {
         out.output[out.size++] = src[i];
      }
   }

   if (out.size < size)
   {
      int * tmp = realloc(out.output, out.size * sizeof(src[0]));
      if(tmp == NULL)
      {
          perror("Memory re-allocation error.\n");
          free(out.output);
          out.output = NULL;
          return out;
      }
      out.output = tmp;
   }

   return out;
}

/* Funkcja pomocnicza dla filter_r */

void do_filter(const int *src, int *dst, size_t size, size_t *count, PredicateType *fun)
{
   if (size > 0)
   {
      if (fun(*src) == true)
      {
         *dst = *src;
         dst++;
         *count = *count + 1;
      }

      do_filter(src + 1, dst, --size, count, fun);
   }
}

/*  Filtr - wersja rekurencyjna */
FilterOutputType  filter_r(const int *src, size_t size, PredicateType *predicate)
{
   FilterOutputType out =
   {
      .output = NULL,
      .size = 0
   };

   out.output = (int*) malloc(size * sizeof(src[0]));

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

   /* czary mary, czyli  wywołanie funkcji rekurencyjnej */
   do_filter(src, out.output, size, &out.size, predicate);
   
   if (out.size < size)
   {
      int * tmp = realloc(out.output, out.size * sizeof(src[0]));
      if(tmp == NULL)
      {
          perror("Memory re-allocation error.\n");
          free(out.output);
          out.output = NULL;
          return out;
      }
      out.output = tmp;
   }

   return out;
}

/* Pomocnicza funkcja do prezentacji danych */
void showData(const int *src, const size_t size)
{
   printf("\n\tCalkowita ilosc elementow wynosi %zu\n\n", size);

   for (size_t i = 0; i < size; ++i)
   {
      printf("Wartosc elementu o indeksie %6zu wynosi %6d\n", i, src[i]);
   }
}

int main(void)
{
   /* Jakieś tam dane... */
   int samples[] = { 100, 200, 300, -1000, 23, 750, 13456, 0, -32767, 200, 13, 80 };
   FilterOutputType result;


   /* Prezentacja danych wejsciowych */
   showData(samples, sizeof(samples) / sizeof(samples[0]));

   /* filtr iteracyjny usunie wszystkie elementy o wartosci powyzej 200 */
   result = filter(samples, sizeof(samples) / sizeof(samples[0]), isGreaterThan200);

   /* Prezentacja danych wyjsciowych */
   printf("\n\n\t Dane po przejsciu przez filtr iteracyjny:\n");
   showData(result.output, result.size);

   free(result.output);

   /* filtr rekurencyjny usunie wszystkie elementy o wartosci powyzej 200 */
   result = filter_r(samples, sizeof(samples) / sizeof(samples[0]), isGreaterThan200);

   /* Ponowna prezentacja danych wyjsciowych */
   printf("\n\n\t Dane po przejsciu przez filtr rekurencyjny:\n");
   showData(result.output, result.size);

   free(result.output);

   getchar();
   return EXIT_SUCCESS;
}
,,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 filter();

Postautor: Antystatyczny » niedziela 26 mar 2017, 22:38

Ok, z tym malloc.h dałem ciała, ale jakoś tak mi podpowiedział VS2017 (a może sam sobie tak podpowiedziałem, a intellisense dokończył). A co do zasady działania, to chyba źle zrozumiałem, co przechodzi przez filtr, a co ma zostać usunięte. Ok, zapamiętam. Kontrola realokacji pamięci tak samo, jak w przypadku malloc. To również zapamiętam, dzięki.
"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 2 gości