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

question-closed Konstruktory wskaźniki C++ programowanie obiektowe

Object Storage Arubacloud
0 głosów
857 wizyt
pytanie zadane 31 grudnia 2019 w C i C++ przez MakaBresk Obywatel (1,060 p.)
zamknięte 6 stycznia 2020 przez MakaBresk

Mam do napisania program:

 

Napotkałem problem: chcę wyświetlić pierwszy element tablicy wskaźników w instrukcji switch case 87 - program przestaje działać. Tablica wskaźników zawiera u mnie stringi w postaci z = a+bj, które wprowadzam za pomocą funkcji ostringstream w case 78.
Jedyny błąd jaki mi wyświetla:

||=== Build: Debug in Zad3 (compiler: GNU GCC Compiler) ===|
H:\JiPP\Lab2\Zad3\main.cpp|11|warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11|
||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 1 second(s)) ===|
||=== Run: Debug in Zad3 (compiler: GNU GCC Compiler) ===|

 

Kod:

#include <iostream>
#include <cstdlib>  // W tym programie służy do obsługi funkcji exit
#include <sstream>  // Strumienie napisowe

using namespace std;

class LiczbaZespolona
{
    double Im, Re;
    string *tablica;    // Utworzenie tablicy wskaźników
    int n = 0;

public:
    // Konstruktor wywoływany podczas tworzenia obiektu klasy
    LiczbaZespolona(double = 0, double = 0, bool = false);    // Nadanie wartości domyślnych dla składowych klasy

    /* Mając taki konstruktor mamy tak na prawdę zestaw konstruktorów:
    LiczbaZespolona(double,double,bool)
    LiczbaZespolona(double,double)
    LiczbaZespolona(double)
    LiczbaZespolona()
    */

    ~LiczbaZespolona(); // Destruktor

    void utworzLiczbeZespolona()
    {
        cout << "Im = " << Im << endl;
        cout << "Re = " << Re << endl;
        cout << "n = " << n << endl;

        // Rezerwuje pamięć od pierwszego elementu tablicy
        tablica = new string[50];

        // Operacje na napisach - łączenie różnych typów obiektów na napisy i odwrotnie
        ostringstream ss;
        ss << "z = " << Re << "+" << Im << "j";

        if (n < 50)
        {
            tablica[n] = ss.str();  // Wpisanie do tablicy liczby zespolonej
            n++;
        }
        else
            cout << "Tablica zostala zapelniona!" << endl;
    }

    void wyswietlLiczbeZespolona()
    {
        cout << "tablica[0] = " << *tablica << endl;
        /*
        cout << "tablica[n] = " << tablica[i] << endl;
        if (tablica[i] != "")    // Sprawdzenie czy liczba zespolona o podanym indeksie jest w tablicy
            cout << tablica[i] << endl;
        else
            cout << "Liczba zespolona o podanym indeksie nie istnieje!" << endl;*/
    }
};

LiczbaZespolona::LiczbaZespolona(double i, double r, bool run)
{
    Im = i;
    Re = r;

    // Nadanie Im i Re tych samych wartości
    if (i != 0 && r == 0)
        Re = Im;

    if (run == true)
        utworzLiczbeZespolona();
}

LiczbaZespolona::~LiczbaZespolona()
{
    delete [] tablica;  // Usunięcie tablicy
}

int main()
{
    char menu;
    double cz_u = 0, cz_rz = 0;
    int indeks = 0;

    while (menu != 'K')
    {
        cout << "--------------------------------------------------------------" << endl;
        cout << "Co mam zrobic:" << endl;
        cout << "N. Utworz liczbe zespolona (2 argumenty)" << endl;
        cout << "R. Utworz li czbe zespolona (1 argument)" << endl;
        cout << "W. Wyswietl wartosc liczby zespolonej o podanym indeksie" << endl;
        cout << "+. Suma dwoch liczb zespolonych" << endl;
        cout << "-. Roznica dwoch liczb zespolonych" << endl;
        cout << "*. Iloczyn dwoch liczb zespolonych" << endl;
        cout << "/. Iloraz dwoch liczb zespolonych" << endl;
        cout << "K. Koniec programu" << endl;

        cout << "Wybierz: ";
        cin >> menu;

        switch (menu)
        {
            case 78:    //N
            {
                cout << "Podaj czesc rzeczywista Re(z): ";
                cin >> cz_rz;

                cout << "Podaj czesc urojona Im(z): ";
                cin >> cz_u;

                 LiczbaZespolona lz(cz_u,cz_rz,true);
            }
            break;

            case 82:    //R
            {
                cout << "Podaj czesc urojona Im(z): ";
                cin >> cz_u;

                LiczbaZespolona lz(cz_u,true);
            }
            break;

            case 87:    //W
            {
                cout << "Podaj indeks liczby zespolonej, ktora chcesz wyswietlic: ";
                cin >> indeks;

                LiczbaZespolona lz;
                lz.wyswietlLiczbeZespolona();
            }
            break;

            case 43:    //+
            {

            }
            break;

            case 45:    //-
            {

            }
            break;

            case 42:    //*
            {

            }
            break;

            case 47:    //slash
            {

            }
            break;

            case 75:    //K
                exit(0);    // Definitywne zakończenie programu
            break;

            default:
                cout << "Nie ma takiej opcji w menu!" << endl;
            break;
        }
    };

    return 0;
}

 

komentarz zamknięcia: Zrealizowany program

1 odpowiedź

+1 głos
odpowiedź 31 grudnia 2019 przez mokrowski Mędrzec (155,460 p.)
wybrane 1 stycznia 2020 przez MakaBresk
 
Najlepsza

A co to za pomysł by obsługa tablicy była w samej klasie? Przecież klasa nie powinna obsługiwać tablic. Także nie powinna obsługiwać wczytywania ze strumienia (tak jak wypisywania na strumień):

#include <iostream>

class LiczbaZespolona {
public:
    LiczbaZespolona();
    explicit LiczbaZespolona(double wartosc);
    LiczbaZespolona(double im, double re);
    double real() const;
    double imag() const;
private:
    double im;
    double re;
};

LiczbaZespolona::LiczbaZespolona()
    : im(0.0), re(0.0) {}

LiczbaZespolona::LiczbaZespolona(double wartosc)
    : im(wartosc), re(wartosc) {}

LiczbaZespolona::LiczbaZespolona(double im_, double re_)
    : im(im_), re(re_) {}

double LiczbaZespolona::real() const {
    return re;
}

double LiczbaZespolona::imag() const {
    return im;
}

std::ostream& operator<<(std::ostream& os, const LiczbaZespolona& lz) {
    return os << '(' << lz.real() << ", " << lz.imag() << ')';
}

int main() {
    LiczbaZespolona lz1;
    LiczbaZespolona lz2(42.3);
    LiczbaZespolona lz3(14.1, 553.1);
    std::cout << lz1 << ' ' << lz2 << ' ' << lz3 << '\n';
}

 

komentarz 6 stycznia 2020 przez tkz Nałogowiec (42,000 p.)
Tą którą byś zarezerwował W KLASIE, nie poza nią.
komentarz 6 stycznia 2020 przez MakaBresk Obywatel (1,060 p.)

Aha, wszystko jasne.
Dziękuję wam Panowie za pomoc.

Jakieś uwagi dotyczące kodu, oprócz braku obsługi błędów dla cin?

main.cpp

#include <iostream>
#include <cstdlib>  // W tym programie służy do obsługi funkcji exit
#include <sstream>  // Strumienie napisowe
#include <iomanip>  // Manipulacja strumieniami wejścia-wyjścia
#include <cmath>    // Funkcje matematyczne
#include "liczbaZespolona.h"    // Dołączam plik nagłówkowy zawierający spis treści klasy (atrybuty + metody)

using namespace std;

// Funkcja operatorowa
// & - podaje referencję do obiektu ostream
ostream& operator<< (ostream &os, const LiczbaZespolona &lz) // Przeciążenie operatora <<
{
    return os << "(" << lz.real() << "," << lz.imag() << ")" << endl;
}

// Operator dodawania 2 liczb zespolonych
LiczbaZespolona operator+ (const LiczbaZespolona &lz1, const LiczbaZespolona &lz2) // Przeciążenie operatora + na 2 obiektach
{
    return LiczbaZespolona(lz1.real() + lz2.real(), lz1.imag() + lz2.imag());
}

// Operator odejmowania 2 liczb zespolonych
LiczbaZespolona operator- (const LiczbaZespolona &lz1, const LiczbaZespolona &lz2) // Przeciążenie operatora - na 2 obiektach
{
    return LiczbaZespolona(lz1.real() - lz2.real(), lz1.imag() - lz2.imag());
}

// Operator mnożenia 2 liczb zespolonych
LiczbaZespolona operator* (const LiczbaZespolona &lz1, const LiczbaZespolona &lz2) // Przeciążenie operatora * na 2 obiektach
{
    return LiczbaZespolona(((lz1.real() * lz2.real()) - (lz1.imag() * lz2.imag())), ((lz1.real() * lz2.imag()) + (lz1.imag() * lz2.real())));
}

// Operator dzielenia 2 liczb zespolonych
LiczbaZespolona operator/ (const LiczbaZespolona &lz1, const LiczbaZespolona &lz2) // Przeciążenie operatora / na 2 obiektach
{
    return LiczbaZespolona((((lz1.real() * lz2.real()) + (lz1.imag() * lz2.imag())) / (pow(lz2.real(),2) + (pow(lz2.imag(),2)))) , (((lz1.imag() * lz2.real()) - (lz1.real() * lz2.imag())) / (pow(lz2.real(),2) + (pow(lz2.imag(),2)))));
}

int main()
{
    char wyborMenu;
    double cz_u, cz_rz;
    int max_liczb_zespolonych = 100;
    LiczbaZespolona *tabLZ[max_liczb_zespolonych];   // Tablica wskaźników do obiektów klasy LiczbaZespolona
    int i = 0;  // Indeks tablicy wskaźników

    // Wypełnienie tablicy wskaźników pustymi wskaźnikami null, aby na nic nie wskazywały
    for (int j = 0; j < max_liczb_zespolonych; j++)
        tabLZ[j] = nullptr;

    while (wyborMenu != 'K')
    {
        cz_rz = 0;
        cz_u = 0;

        cout << "--------------------------------------------------------------" << endl;
        cout << "Co mam zrobic:" << endl;
        cout << "N. Utworz liczbe zespolona (2 argumenty)" << endl;
        cout << "R. Utworz liczbe zespolona (1 argument)" << endl;
        cout << "W. Wyswietl wartosc liczby zespolonej o podanym indeksie" << endl;
        cout << "+. Suma dwoch liczb zespolonych" << endl;
        cout << "-. Roznica dwoch liczb zespolonych" << endl;
        cout << "*. Iloczyn dwoch liczb zespolonych" << endl;
        cout << "/. Iloraz dwoch liczb zespolonych" << endl;
        cout << "K. Koniec programu" << endl;
        cout << endl;

        cout << "Wybierz: ";
        cin >> wyborMenu;
        cout << endl;

        switch (wyborMenu)
        {
            case 'N':
            {
                // Sprawdzenie czy mozna zapisac kolejna liczbe zespolona do tablicy
                if (i < max_liczb_zespolonych)
                {
                    cout << "Podaj czesc rzeczywista Re(z): ";
                    cin >> cz_rz;

                    cout << "Podaj czesc urojona Im(z): ";
                    cin >> cz_u;

                    // Rezerwuję pamięć na wartość liczby zespolonej operatorem new
                    tabLZ[i] = new LiczbaZespolona(cz_rz,cz_u); // Przypisanie wartości poprzez wywołanie konstruktora
                    i++;    // Zwiększenie indeksu tablicy
                }
                else
                    cout << "Tablica zostala zapelniona!" << endl;
            }
            break;

            case 'R':
            {
                // Sprawdzenie czy mozna zapisac kolejna liczbe zespolona do tablicy
                if (i < max_liczb_zespolonych)
                {
                    cout << "Podaj czesc urojona Im(z): ";
                    cin >> cz_u;

                    // Rezerwuję pamięć na wartość liczby zespolonej operatorem new
                    tabLZ[i] = new LiczbaZespolona(cz_u); // Przypisanie wartości składowym klasy poprzez wywołanie konstruktora
                    i++;    // Zwiększenie indeksu tablicy
                }
                else
                    cout << "Tablica zostala zapelniona!" << endl;
            }
            break;

            case 'W':
            {
                int i_user = 0;

                cout << "Podaj indeks liczby zespolonej: ";
                cin >> i_user;

                // Sprawdzenie czy wskaźnik zawiera pusty wskaźnik null
                if (tabLZ[i_user] == nullptr)
                    cout << "Liczba zespolona o podanym indeksie nie istnieje! Dodaj ja poprzez opcje: N" << endl;

                // Sprawdzenie czy użytkownik nie chce wyświetlić liczby zespolonej poza zakresem tablicy
                else if (i_user >= max_liczb_zespolonych)
                    cout << "Maksymalny indeks liczby zespolonej: " << max_liczb_zespolonych-1 << endl;
                else
                    // Jeżeli nie, wyświetla zawartość zapisaną pod danym wskaźnikiem
                    cout << *tabLZ[i_user];
            }
            break;

            case '+':
            {
                int i_lz1 = 0, i_lz2 = 0;
                cout << "Podaj indeksy liczb zespolonych, ktore chcesz dodac: " << endl;
                cin >> i_lz1;
                cin >> i_lz2;

                // Sprawdzenie czy wskaźnik zawiera pusty wskaźnik null
                if (tabLZ[i_lz1] == nullptr || tabLZ[i_lz2] == nullptr)
                    cout << "Liczby zespolone o podanych indeksach nie istnieja! Dodaj je poprzez opcje: N" << endl;

                // Sprawdzenie czy użytkownik nie chce wyświetlić liczby zespolonej poza zakresem tablicy
                else if (i_lz1 > max_liczb_zespolonych-2 || i_lz2 > max_liczb_zespolonych-2)
                    cout << "Maksymalny indeks liczby zespolonej: " <<  max_liczb_zespolonych-2 << endl;
                else
                {
                    int i_start = i;

                    cout << "Liczba zespolona 1:" << endl;
                    cout << *tabLZ[i_lz1] << endl;

                    cout << "Liczba zespolona 2:" << endl;
                    cout << *tabLZ[i_lz2] << endl;

                    // Wyświetlenie dla wyniku tylko 2 miejsc po przecinku
                    cout << setprecision(2);
                    cout << "Wynik: " << (*tabLZ[i_lz1])+(*tabLZ[i_lz2]);

                    // Zapisanie wyniku do kolejnej szufladki tablicy wskaźników, operatorem new rezerwuję pamieć dla kolejnej liczby zespolonej
                    while (i > i_lz2+1)
                        i--;

                    tabLZ[i] = new LiczbaZespolona((*tabLZ[i_lz1])+(*tabLZ[i_lz2]));
                    cout << "Indeks wyniku: " << i << endl;

                    i = i_start; // Zresetowanie wartości indeksu i tablicy
                }
            }
            break;

            case '-':
            {
                int i_lz1 = 0, i_lz2 = 0;
                cout << "Podaj indeksy liczb zespolonych, ktore chcesz dodac: " << endl;
                cin >> i_lz1;
                cin >> i_lz2;

                // Sprawdzenie czy wskaźnik zawiera pusty wskaźnik null
                if (tabLZ[i_lz1] == nullptr || tabLZ[i_lz2] == nullptr)
                    cout << "Liczby zespolone o podanych indeksach nie istnieja! Dodaj je poprzez opcje: N" << endl;

                // Sprawdzenie czy użytkownik nie chce wyświetlić liczby zespolonej poza zakresem tablicy
                else if (i_lz1 > max_liczb_zespolonych-2 || i_lz2 > max_liczb_zespolonych-2)
                    cout << "Maksymalny indeks liczby zespolonej: " <<  max_liczb_zespolonych-2 << endl;
                else
                {
                    int i_start = i;

                    cout << "Liczba zespolona 1:" << endl;
                    cout << *tabLZ[i_lz1] << endl;

                    cout << "Liczba zespolona 2:" << endl;
                    cout << *tabLZ[i_lz2] << endl;

                    // Wyświetlenie dla wyniku tylko 2 miejsc po przecinku
                    cout << setprecision(2);
                    cout << "Wynik: " << (*tabLZ[i_lz1])-(*tabLZ[i_lz2]);

                    // Zapisanie wyniku do kolejnej szufladki tablicy wskaźników, operatorem new rezerwuję pamieć dla kolejnej liczby zespolonej
                    while (i > i_lz2+1)
                        i--;

                    tabLZ[i] = new LiczbaZespolona((*tabLZ[i_lz1])-(*tabLZ[i_lz2]));
                    cout << "Indeks wyniku: " << i << endl;

                    i = i_start; // Zresetowanie wartości indeksu i tablicy
                }
            }
            break;

            case '*':
            {
                int i_lz1 = 0, i_lz2 = 0;
                cout << "Podaj indeksy liczb zespolonych, ktore chcesz dodac: " << endl;
                cin >> i_lz1;
                cin >> i_lz2;

                // Sprawdzenie czy wskaźnik zawiera pusty wskaźnik null
                if (tabLZ[i_lz1] == nullptr || tabLZ[i_lz2] == nullptr)
                    cout << "Liczby zespolone o podanych indeksach nie istnieja! Dodaj je poprzez opcje: N" << endl;

                // Sprawdzenie czy użytkownik nie chce wyświetlić liczby zespolonej poza zakresem tablicy
                else if (i_lz1 > max_liczb_zespolonych-2 || i_lz2 > max_liczb_zespolonych-2)
                    cout << "Maksymalny indeks liczby zespolonej: " <<  max_liczb_zespolonych-2 << endl;
                else
                {
                    int i_start = i;

                    cout << "Liczba zespolona 1:" << endl;
                    cout << *tabLZ[i_lz1] << endl;

                    cout << "Liczba zespolona 2:" << endl;
                    cout << *tabLZ[i_lz2] << endl;

                    // Wyświetlenie dla wyniku tylko 2 miejsc po przecinku
                    cout << setprecision(2);
                    cout << "Wynik: " << (*tabLZ[i_lz1])*(*tabLZ[i_lz2]);

                    // Zapisanie wyniku do kolejnej szufladki tablicy wskaźników, operatorem new rezerwuję pamieć dla kolejnej liczby zespolonej
                    while (i > i_lz2+1)
                        i--;

                    tabLZ[i] = new LiczbaZespolona((*tabLZ[i_lz1])*(*tabLZ[i_lz2]));
                    cout << "Indeks wyniku: " << i << endl;

                    i = i_start; // Zresetowanie wartości indeksu i tablicy
                }
            }
            break;

            case '/':
            {
                int i_lz1 = 0, i_lz2 = 0;
                cout << "Podaj indeksy liczb zespolonych, ktore chcesz dodac: " << endl;
                cin >> i_lz1;
                cin >> i_lz2;

                // Sprawdzenie czy wskaźnik zawiera pusty wskaźnik null
                if (tabLZ[i_lz1] == nullptr || tabLZ[i_lz2] == nullptr)
                    cout << "Liczby zespolone o podanych indeksach nie istnieja! Dodaj je poprzez opcje: N" << endl;

                // Sprawdzenie czy użytkownik nie chce wyświetlić liczby zespolonej poza zakresem tablicy
                else if (i_lz1 > max_liczb_zespolonych-2 || i_lz2 > max_liczb_zespolonych-2)
                    cout << "Maksymalny indeks liczby zespolonej: " <<  max_liczb_zespolonych-2 << endl;
                else
                {
                    int i_start = i;

                    cout << "Liczba zespolona 1:" << endl;
                    cout << *tabLZ[i_lz1] << endl;

                    cout << "Liczba zespolona 2:" << endl;
                    cout << *tabLZ[i_lz2] << endl;

                    // Wyświetlenie dla wyniku tylko 2 miejsc po przecinku
                    cout << setprecision(2);
                    cout << "Wynik: " << (*tabLZ[i_lz1])/(*tabLZ[i_lz2]);

                    // Zapisanie wyniku do kolejnej szufladki tablicy wskaźników, operatorem new rezerwuję pamieć dla kolejnej liczby zespolonej
                    while (i > i_lz2+1)
                        i--;

                    tabLZ[i] = new LiczbaZespolona((*tabLZ[i_lz1])/(*tabLZ[i_lz2]));
                    cout << "Indeks wyniku: " << i << endl;

                    i = i_start; // Zresetowanie wartości indeksu i tablicy
                }
            }
            break;

            case 'K':
                exit(0);    // Definitywne zakończenie programu
            break;

            default:
                cout << "Nie ma takiej opcji w menu!" << endl;
            break;
        }
    };

    // Usunięcie tablicy wskaźników
    for (int j = 0; j < max_liczb_zespolonych; j++)
        delete tabLZ[j];

    return 0;
}
komentarz 6 stycznia 2020 przez MakaBresk Obywatel (1,060 p.)

liczbaZespolona.h

#include <iostream>

using namespace std;

class LiczbaZespolona
{
    double Re, Im;

public:
    LiczbaZespolona();
    explicit LiczbaZespolona(double wartosc); // explicit - jawne castowanie typów
    // Wytłumaczenie co oznacza explicit - https://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-mean
    LiczbaZespolona(double re_, double im_);

    // Metody - funkcje wewnątrz klasy
    double real() const;    // Słowo klucze const oznacza, że funkcja nie zmienia nic w klasie
    double imag() const;
    LiczbaZespolona& operator= (const LiczbaZespolona&);
};

liczbaZespolona.cpp

#include <iostream>
#include "liczbaZespolona.h"    // Dołączam plik nagłówkowy zawierający spis treści klasy (atrybuty + metody)

using namespace std;

// Nadanie wartości w trakcie tworzenia klasy, a nie po jej utworzeniu
LiczbaZespolona::LiczbaZespolona()  :   Re(0.0), Im(0.0)  {}
LiczbaZespolona::LiczbaZespolona(double wartosc)  : Re(wartosc), Im(wartosc)    {}
LiczbaZespolona::LiczbaZespolona(double re_, double im_)    :   Re(re_), Im(im_)    {}

// const - oznajmienie, że funkcja nie zmienia nic w klasie
double LiczbaZespolona::real() const
{
    return Re;
}

// const - oznajmienie, że funkcja nie zmienia nic w klasie
double LiczbaZespolona::imag() const
{
    return Im;
}

// Przeciążenie operatora =
LiczbaZespolona &LiczbaZespolona ::operator= (const LiczbaZespolona &lz)
{
    // Sprawdzenie czy nie przypisujemy do obiektu samego siebie
    if (&lz != this)
    {
        Re = lz .Re;
        Im = lz .Im;
    }
    // Zwrócenie referencji do samego siebie
    return *this;
}

 

komentarz 6 stycznia 2020 przez tkz Nałogowiec (42,000 p.)
main.cpp 46. i 47. linia VLA nie jest dozwolone w C++.

44. linia, wyborMenu jest niezainicjowane.

Brak operator "==" dla klasy. No i jeszcze pewnie sporo więcej,
komentarz 6 stycznia 2020 przez MakaBresk Obywatel (1,060 p.)
Ok, dziękuję.
W takim razie zostawiam ten program do ewentualnych przeróbek w przyszłości.
Temat zamykam.

Podobne pytania

0 głosów
1 odpowiedź 176 wizyt
0 głosów
1 odpowiedź 177 wizyt
0 głosów
2 odpowiedzi 1,191 wizyt

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 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!

...