[C++] czy dobrze napisałam program?


(Pieczarka1900) #1

Od kilku dni uczę się języka C++ z pewnej strony internetowej. Jestem kompletnym laikiem, więc proszę o wyrozumiałość. W pierwszym rozdziale są zadania typu: "Napisz program, który wczytuje 2 liczby i podaje iloraz, iloczyn, sumę i różnicę."

Napisałam je, tylko nie mam pojęcia, czy poprawnie. Bardzo bym prosiła, by ktoś "spojrzał" na to i sam ocenił. Głównie chodzi o to, czy poprawnie połączyłam instrukcje. Szukałam info o łączeniu, ale ciężko mi cokolwiek znaleźć... nie wiem, może źle szukam.

Nie wiem czy to ważne, ale pisałam w CodeBlocks 8.02.

Z góry wielkie dzięki.

http://wklejto.pl/9757"Napisz program, który wczytuje 2 liczby i podaje iloraz, iloczyn, sumę i różnicę."

http://wklejto.pl/9758 "Napisz program który wczytuje 2 liczby całkowite i oblicza pole prostokąta oraz jego obwód."


(system) #2

Czy piszesz na sucho, bez kompilatora? Ściągnij sobie DevCpp darmowy przyjazny itp.

Kilka "zarzutów" do programu od poważnych (uniemożliwiających kompilacje) do stylistycznych:

  1. deklaracja: int a;b;c; nie jest poprawna, musi być: int a,b,c; albo int a; int b; int c;

  2. piszesz end1 zamiast endl (to skrót od "end line");

  3. w tym kontekście lepiej użyć double zamiast int;

  4. brak kontroli poprawności wprowadzenia;

  5. niepotrzebnie powtarzasz wprowadzenie;

  6. jeżeli użytkownik chce powtórzyć obliczenia to musi odpalić program jeszcze raz;

  7. zbędne nawiasy klamrowe.

np:

#include 


using namespace std;


int main()

  {

   while(true)

     {

      double liczba1,liczba2;

      cout<<"Wprowadz 2 liczby: ";

      cin>>liczba1>>liczba2;

      if(cin)

        {

         cout

            <<"Iloczyn wynosi :"<<(liczba1*liczba2)<
            <<"Iloraz wynosi :"<<(liczba1/liczba2)<
            <<"Suma wynosi :"<<(liczba1+liczba2)<
            <<"Roznica wynosi :"<<(liczba1-liczba2)<
            <
         ;

        }

      else

        {

         cin.clear();

         cin.ignore(2E9,'\n');

         cout<<"Blad wprowadzania danych"<
        }

     }

   return 0;

  }

(Pieczarka1900) #3

Pisałam w kompilatorze CodeBlocks 8.02.

  1. Gość pisał taką czcionką, że myślałam że l to 1, bo wyglądały tak samo :open_mouth:

Jeśli chodzi o kod, to miał to być jak najprostszy program. Nie rozumiem nawet o co chodzi z fragmentem

cin.clear();

(Proktor86adv) #4

Kod zamieszczony przez 13tySmok jest niezgodny ze standardem C++, w związku z czym na niektórych kompilatorach się skompiluje a na innych nie. Być może z tego powodu w Code::Blocks nie działa. Oto zmodyfikowana wersja która powinna śmigać (wywaliłem sprawdzanie poprawności wprowadzonych danych dla przejrzystości przykładu):

#include 


using namespace std;


int main() {

    bool repeat = true;


    while (repeat) {

        double liczba1, liczba2;


        cout << "Wprowadz 2 liczby: ";

        cin >> liczba1 >> liczba2;


        cout << "Iloczyn wynosi: " << liczba1 * liczba2 << endl;

        cout << "Iloraz wynosi: " << liczba1 / liczba2 << endl;

        cout << "Suma wynosi: " << liczba1 + liczba2 << endl;

        cout << "Roznica wynosi: " << liczba1 - liczba2 << endl;


        cout << "Jeszcze raz? (t/n) ";

        char odp;

        cin >> odp;

        repeat = (odp == 't');

    }


    return 0;

}

I mała rada - kodu źródłowego nie zapisuje się do plików .exe, tylko .cpp (najczęściej). Plik .exe (pod Windowsem) zostanie wygenerowany przez kompilator.


(system) #5

(Proktor86adv) #6

Nie powiesz mi chyba, że nie słyszałeś o "nowym" formacie plików nagłówkowych biblioteki standardowej (bez rozszerzenia) oraz przestrzeni nazw std?

Hehe jakby to był program tylko na Vistę, to chyba faktycznie trzeba by tak zrobić :wink:. A poważnie - jestem przeciwnikiem stosowania pętli nieskończonych, nawet w prostych programach. Pętla powinna być tak skonstruowana, aby czytający warunek od razu widział, jak długo ma trwać. To oczywiście kwestia przyjętego stylu i nie zamierzam nikogo do niego przekonywać - ja po prostu tak nie robię.

A do czego ma prowadzić to pytanie? Istnieje tu jakiś podział na zwolenników i przeciwników Symfonii?

[edit] Dopisane przez ciebie rozwiązanie oczywiście też jest niezłe, z tym że ja bym zrezygnował z break i przypisał to do zmiennej boolowskiej (ale jak już napisałem to kwestia przyjętego stylu).


(system) #7

No racja, skopiowałem to co było podane i poprawiłem tylko w środku, nawet nie zobaczyłem co jest powyżej main(). Z resztą z ciekawości skompilowałem to (bez modyfikacji) pod CodeBlocks i działa owszem z dwoma ostrzeżeniami.

Chcesz mi wmówić że w twoim przykładzie po przeczytaniu warunku od razu widać jak długo ta pętla będzie trwać? Określasz czy robić kolejny krok dopiero na końcu pętli, to czemu nie zastosować do { }while(), lub while(true) { if() break; } ?

To takie moje prywatne badanie socjologiczne. :smiley:


(Proktor86adv) #8

Co do pętli - w tym wypadku nie ma większej różnicy, chodziło mi o ogólną zasadę.

Odnośnie Symfonii - mój stosunek do niej jest raczej neutralny. Jeżeli ktoś nigdy w życiu nie programował w żadnym języku to rozpoczęcie od Symfonii znacznie ułatwia start, zwłaszcza przeczytanie chociaż 1 tomu. Sam nigdy nie doczytałem do końca, bo zwyczajnie zaczęła mnie nudzić. Ostatnio sięgnąłem po Pasję i wymiękłem po około 20 stronach, jak autor po raz któryś przytoczył ten sam przykład z szablonami (może potem się rozkręca ale taki rozlazły styl średnio mi odpowiada).

Dzisiaj cenię "Język C++" oraz "Thinking in C++" wyżej, pytanie tylko, czy gdybym od nich zaczynał (zwłaszcza od "Thinking in C++" bo umówimy się, że książka Stroustrupa nie jest do nauki tego języka, raczej utrwalenia/rozszerzenia posiadanej wiedzy) byłoby mi łatwiej niż w przypadku Symfonii? Ciężko powiedzieć, ale raczej wątpię.

Ale chyba pora kończyć tego offtopa. Pozdrawiam.


(system) #9

Temat brzmi: "czy dobrze napisałam program?", więc dyskusja o zasadach nawet tych nie pisanych jest jak najbardziej na miejscu. Co do pętli - jest wielka różnica, każdy sztuczny zabieg zmniejsza czytelność. Gdzie program "podejmuję decyzje" o zakończeniu pętli tam ma być to widoczne. Owszem w tym programie cała pętla jest widoczna na ekranie, ale są przypadki kiedy pętla rozciąga się na kilka tysięcy wierszy. Np wiesz że coś nie tak się dzieje po komunikacie: "bla-bla-bla", więc znajdujesz ten komunikat przez menu znajdź, no i widzisz że tuż po komunikacie zmieniona zostaje wartość zmiennej logicznej a dalej zamykająca się klamerka, czy zrozumiesz o co chodzi? Natomiast jak zobaczysz w tym miejscu if() break; to od razu rozumiesz że to warunek przerwania pętli. Wszystkie te ogólne nie pisane zasady istnieją tylko po to aby zwiększyć czytelność programu a nie po to żeby byli. :smiley:

Również pozdrawiam.


(Pieczarka1900) #10

Więc ja napiszę tak... : ja nie rozumieć o czym Wy pisać :o

Chyba lepiej najpierw poczytam... Już mam co czytać. Bo z tego co piszecie, to ja jestem zielona... Ja na prawdę dopiero zaczęłam. Nawet przeczytałam wszystko, co napisaliście, ale nidyrydy to jakbym czytała po chińsku... :frowning:

Uważam też, że nie ma sensu, pytać co to są pętle i tak dalej, bo i tak bym tego nie zrozumiała :x

Ale nie martwcie się. Poczytam i jeszcze tu wrócę! :stuck_out_tongue:


(Proktor86adv) #11

Oczywiście, że tak. Patrząc na warunek pętli widzę, że ta zmienna kontroluje jest wykonanie i dalej wszystko jest jasne. Czy ty miałbyś problemy ze zrozumieniem czegoś takiego? Patrząc na break jeszcze muszę zobaczyć, z jakiego bloku to faktycznie wyskoczy (oczywiście nie w tym przykładzie). A co jak będziesz miał zagnieżdżoną pętlę i w jej ciele zdecydujesz o opuszczeniu obu pętli - zastosujesz wtedy goto czy 2x break przy udziale jakiejś dodatkowej zmiennej log? I też będziesz mi mówił, że to jest naturalne rozwiązanie? Daj spokój.

Jak najbardziej. I jedną z nich jest właśnie unikanie sztucznych konstrukcji typu pętla nieskończona :-D.

PS. Naprawdę zdarzyło ci się kiedyś napisać pętlę na kilka tysięcy linijek?


(system) #12

Patrząc na warunek pętli - owszem, ale musisz jeszcze się domyślić ze ta zmieniona zmienna kontroluje jakąś pętle a potem tą pętle znaleźć i popatrzyć na warunek a potem dopiero tak samo jak w przypadku break zobaczyć, z jakiego bloku to faktycznie wyskoczy. Jeżeli napiszesz dwie zagnieżdżone pętli kontrolowane jedną zmienną to nie potrzebujesz dwóch a tylko jedną. Stosowanie goto w C/C++ to barbarzyństwo. :smiley: W przypadku dwóch pętli owszem będzie dwa razy break, o ile te pętli z natury nieskończone, jedynie warunki będą inne.

Ta pętla (z przykładu) jest nieskończona, ponieważ nie wiadomo kiedy się skończy, i w tym przypadku pętla ze zmienna kontrolującą jest sztuczną konstrukcją.

Jak najbardziej, pisało się bardzo skomplikowane programy.


(Proktor86adv) #13

W ogóle do mnie ta argumentacja nie przemawia - nie wiem jak ty ale ja zaczynam czytanie każdej pętli od warunku - niczego nie muszę szukać. Ale gdyby większość moich pętli była nieskończona to pewnie też wpadłbym w nawyk czytania ich od środka :wink:. Ale kończę dyskusję na ten temat bo to do niczego nas już nie doprowadzi - szanuję oczywiście twoje zdanie, pozwolę sobie jednak zostać przy swoim.

Zaintrygowało mnie to trochę. Ciekawe co to był za przypadek, że nie mogłeś tych kilku tysięcy linijek (które przecież na pewno nie realizowały tylko jednego zadania) powsadzać do odpowiednio pomyślanych funkcji pomocniczych (choćby inline jeżeli powodem była wydajność i oczywiście był to język który takie coś umożliwia). No chyba, że do tych kilku tysięcy linijek wliczasz długość wywołanych w pętli funkcji?


(system) #14

Kiedy będziesz musiał robić poprawki w swoim projekcie, w którym same źródła maja ponad 5MB wagi to chcę zobaczyć jak będziesz każdą pętle od początku czytać :lol:

Kiedy idą skomplikowane obliczenia to czasami nie ma sposobu na rozbicie to na procedury pomocnicze no chyba że przekazując po 20 i więcej zmiennych. Owszem możną próbować stworzyć klasę która jest obszarem zmiennych które byli lokalne kiedy funkcja była całością. Nawet próbowałem tak zrobić bo trudno się pracuje z tak wielką funkcja, ale te próby skończyli się niczym, tylko bardziej zagmatwałem.