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

Największa, najmniejsza wartość obiektowo (C++)

Object Storage Arubacloud
0 głosów
717 wizyt
pytanie zadane 13 czerwca 2018 w C i C++ przez Sic Dyskutant (8,510 p.)
edycja 13 czerwca 2018 przez Sic

Witam napisałem program, który wyznacza z tablicy wartości największą, najmniejszą i pokazuje średnią.

Program się włącza, jednak dane są domyślne. Dlaczego przyjmuje wartości domyślne a nie te, które zostały zaincjalizowane?

plik nagłówkowy:

#ifndef DANE_H_
#define DANE_H_

namespace SALES
{
        class Sales
        {
                private:
                        static const int QUARTERS = 4;
                        double sale[QUARTERS];
                        double average, max, min;
                public:
                        Sales(double * sales, const int QUARTERS);
                        Sales();
                        void showSales();
        };
}
#endif

plik deklaracji (próbowałem też tutaj zainicjalizować tablicę, jednak również był ten sam efekt):

#include "dane.h"
#include <iostream>

SALES::Sales::Sales(double * sale, const int QUARTERS)
{
        this->min = this->sale[0];
        this->max = this->sale[0];
        this->average = 0;
        for(int i=0; i<this->QUARTERS; i++)
        {
                if(this->sale[i] > this->max)
                        this->max = this->sale[i];
                if(this->sale[i] < this->min)
                        this->min = this->sale[i]; 
                this->average += this->sale[i];
        }
        std::cout << "Największa wartość: " << this->max << "\nNajmniejsza wartość: " << this->min << "\nŚrednia wartość: " << this->average/this->QUARTERS << std::endl;
}

void SALES::Sales::showSales()
{
        std::cout << "Największa wartość: " << max << "\nNajmniejsza wartość: " << min << "\nŚrednia wartość: " << average/QUARTERS << std::endl;
}

plik główny:

#include "dane.h"
#include <iostream>

int main()
{
        double table[4] = {22.11, 3.55, 33.55, 3.56};
        SALES::Sales object(table, 4);
        std::cout << "\n\n";
        object.showSales();
        return 0;
}

 

komentarz 13 czerwca 2018 przez Bondrusiek Maniak (61,370 p.)
Jakie jest pytanie do tego tematu bo za bardzo nie wiem o co Ci chodzi?
komentarz 13 czerwca 2018 przez Sic Dyskutant (8,510 p.)
Dlaczego przyjmuje wartości domyślne a nie te, które zostały zaincjalizowane?

2 odpowiedzi

+1 głos
odpowiedź 13 czerwca 2018 przez Bondrusiek Maniak (61,370 p.)
wybrane 13 czerwca 2018 przez Sic
 
Najlepsza

Witam,

zapominasz przypisać wartości do tablicy np. możesz to zrobić w konstruktorze :

...
SALES::Sales::Sales(double * sale, const int QUARTERS)
{
        for(int i = 0; i < QUARTERS; i++)
        {
            this->sale[i] = *(sale + i);
        }
...

 

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

To w zupełności wystarczyło smiley, ale nie wiem dlaczego mam problem z najmniejszą wartością (pokazuje mi wartość domyślną), a dobrze jest przypisana. Co mogło pójśc nie tak ?

komentarz 13 czerwca 2018 przez Bondrusiek Maniak (61,370 p.)

U mnie pokazuje poprawną wartość czyli 3.55(z tej tablicy

double table[4] = {22.11, 3.55, 33.55, 3.56};

)

komentarz 13 czerwca 2018 przez Sic Dyskutant (8,510 p.)
Największa wartość: 33.55
Najmniejsza wartość: 1.4822e-323
Średnia wartość: 15.6925

Mozliwe, że to błąd kompilatora(g++), próbowałem kompilować normalnie i "-std=c++11".
1
komentarz 13 czerwca 2018 przez Bondrusiek Maniak (61,370 p.)

Powyższy kod w jednym pliku

#include <iostream>

using namespace std;

namespace SALES
{
        class Sales
        {
                private:
                        static const int QUARTERS = 4;
                        double sale[QUARTERS];
                        double average, max, min;
                public:
                        Sales(double * sales, const int QUARTERS);
                        Sales();
                        void showSales();
        };
}

SALES::Sales::Sales(double * sale, const int QUARTERS)
{
        for(int i = 0; i < QUARTERS; i++)
        {
            this->sale[i] = *(sale + i);
            cout << this->sale[i] << endl;
        }
        this->min = this->sale[0];
        this->max = this->sale[0];
        this->average = 0;
        for(int i=0; i<this->QUARTERS; i++)
        {
                if(this->sale[i] > this->max)
                        this->max = this->sale[i];
                if(this->sale[i] < this->min)
                        this->min = this->sale[i];
                this->average += this->sale[i];
        }
        std::cout << "Największa wartość: " << this->max << "\nNajmniejsza wartość: " << this->min << "\nŚrednia wartość: " << this->average/this->QUARTERS << std::endl;
}

void SALES::Sales::showSales()
{
        std::cout << "Największa wartość: " << max << "\nNajmniejsza wartość: " << min << "\nŚrednia wartość: " << average/QUARTERS << std::endl;
}

int main(){

    double table[4] = {22.11, 3.55, 33.55, 3.56};
            SALES::Sales object(table, 4);
            std::cout << "\n\n";
            object.showSales();
    return 0;
}

 

2
komentarz 13 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)

A co to "u grzyba" jest? 

SALES::Sales::Sales(double * sale, const int QUARTERS)

Po pierwsze dlaczego int? Oczekujesz indeksów ujemnych?

Po drugie dlaczego const? Wartość jest przekazywana przez kopię!

 

this->average += this->sale[i];

Dlaczego zmienna "średnia -> ang. average" trzyma sumę? Jak chcesz mieć średnią w klasie to trzymaj w niej średnią.

Po co to this? Przecież jasno jest zdefiniowana kolejność przeszukiwania przestrzeni nazewniczych. this w takim kontekście używasz tylko wtedy gdy jest niejednoznaczność. Przesadzasz z this'ami.

Przesadzasz także z std::endl. To wyprowadza '\n' (znak nowej linii) i opróżnia bufor. To drugie jest jest Ci do niczego tu potrzebne.

static const int QUARTERS = 4;

Znów... indeksy mogą być ujemne? Typ który tu powinien być to std::size_t i lepiej jest definiować stałe przez constexpr (od 2011 roku to standard).

Uwaga ogólna. Kod sprawdzający wartość min i max, można zapisać w jednej linii z użyciem odpowiedniego algorytmu z <algorithm>.

komentarz 13 czerwca 2018 przez sp00ky Obywatel (1,760 p.)
Podejrzewam, że autor robi zadanie 4 z rozdziału 10 książki Primer Plus VI. W zadaniu tym ma powtórzyć konkretne zadanie programistyczne, które nie używa funkcji min_element, max_element z <algorithm>.
komentarz 14 czerwca 2018 przez Sic Dyskutant (8,510 p.)

Pozmieniałem odrobinę deklarację posiadam błąd w wykorzystaniu std::minmax_element(); ( pytanie tylko co jest nie tak?)

#include "dane.h"
#include <iostream>
#include <algorithm> 
SALES::Sales::Sales(double * sale, const int QUARTERS)
{
        double total = 0;
        auto result = std::minmax_element(sale.begin(), sale.end());
       for(int i=0; i<QUARTERS; i++)
                total += sale[i];
      
        average = total/4;
        std::cout << "Największa wartość: " << *result.first << "\nNajmniejsza wartość: " << *result.second << "\nŚrednia wartość: " << average << std::endl;
}

 

1
komentarz 14 czerwca 2018 przez Bondrusiek Maniak (61,370 p.)

@Sic

double jest typem wbudowanym i nie posiada metod begin() czy end(). Ten typ rozwiązanie pasuje do kontenerów np. std::vector<> gdyż możesz wykorzystać iteratory aby wykorzystać begin(), end().

http://en.cppreference.com/w/cpp/algorithm/minmax_element

#include <algorithm>
#include <iostream>
#include <vector>
 
int main()
{
    std::vector<int> v = { 3, 9, 1, 4, 2, 5, 9 };
 
    auto result = std::minmax_element(v.begin(), v.end());
    std::cout << "min element at: " << (result.first - v.begin()) << '\n';
    std::cout << "max element at: " << (result.second - v.begin()) << '\n';
}

 

komentarz 14 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)

@Sic,

Wskaźnik jest naturalnym iteratorem. Podobnie sumę elementów policzysz z użyciem std::accumulate.

#include <iostream>
#include <algorithm>
#include <numeric>
#include <cstddef>

void info(double * tab, std::size_t size) {
    auto pr = std::minmax_element(tab, tab + size);
    double min = *pr.first;
    double max = *pr.second;
    double average  = std::accumulate(tab, tab + size, 0.0) / size;
    std::cout << "min = " << min << " max = " << max
        << " average = " << average << '\n';
}

int main() {
    double table[] = {22.11, 3.55, 33.55, 3.56};
    info(table, 4);
}

Można dyskutować czy przejście 2 x przez kontener jest opłacalne. IMHO przy małych kontenerach warto bo upraszczasz kod i nie popełnisz w nim pomyłek. Przy większych oczywiście można optymalizować np poprzez użycie "nietypowo" std::accumulate.

#include <iostream>
#include <algorithm>
#include <numeric>
#include <cstddef>

void info(double * tab, std::size_t size) {
    double min = *tab;
    double max = *tab;
    double sum = 0;
    double average = (std::accumulate(tab, tab + size, *tab,
            [&](double a, double b) {
                min = b < min ? b: min;
                max = b > max ? b: max;
                return a + b;
            }
    ) - *tab) / size;
    std::cout << "min = " << min << " max = " << max
        << " average = " << average << '\n';
}

int main() {
    double table[] = {22.11, 3.55, 33.55, 3.56};
    info(table, 4);
}

 

komentarz 14 czerwca 2018 przez sp00ky Obywatel (1,760 p.)

@Sic,

Myślę, że powinieneś się skupić na treści zadania, a biblioteki i ich funkcje zaczniesz wykorzystywać wraz z doświadczeniem.

Normalnie, aż poszukałem treści zadania (zadanie 4, rozdział 10):

Powtórz ćwiczenie programistyczne numer 4 z rozdziału 9, konwertując strukturę Sales i związane z nią funkcję na postać klasy i jej metod. Funkcję setSales(Sales &, double [], int) zastąp stosownym konstruktorem. Zaimplementuj z użyciem konstruktora interaktywną metodę setSales(Sales &). Całą klasę umieść w przestrzeni nazw SALES.

Rozdział 9. Ćwiczenia programistyczne, zadanie 4

Napisz 3-plikowy program bazujący na poniższej przestrzeni nazw:

namespace SALES
{
    const int QUARTERS = 4;

    struct Sales
    {
        double sales[QUARTERS];
        double average;
        double max;
        double min;
    };

    // kopiuje mniej niż 4 lub n elementów z tablicy ar
    // do składowej sales struktury s i oblicza oraz zachowuje w odpowiednich
    // składowych struktury Sales wartości: średnią, minimalną i maksymalną
    // zeruje pozostałe elementy tablicy sales (jeśli są)
    void setSales(Sales & s, const double ar[], int n);

    // pobiera interaktywnie informacje dla 4 mieszkań
    // zachowuje je w składowej sales struktury s i oblicza oraz zachowuje
    // w odpowiednich składowych s wartość średnią, minimalną i maksymalną
    void setSales(Sales & s);

    // wyświetla komplet informacji ze struktury s
    void showSales(const Sales & s);
}
Pierwszy z plików powinien być plikiem nagłówkowym deklarującym powyższą przestrzeń nazw. Drugi plik powinien zawierać kod źródłowy uzupełniający przestrzeń nazw z pliku nagłówkowego o definicję zadeklarowanych w niej funkcji. Wreszcie trzeci plik powinien deklarować dwa obiekty typu Sales. Jeden z obiektów powinien wypełniać interaktywną wersję funkcji setSales(), a drugi z obiektów jej wersję nieinteraktywną. Na koniec program powinien wyświetlić zawartość obu struktur wywołaniem showSales().

Czyli:

// sales.h

#ifndef SALES_H
#define SALES_H

namespace SALES {
const int QUARTERS = 4;

class Sales {
private:
    double sales[QUARTERS];    // tablica na ceny sprzedanych mieszkań
    double average;
    double max;
    double min;
public:
    Sales() {}
    ~Sales() {}
    Sales(const double ar[], int n);
    void setSales();
    void showSales() const;
};
}

#endif // SALES_H
// sales.cpp

#include <iostream>
#include "sales.h"  // deklaracje klasy i przestrzeni nazw

/* kopiuje co najmniej 4 elementy z n-elementowej tablicy ar,
 * zeruje pozostałe elementy tablicy jeśli są,
 * oblicza wartość średnią oraz szuka wartości minimalnej i maksymalnej,
 * dane zachowuje w odpowiednich składowych klasy */
SALES::Sales::Sales(const double ar[], int n) {

    // kopiuję 4 elementy z tablicy, pozostałe są zerowane
    for (int i = 0; i < QUARTERS; i++) {
        if (i <= n)
            sales[i] = ar[i];
        else
            sales[i] = 0.0;
    }

    // szuka wartości minimalnej i maksymalnej oraz oblicza średnią
    double minimum = sales[0];
    double maximum = sales[0];
    double sum = 0.0;

    for (int i = 0; i < QUARTERS; i++) {
        double temp = sales[i];
        if (temp > maximum)
            maximum = temp;
        if (temp < minimum)
            minimum = temp;
        sum += temp;
    }
    min = minimum;
    max = maximum;
    average = sum / static_cast<double>(QUARTERS);
}

/* pobiera interaktywnie informacje dla 4 mieszkań,
 * oblicza wartość średnią oraz szuka wartości minimalnej i maksymalnej,
 * dane zachowuje w odpowiednich składowych klasy */
void SALES::Sales::setSales() {
    std::cout << "Podaj ceny sprzedanych mieszkan: " << std::endl;

    // pobiera interaktywnie informacje dla 4 mieszkań
    for (int i = 0; i < QUARTERS; i++) {
        std::cout << "Cena #" << i + 1 << ": ";

        // sprawdzam czy wprowadzono liczbę
        while (!(std::cin >> sales[i])) {
            std::cin.clear();
            while (std::cin.get() != '\n')
                continue;
            std::cout << "Niepoprawna wartosc, podaj liczbe: ";
        }
    }

    // szuka wartości minimalnej i maksymalnej oraz oblicza średnią
    double minimum = sales[0];
    double maximum = sales[0];
    double sum = 0.0;

    for (int i = 0; i < QUARTERS; i++) {
        double temp = sales[i];
        if (temp > maximum)
            maximum = temp;
        if (temp < minimum)
            minimum = temp;
        sum += temp;
    }
    min = minimum;
    max = maximum;
    average = sum / static_cast<double>(QUARTERS);
}

// wyświetla komplet informacji
void SALES::Sales::showSales() const {
    for (int i = 0; i < QUARTERS; i++) {
        std::cout << sales[i] << " ";
    }
    std::cout << "\nMinimalna: " << min << std::endl;
    std::cout << "Maksymalna: " << max << std::endl;
    std::cout << "Srednia: " << average << std::endl;
}
// main.cpp

#include <iostream>
#include "sales.h"   // deklaracje klasy i przestrzeni nazw

int main() {

    const double sales[]{ 321.26, 275.69, 114.98, 401.73 }; // tablica, np. ceny sprzedanych mieszkań

    // wersja nieinteraktywna
    SALES::Sales notInteractive(sales, 4);
    std::cout << "Ceny sprzedazy zapisane w tablicy: ";
    notInteractive.showSales();

    // wersja interaktywna
    SALES::Sales interactive;
    interactive.setSales();
    std::cout << "Ceny podane przez uzytkownika: ";
    interactive.showSales();

    return 0;
}

I jak już dojdziesz do rozwiązania, to możesz poćwiczyć zamianę na vector i użycie funkcji min_element, max_element z <algorithm>.

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

@Bondrusiek,

Nie zamierzam używać wektorów ani array

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

@sp00ky,

Przyznaję nie zrobiłem tego dokładnie z treścią. Jednak mam pytanie do jednej części tego programu, bo tego nie wiedziałem:

for (int i = 0; i < QUARTERS; i++) {
        std::cout << "Cena #" << i + 1 << ": ";

Przyznaję nie wykorzystywałem jeszcze takie sposobu i całkowicie go nie pojmuję.

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

@mokrowski,

Dziękuję za pokazanie mi tej metody usprawniłem wszystko.

Mam tylko pytanie co do std::size_t czy ten typ danych można wykorzystywać w każdej sytuacji czy może istnieją jakieś wyjątki ?

1
komentarz 14 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)
std::size_t to typ danych do określania wszelkiego rodzaju rozmiaru kontenerów (ilości elementów w nich zapisanych) i tego typu nieujemnych wielkości. Standard zawsze mapuje go na typ który pomieści największy możliwy kontener (tj ilość elementów) na danej platformie systemowej. W tych kontekstach std::size_t się sprawdza i do tego służy.
1
komentarz 15 czerwca 2018 przez sp00ky Obywatel (1,760 p.)
edycja 15 czerwca 2018 przez sp00ky

@Sic,

 

@sp00ky,

Przyznaję nie zrobiłem tego dokładnie z treścią. Jednak mam pytanie do jednej części tego programu, bo tego nie wiedziałem:

?

1

2

for (int i = 0; i < QUARTERS; i++) {

        std::cout << "Cena #" << i + 1 << ": ";

Przyznaję nie wykorzystywałem jeszcze takie sposobu i całkowicie go nie pojmuję.

To jest zwykła pętla, która pobiera od Ciebie dane do tablicy, przed pobraniem wartości wyświetli w konsoli:

Cena #1: Podajesz cenę
Cena #2: Podajesz cenę
Cena #3: i tak dalej
komentarz 15 czerwca 2018 przez Sic Dyskutant (8,510 p.)
to dlaczego jest "i+1"?
komentarz 15 czerwca 2018 przez Sic Dyskutant (8,510 p.)
Dziękuję muszę częściej z niego korzystać.
komentarz 15 czerwca 2018 przez sp00ky Obywatel (1,760 p.)

@Sic,

Ponieważ pętla startuje od pierwszego elementu tablicy int i = 0 (elementy tablicy liczymy od 0 elementu [0, 1, 2 , 3, ... n] ), a w konsoli ma się wyświetlić Cena #1 (a nie Cena #0), więc do i dodajemy 1. Proponuję poćwiczyć strumienie, aby nabrać trochę wprawy.

+1 głos
odpowiedź 13 czerwca 2018 przez mokrowski Mędrzec (155,460 p.)

dane.h:

#ifndef DANE_H_
#define DANE_H_

#include <cstddef>

namespace SALES
{

class Sales
{
public:
    constexpr static std::size_t QUARTERS = 4;
    Sales(double * sales, std::size_t QUARTERS);
    Sales();
    void showSales();
private:
    double sale[QUARTERS];
    double average;
    double max;
    double min;
};

}
#endif

dane.cpp

#include "dane.h"
#include <iostream>

SALES::Sales::Sales(double * sale, std::size_t QUARTERS)
{
    min = sale[0];
    max = sale[0];
    double sum = 0;
    for(std::size_t i = 0; i < QUARTERS; ++i)
    {
        if(sale[i] > max)
        {
            max = sale[i];
        }
        if(sale[i] < min)
        {
            min = sale[i];
        }
        sum += sale[i];
    }
    average = sum / QUARTERS;
    std::cout << "Największa wartość: " << max
        << "\nNajmniejsza wartość: " << min
        << "\nŚrednia wartość: " << average
        << '\n';
}

void SALES::Sales::showSales()
{
    std::cout << "Największa wartość: " << max
        << "\nNajmniejsza wartość: " << min
        << "\nŚrednia wartość: " << average
        << '\n';
}

main.cpp

#include "dane.h"
#include <iostream>

int main()
{
    double table[] = {22.11, 3.55, 33.55, 3.56};
    SALES::Sales object(table, sizeof(table)/sizeof(*table));
    std::cout << "\n\n";
    object.showSales();
}

 

Podobne pytania

0 głosów
2 odpowiedzi 2,559 wizyt
pytanie zadane 7 listopada 2018 w C i C++ przez ola123 Nowicjusz (180 p.)
0 głosów
0 odpowiedzi 1,098 wizyt
pytanie zadane 20 marca 2020 w Java przez mn130496 Gaduła (3,530 p.)
+2 głosów
1 odpowiedź 338 wizyt

92,615 zapytań

141,465 odpowiedzi

319,782 komentarzy

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

...