• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

"Niby pętla, ale bez pętli"

Object Storage Arubacloud
0 głosów
252 wizyt
pytanie zadane 2 maja 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)
edycja 2 maja 2020 przez Patrycjerz

Czołem :)

Mam do wykonania zadanie, do którego wymagane mam użycie wskaźników na funkcję oraz rekurencji (z tym ostatnim o ile oczywiście myślę poprawnie).

Oto treść:

Napisz proceduralny odpowiednik pętli for o nazwie for_loop. Procedura ta ma przyjmować 4 argumenty, w następującej kolejności:

wartość początkową iteratora,
wartość kroku iteratora,
wartość końcową iteratora,
wskaźnik na funkcję iterującą.
W funkcji for_loop przyjmij, że iteracje mogą być wykonywanie wyłącznie od wartości początkowej do wartości końcowej z podanym krokiem.

Jako typ iteratora przyjmij double.

Odpowiednik pętli for ma wywoływać funkcję iterującą (4 argument) w taki sam sposób, jak pętla for uruchamia swój kod. Funkcja iterująca powinna przyjmować jeden argument typu double i nie zwracać żadnej wartości (ma być procedurą).

Do testów przygotuj funkcje iterujące, które będą wyświetlać (wszystkie przykłady dla wywołania for_loop start=0, krok=10, stop=40):

Wartość parametru (funkcja print_value).
Przykład: 0 10 20 30.
Skumulowaną wartość parametru (funkcja print_accumulated).
Przykład: 0 10 30 60.
Kwadrat argumentu (funkcja print_square).
Przykład: 0 100 400 900.
Moduł argumentu (funkcja print_abs).
Przykład: 0 10 20 30.
Deklaracje wszystkich funkcji umieść w pliku nagłówkowym for_loop.h, a definicje w pliku for_loop.c.

Przykładowe wywołanie funkcji for_loop powinno wyglądać następująco:

for_loop(0, 10, 40, print_value);
Wynik:

0 10 20 30
Napisz program, który uruchomi funkcję for_loop dla danych oraz typu funkcji podanych przez użytkownika.

W tym celu pobierz wartość: początkową, krok oraz wartość końcową iteratora od użytkownika i sprawdź, czy są one poprawne.

Następnie pobierz i sprawdź rodzaj funkcji do wykonania w postaci liczby całkowitej, z wartościami o następującym znaczeniu:

0 - funkcja print_value,

1 - funkcja print_accumulated,

2 - funkcja print_square,

3 - funkcja print_abs.

W przypadku podania błędnych danych program powinien wyświetlić komunikat Incorrect input data i zakończyć działanie z kodem błędu 2.

W przypadku wprowadzenia przez użytkownika błędnych znaków program powinien wyświetlić komunikat Incorrect input i niezwłocznie zakończyć działanie z kodem błędu 1.

Jeżeli dane wejściowe są poprawne, to program ma wywołać funkcję for_loop z parametrami o wczytanych wartościach.

Zadeklaruj w funkcji main tablicę wskaźników na podane funkcje (o nazwie funcs) i przypisz do kolejnych komórek adresy poszczególnych funkcji. Korzystaj z tej tablicy do wyboru funkcji iterującej.

Przykładowa interakcja z programem -- sukces:

Podaj poczatek, krok i koniec przedzialu: -5.396646 0.589966 6.782289⏎
Podaj rodzaj operacji: 1⏎
-5.396646 -10.203326 -14.420040 -18.046788 -21.083570 -23.530386 -25.387236 -26.654120 -27.331038 -27.417990 -26.914976 -25.821996 -24.139050 -21.866138 -19.003260 -15.550416 -11.507606 -6.874830 -1.652088 4.160620 10.563294 
Przykładowa interakcja z programem -- błąd danych wejściowych:

Podaj poczatek, krok i koniec przedzialu: 5.438089 GLfRcfZbw 9.575884⏎
Incorrect input
Podaj poczatek, krok i koniec przedzialu: 8.832101 -0.527650 29.165311⏎
Incorrect input data
Podaj poczatek, krok i koniec przedzialu: 9.090990 -0.693981 -2.284145⏎
Podaj rodzaj operacji4⏎
Incorrect input data
Podaj poczatek, krok i koniec przedzialu: tmRkmhXCZ 6.077097 6.975625⏎
Incorrect input
Podaj poczatek, krok i koniec przedzialu: -6.890850 5.006669 6.025982⏎
Podaj rodzaj operacjizOXOz⏎
Incorrect input
Uwaga

W programie nie wolno używać pętli oraz goto!
W programie nie wolno używać operatora [], za wyjątkiem deklaracji tablicy.

Rozpisałem kod do zadania.

Plik main.c :

#include <stdio.h>
#include <stdlib.h>
#include "for_loop.h"

int main()
{
    void (*funcs[])(double)={&print_value,&print_accumulated,&print_square,&print_abs};
    printf("Podaj poczatek, krok i koniec przedzialu: ");
    double start,step,ending;
    if(scanf("%lf %lf %lf",&start,&step,&ending)!=3)
    {
        printf("Incorrect input");
        return 1;
    }
    if( step == 0 )
    {
        printf("Incorrect input data");
        return 2;
    }
    if( start > ending && step > 0 )
    {
        printf("Incorrect input data");
        return 2;
    }
    if( start < ending && step < 0 )
    {
        printf("Incorrect input data");
        return 2;
    }
    printf("Podaj rodzaj operacji: ");
    int wybor;
    if(scanf("%d",&wybor)!=1)
    {
        printf("Incorrect input");
        return 1;
    }
    if( wybor < 0 || wybor > 3 )
    {
        printf("Incorrect input data");
        return 2;
    }
    for_loop(start,step,ending,*(funcs + wybor));
    return 0;
}

Plik for_loop.c:

#include <stdio.h>
#include <stdlib.h>
#include "for_loop.h"
#include <math.h>
void for_loop(double start, double step, double ending,void (*pointer)(double))
{
    if(start >= ending && step > 0 )
    {
        return;
    }
    if(start <= ending && step < 0 )
    {
        return;
    }
    if( pointer != print_value && pointer != print_accumulated && pointer != print_square && pointer != print_abs )
    {
        return;
    }
    else
    {
        pointer(start);
        start += step;
        for_loop(start,step,ending,pointer);
    }


}
void print_value(double a)
{
    printf("%f ",a);
}
void print_accumulated(double a)
{
    double temp = a * 2;
    a += temp;
    printf("%f ",a);
}
void print_square(double a)
{
    if( a < 0 )
    {
        a *= (-1);
    }
    printf("%f ",pow(a,2.0));
}
void print_abs(double a)
{
    if( a < 0 )
    {
        a *= -1;
    }
    printf("%f ",a);
}

Na tą chwilę miałbym prośbę, abyście wypowiedzieli się w kwestii ewentualnych zabezpieczeń przed błędami użytkownika przy wprowadzaniu danych oraz poprawieniu funkcji print_accumulated.

1 odpowiedź

+1 głos
odpowiedź 2 maja 2020 przez Patrycjerz Mędrzec (192,320 p.)
wybrane 2 maja 2020 przez Hubertius
 
Najlepsza
  1. Warunki zabezpieczające przed wprowadzeniem niepoprawnych, wg logiki programu, wartości liczbowych, mógłbyś złączyć w jedną instrukcję `if`. Nie jest to nic obligatoryjnego, gdyż redundancji kodu nie ma zbyt wiele, ale warto i tak skracać kod źródłowy.
  2. Przy podawaniu adresu funkcji nie jest konieczne używanie operatora `&` – wystarczy tylko nazwa funkcji.
  3. Funkcja `print_accumulated`, wg opisu zadania, ma niepoprawną implementację. Zapewne miałeś problem z zachowaniem tymczasowej sumy pomiędzy wywołaniami funkcji. Jako że wskaźnik na funkcję musi mieć typ z treści zadania, to możesz użyć zmiennej statycznej:
    void print_accumulated(double a)
    {
        static double sum = 0.0;
        sum += a;
        printf("%f ", sum);
    }

    Definicja i inicjalizacja zmiennej `sum` wykona się tylko raz, podczas załadowania procesu w systemie operacyjnym, więc nie musisz się bać, że za każdym razem suma wyniesie `a` (zero plus wartość `a`).

  4. Funkcja `print_square` nie potrzebuje warunku sprawdzającego wartość mniejszą niż zero. Przecież podnoszenie liczby rzeczywistej do potęgi drugiej "likwiduje" ten znak, czyli np. (-5)^2 = 25 oraz 5^2 = 25.

  5. Wg mnie bardziej zrozumiałe jest przypisanie wartości przeciwnej niż mnożenie przez -1:

    void print_abs(double a)
    {
        if( a < 0 )
        {
            a = -a;
        }
        printf("%f ",a);
    }

    To tylko moje upodobanie i oprócz względów kosmetycznych nie ma to chyba znaczenia w kodzie wynikowym programu.

Podobne pytania

+2 głosów
2 odpowiedzi 399 wizyt
pytanie zadane 26 grudnia 2021 w C i C++ przez Dynamic Bywalec (2,910 p.)
0 głosów
0 odpowiedzi 172 wizyt
pytanie zadane 29 kwietnia 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)
0 głosów
1 odpowiedź 141 wizyt
pytanie zadane 11 stycznia 2020 w C i C++ przez amtrax Dyskutant (9,630 p.)

92,551 zapytań

141,393 odpowiedzi

319,523 komentarzy

61,936 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...