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

Sprawdzanie stosu wykorzystując struktury

VPS Starter Arubacloud
0 głosów
274 wizyt
pytanie zadane 19 czerwca 2018 w C i C++ przez Sic Dyskutant (8,510 p.)

Witam!

Za pomocą biblioteki <stack> chciałem wprowadzać i zdejmować na i z stosu elementy struktury, jednak mam problem z doborem typu std::stack<?> nazwa.

Bez poprawek (oraz zmian które zostaną dodane) tak wygląda obecnie kod. Moje pytanie jest jak wprowadzić do deklaracji std::stack typ danych zgodny ze strukturą podaną w kodzie?

#include <string>
#include <iostream>
#include <stack>
#include <cctype>
struct world
{
        std::string fullname;
        double payment;
};

void print_stack_size(std::stack <int> & first_stack);  
int main()
{
        std::size_t quantity = 10;
        std::stack <int> mystack;
        world people;
        char letter;

        print_stack_size(mystack);
        std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
        while(std::cin >> letter && toupper(letter) != 'D')
        {
                while(std::cin.get() != '\n') continue;
                if(!isalpha(letter)) { std::cout << '\a'; continue;};
                switch(toupper(letter))
                {
                        case 'A':
                                std::cout << "Wprowadź nazwę: "; std::cin >> people.fullname;
                                mystack.push(people.fullname);
                                std::cout << "Wprowadź wartość: "; std::cin >> people.payment;
                                mystack.push(people.payment);
                                print_stack_size(mystack);
                        break;
                        case 'S':
                                print_stack_size(mystack);
                                mystack.pop();
                                std::cout << "Ostatni dodany element został zdjęty!\n";
                                print_stack_size(mystack);
                        break;
                }//switch
                std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
        }//while
        std::cout << "Koniec programu!\n\n";
        return 0;
}//main

void print_stack_size(std::stack <int> & first_stack)
{
        if(first_stack.empty())
                std::cout << "Kontener jest pusty!\n";
        else
                std::cout << "Kontener posiada elementy: " << first_stack.size() << std::endl;
}

 

1 odpowiedź

+1 głos
odpowiedź 19 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
wybrane 21 czerwca 2018 przez Sic
 
Najlepsza

Naprawdę tryb minimalnych poprawek. Jeszcze jest dużo do zrobienia.

#include <string>
#include <iostream>
#include <stack>
#include <cctype>

struct world
{
    std::string fullname;
    double payment;
};

void print_stack_size(const std::stack<world>& first_stack);

int main() {
    std::size_t quantity = 10;
    std::stack <world> mystack;
    world people;
    char letter;

    print_stack_size(mystack);
    std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
    while(std::cin >> letter && toupper(letter) != 'D') {
        while(std::cin.get() != '\n') continue;
        if(!isalpha(letter)) {
            std::cout << '\a';
            continue;
        };
        switch(toupper(letter)) {
        case 'A':
            std::cout << "Wprowadź nazwę: ";
            std::cin >> people.fullname;
            std::cout << "Wprowadź wartość: ";
            std::cin >> people.payment;
            mystack.push(people);
            print_stack_size(mystack);
            break;
        case 'S':
            print_stack_size(mystack);
            if(mystack.empty()) {
                std::cout << "Nie mogę zdjąć elementu ze stosu. Stos jest pusty!\n";
            } else {
                mystack.pop();
                std::cout << "Element ze szczytu stosu został zdjęty!\n";
            }
            print_stack_size(mystack);
            break;
        }//switch
        std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
    }//while
    std::cout << "Koniec programu!\n\n";
}//main

void print_stack_size(const std::stack<world> & first_stack) {
    if(first_stack.empty()) {
        std::cout << "Kontener jest pusty!\n";
    } else {
        std::cout << "Kontener posiada elementy: " << first_stack.size() << std::endl;
    }
}

 

komentarz 20 czerwca 2018 przez Sic Dyskutant (8,510 p.)
Co masz na myśli mówiąc "dużo do zrobienia" ?
1
komentarz 20 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
Jako pierwsza.. rozsądna modularyzacja np. do funkcji. Dalej wydzielnie poleceń i akcji.
komentarz 20 czerwca 2018 przez Sic Dyskutant (8,510 p.)
Mam po prostu poprzenosić pewne elementy do funckji ?
1
komentarz 20 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
Na początek tak a później zobaczysz co jeszcze można zrobić aby kod był czytelny i pokazywał intencje.
komentarz 21 czerwca 2018 przez Sic Dyskutant (8,510 p.)

W sumie dodałem tylko jedną funkcję, dla większęj przejrzystości 'main'.

#include <string>
#include <iostream>
#include <stack>
#include <cctype>
struct world
{       
        std::string fullname;
        double payment;
};

void enter_text(world & person);
void print_stack_size(std::stack <world> & first_stack);
int main()
{
        std::size_t quantity = 10;
        std::stack <world> mystack;
        world people;
        char letter;

        print_stack_size(mystack);
        std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
        while(std::cin >> letter && toupper(letter) != 'D')
        {
                while(std::cin.get() != '\n') continue;
                if(!isalpha(letter)) { std::cout << '\a'; continue;};
                switch(toupper(letter))
                {
                        case 'A':
                                enter_text(people);
                                mystack.push(people);
                                print_stack_size(mystack);
                        break;
                        case 'S':
                                print_stack_size(mystack);
                                mystack.pop();
                                std::cout << "Ostatni dodany element został zdjęty!\n";
                                print_stack_size(mystack);
                        break;
                }//switch
                std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
        }//while
        std::cout << "Koniec programu!\n\n";
        return 0;
}//main

void enter_text(world & person)
{
        std::cout << "Wprowadź nazwę: "; std::cin >> person.fullname;
        std::cout << "Wprowadź wartość: "; std::cin >> person.payment;
}
void print_stack_size(std::stack <world> & first_stack)
{
        if(first_stack.empty())
                std::cout << "Kontener jest pusty!\n";
        else
                std::cout << "Kontener posiada elementy: " << first_stack.size() << std::endl;
}

Jedyne co mógłbym zrobić to podzielić program na dodatkowe pliki.

1
komentarz 21 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
1. Masz wprowadzające w błąd nazwy zmiennych i funkcji.

Co to jest word? Za chwilę nazywasz to people (a nie person która jest liczbą pojedynczą od people). Tak naprawdę ta struktura powinna nazywać się np. Transaction.

W read_text(...) przyjmujesz .. (world & person) ! Nie sądzisz że to tak opisowe jak kopanie(rower & nihilizm) :-) ? NIe lepiej nazwać tę funkcję create_people lub jak pisałem wcześniej create_transaction?

print_stack_size ... niby dopuszczalnie. Jednak chyba lepiej show_stack_condition.. tu się nie upieram. Upieram się jednak co do const które powinno się pojawić w tej referencji. Nie modyfikujesz stosu w tej funkcji.

2. Wydzielenie funkcji. W swojej aplikacji masz funkcję "wykonaj operację na stosie" a jak dokładniej się "wgryźć w temat" to "wybierz operację do wykonania na stosie" i "wykonaj operację na stosie".

3. Jakoś nie widzę użycia zmiennej quantity.

Hmm... zastanawiam się czy nie zepsuję Ci zabawy umieszczając propozycję implementacji. Jeśli będziesz chciał, umieszczę. Jednak będzie (z premedytacją) zawierała nowe elementy języka C++ które pojawiły się po 2014. Najpierw próbuj sam.
komentarz 21 czerwca 2018 przez Sic Dyskutant (8,510 p.)
edycja 21 czerwca 2018 przez Sic

1. Wprowadzone zmiany:

#include <string>
#include <iostream>
#include <stack>
#include <cctype>
struct Transaction
{       
        std::string fullname;
        double payment;
};

void create_transaction(Transaction & first_man);
void print_stack_size(const std::stack <Transaction> & first_stack);
int main()
{       
        std::stack <Transaction> mystack;
        Transaction people;
        char letter;
        
        print_stack_size(mystack);
        std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
        while(std::cin >> letter && toupper(letter) != 'D')
        {       
                while(std::cin.get() != '\n') continue;
                if(!isalpha(letter)) { std::cout << '\a'; continue;};
                switch(toupper(letter))
                {       
                        case 'A':
                                create_transaction(people);
                                mystack.push(people);
                                print_stack_size(mystack);
                        break;
                        case 'S':
                                print_stack_size(mystack);
                                mystack.pop();
                                std::cout << "Ostatni dodany element został zdjęty!\n";
                                print_stack_size(mystack);
                        break;
                }//switch
                 std::cout << "Wcisniej A (żeby dodać element do stosu), S (żeby przetworzyć element stosu) lub D (żeby zakoczyć)\n";
        }//while
        std::cout << "Koniec programu!\n\n";
        return 0;
}//main

void create_transaction(Transaction & first_man)
{
        std::cout << "Wprowadź nazwę: "; std::cin >> first_man.fullname;
        std::cout << "Wprowadź wartość: "; std::cin >> first_man.payment;
}
void print_stack_size(const std::stack <Transaction> & first_stack)
{
        if(first_stack.empty())
                std::cout << "Kontener jest pusty!\n";
        else
                std::cout << "Kontener posiada elementy: " << first_stack.size() << std::endl;
}

 

2. Nie rozumiem "punktu drugiego" twojej wypowiedzi.

3. Zawsze można zrobic osobną wersję programu z twoją propozycją.

Jakie to są elementy?

1
komentarz 21 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
edycja 21 czerwca 2018 przez mokrowski

A no to masz:

#include <iostream>
#include <string>
#include <stack>
#include <cctype>
#include <cstdlib>
#include <unordered_map>
#include <limits>
#include <functional>
#include <optional>
 
struct Transaction;

using stack_type = std::stack<Transaction>;
using command_type = std::optional<std::function<void(stack_type&)>>;
 
void show_stack_condition(const stack_type& transaction_stack);
void add_transaction_to(stack_type& transaction_stack);
[[nodiscard]] command_type find_command(char letter);
void remove_transaction_from(stack_type& transaction_stack);
[[nodiscard]] char read_upper_alpha(const std::string& msg);
[[nodiscard]] double read_double(const std::string& msg);
void process_command_on(stack_type& transaction_stack);
[[nodiscard]] Transaction read_transaction();

struct Transaction {
    std::string fullname;
    double payment;
};
 
int main() {
    // XXX: Nie wiem do czego ma służyć to quantity.
    //std::size_t quantity = 10; 
    stack_type mystack;
 
    show_stack_condition(mystack);
    process_command_on(mystack);
}
 
void show_stack_condition(const stack_type& transaction_stack) {
    if(transaction_stack.empty()) {
        std::cout << "Kontener jest pusty!\n";
    } else {
        std::cout << "Kontener posiada " << transaction_stack.size()
            << " ilość elementów.\n";
    }
}

[[nodiscard]] Transaction read_transaction() {
    Transaction transaction;
    std::cout << "Wprowadź nazwę: ";
    std::cin >> transaction.fullname;
    transaction.payment = read_double("Wprowadź wartość: ");
    return transaction;
}

void add_transaction_to(stack_type& transaction_stack) {
    transaction_stack.push(read_transaction());
}

void remove_transaction_from(stack_type& transaction_stack) {
    if(transaction_stack.empty()) {
        std::cout << "Nie mogę zdjąć elementu ze stosu. Stos jest pusty!\n";
    } else {
        transaction_stack.pop();
        std::cout << "Element ze szczytu stosu został zdjęty!\n";
    }
}

[[nodiscard]] double read_double(const std::string& msg) {
    std::cout << msg;
    double value;
    while(!(std::cin >> value)) {
        std::cout << '\a';
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    return value;
}

[[nodiscard]] char read_upper_alpha(const std::string& msg) {
    std::cout << msg;
    char letter;
    while((std::cin >> letter) && (!isalpha(letter))) {
        std::cout << '\a';
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    return toupper(letter);
}

[[nodiscard]] command_type find_command(char letter) {
    static const std::unordered_map<char, command_type::value_type> commandMap{
        {'A', [](auto& stk) { add_transaction_to(stk); }},
        {'S', [](auto& stk) { show_stack_condition(stk); remove_transaction_from(stk); }},
        {'D', [](auto& stk [[maybe_unused]]) { std::cout << "Koniec programu!\n\n"; exit(EXIT_SUCCESS); }}
    };
    auto it = commandMap.find(letter);
    if(it == commandMap.cend()) {
        return {};
    }
    return std::make_optional(it->second);
}

void process_command_on(stack_type& transaction_stack) {
    for(;;) {
        auto letter = read_upper_alpha(
                "Wciśnij A (żeby dodać element do stosu), "
                "S (żeby przetworzyć element stosu) lub "
                "D (żeby zakoczyć)\n"
        );
        auto command = find_command(letter);
        if(!command) {
            std::cout << "Nie ma takiego polecenia!\n";
            continue;
        }
        (*command)(transaction_stack);
        show_stack_condition(transaction_stack);
    }
}

Jeśli coś jest niezrozumiałe, pytaj...

PS optional występuje od C++17 https://en.cppreference.com/w/cpp/utility/optional

PS 2 Dodałem jeszcze atrybuty. Trochę na wyrost ale zawsze będziesz miał informację o czym poczytać :) https://en.cppreference.com/w/cpp/language/attributes

komentarz 21 czerwca 2018 przez Sic Dyskutant (8,510 p.)
edycja 21 czerwca 2018 przez Sic

Nie rozumiem kilku linii (oczywiście zapoznałem się z literaturą nagłówków)

1. Skąd się wzięło i co to jest 'find_command'?

command_type find_command(char letter);

2. Funkcja struktury (czyli jest możliwość tworzenia obiektów jako funkcje)?

Transaction read_transaction();

3. Co dokładnie robi ta linia ?

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Naprawdę potrzebna była do wypisania cała dodatkowa funkcja?

4. Przestrzeń i funckja (nie rozumiem o co tutaj chodzi), domyślam się jak może to wyglądać, ale nie rozumiem wykonania:

command_type find_command(char letter) {
    static const std::unordered_map<char, command_type::value_type> commandMap{
        {'A', [](auto& stk) { add_transaction_to(stk); }},
        {'S', [](auto& stk) { show_stack_condition(stk); remove_transaction_from(stk); }},
        {'D', [](auto& stk) { std::cout << "Koniec programu!\n\n";
                                                   exit(EXIT_SUCCESS); (void) stk;}}
    };
    auto it = commandMap.find(letter);
    if(it == commandMap.cend()) {
        return {};
    }
    return std::make_optional(it->second);
}
 
void process_command_on(stack_type& transaction_stack) {
    for(;;) {
        auto letter = read_upper_alpha(
                "Wciśnij A (żeby dodać element do stosu), "
                "S (żeby przetworzyć element stosu) lub "
                "D (żeby zakoczyć)\n"
        );
        auto command = find_command(letter);
        if(!command) {
            std::cout << "Nie ma takiego polecenia!\n";
            continue;
        }
        (*command)(transaction_stack);
        show_stack_condition(transaction_stack);
    }
}

5. W jaki sposób mogę skompilować (kod od  c++17) w kompilatorze 'g++' ?

code_prof.cpp:9:20: fatal error: optional: No such file or directory
compilation terminated.

 

komentarz 21 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
Ad. 1. command_type jest typem opcjonalnym. Może zwrócić funkcję do wykonania lub wartość pustą jeśli takiej funkcji nie ma. Nie będzie jej jeśli litera do wyboru funkcji będzie poza kluczami mapy (żadna z "ASD"). Wtedy find(..) z linii 8 dojdzie do końca kontenera czyli cend(). W przypadku zwrócenia funkcji, wystarczy ją uruchomić przesyłając argument w postaci stosu.

Ad. 2. Funkcja zwraca Transaction. Parametry do jego utworzenia wczytuje z konsoli.

Ad. 3. Jeśli użytkownik wpisał dane spoza zbioru oczekiwanych, ignore(...) powoduje "skonsumowanie" znaków do najbliższego '\n'. Z racji tego że nie wiadomo ile ich maksymalnie może być, maksymalną obsługiwaną na danej platformie wartość pobieram z std::limits<std::streamsize>::max().

Funkcja była potrzebna bo jeśli pytasz o wartość double, użytkownik może wprowadzić "ble ble ble" które jest stringiem. Podobnie dla litery może wprowadzić cyfrę a nie literę.

Ad. 4. process_command_on(...), wykonuje w pętli przetwarzanie komend. for(;;) jest pętlą nieskończoną. W 22 linii masz poszukiwanie komendy na podstawie znaku wczytanego w 17 linii. Linia 23 sprawdza czy znaleziono komendę czy nie (przypadek braku komendy masz w find_command(...) linia 10). Linia 27 w process_command_on(..) uruchamia komendę bo warunek sprawdził że istnieje (przypominam że find_command(...) zwraca opcję i komendy może nie być). Typ samej funkcji w mapie to std::function<void(std::stack<Transaction>&)> ale wyłuskałem go z command_type::value_type bo moim zdaniem jest bardziej opisowe skąd się to wzięło. Od C++17 lambda może mieć typ auto który sama wywnioskuje co oszczędziło mi "klepania" typu stosu.

Można dyskutować czy dla 'D' ładne jest takie "zerwanie sterowania" przez exit(...). Myślę że przykład jest na tyle mały że nie budzi to wątpliwości. Już i tak wyszło długie ale za to bardzo łatwe w utrzymaniu :)
komentarz 21 czerwca 2018 przez Sic Dyskutant (8,510 p.)
Dziękuję Ci za opis i pokazanie mi zaawansowanej strony tworzenia kodu. Moje umiejętności jeszcze nie pozwalają na stworzenie takiego programu, ale na pewno będę wzorował się na sposobie myślenia i wykorzystywaniu funkcji wbudowanych.

Podobne pytania

0 głosów
1 odpowiedź 382 wizyt
0 głosów
2 odpowiedzi 191 wizyt
pytanie zadane 22 października 2022 w Systemy operacyjne, programy przez TlenekWodoru Użytkownik (520 p.)
0 głosów
0 odpowiedzi 135 wizyt
pytanie zadane 24 września 2022 w Systemy operacyjne, programy przez Patrykosik88 Początkujący (340 p.)

92,452 zapytań

141,262 odpowiedzi

319,077 komentarzy

61,854 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

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 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!

...