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

Sprawdzanie stosu wykorzystując struktury

0 głosów
54 wizyt
pytanie zadane 19 czerwca 2018 w C i C++ przez Sic Mądrala (7,330 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 VIP (110,820 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 21 czerwca 2018 przez Sic Mądrala (7,330 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 VIP (110,820 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 Mądrala (7,330 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 VIP (110,820 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 Mądrala (7,330 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ź 95 wizyt
0 głosów
2 odpowiedzi 91 wizyt
pytanie zadane 14 października 2018 w C i C++ przez periedynek Obywatel (1,320 p.)
0 głosów
2 odpowiedzi 262 wizyt
pytanie zadane 4 sierpnia 2017 w C i C++ przez Jakub 0 Stary wyjadacz (13,240 p.)
Porady nie od parady
Odznacz odpowiedź zieloną fajką, jeśli uważasz, że jest ona najlepsza ze wszystkich i umożliwiła ci rozwiązanie problemu.Najlepsza odpowiedź

66,453 zapytań

113,208 odpowiedzi

239,681 komentarzy

46,704 pasjonatów

Przeglądających: 255
Pasjonatów: 10 Gości: 245

Motyw:

Akcja Pajacyk

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

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...