Prosty kalkulator, opinia kodu

Prosty kalkulator, opinia kodu

Wątek przeniesiony 2022-03-05 15:04 z C/C++ przez Riddle.

SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

Witam!

Jestem początkujący i chciałbym by ktoś zerknął na owy kod i podpowiedział czy jest on w miarę dobrze napisany, optymalny a może da się go zrobić krócej? Doradził co do ewentualnych zmian.

Kopiuj
#include <stdio.h>

void wpisz(int *a, int *b){
    printf("Podaj a = ");
    scanf("%d", a);
    printf("Podaj b = ");
    scanf("%d", b);
}

void text(int *n){
    printf("Jakie działanie chcesz wykonać? \n1 - dodawanie\n2 - odejmowanie\n3 - mnozenie\n4 - dzielenie\n5 - reszta z dzielenia\n6 - koniunkcja bitowa(AND)\n7 - alternatywa bitowa(OR)\n8 - alternatywa rozłączna(XOR)\n9 - negacja bitowa\nPodaj numer operacji: ");
    scanf("%d", n);
}

void dod(int a, int b){
    int suma;
    suma = a + b;
    printf("%d + %d = %d \n", a,b, suma);
}

void ode(int a, int b){
    int roznica;
    roznica = a - b;
    printf("%d - %d = %d \n", a, b, roznica);
}

void mnoz(int a, int b){
    int iloczyn;
    iloczyn = a * b;
    printf("%d * %d = %d \n", a, b, iloczyn);
}

void dziel(int a, int b){
    float iloraz;
    iloraz = a / b;
    printf("%d // %d = %.2f\n", a, b, iloraz);
}

void mod(int a, int b){
    int modulo;
    modulo = a % b;
    printf("%d %% %d = %d\n", a, b, modulo);
}

void kon(int a, int b){
    int koniunkcja;
    koniunkcja = a & b;
    printf("%d & %d = %d\n", a, b, koniunkcja);
}
void albit(int a, int b){
    int alternatywab;
    alternatywab = a | b;
    printf("%d | %d = %d\n", a, b, alternatywab);
}

void altroz(int a, int b){
    int rozlaczna;
    rozlaczna = a ^ b;
    printf("%d ^ %d = %d", a, b, rozlaczna);
}

void neg(int a, int b){
    int neg1, neg2;
    neg1 = ~a;
    neg2 = ~b;
    printf("~%d = %d\n~%d = %d\n", a, neg1, b, neg2);
}


int main(){
    
    int a;
    int b;
    int n;
    wpisz(&a,&b);
    text(&n);
    
    switch (n){
        case 1:
            dod(a,b);
            break;
        case 2:
            ode(a,b);
            break;
        case 3:
            mnoz(a,b);
            break;
        case 4:
            dziel(a,b);
            break;
        case 5:
            mod(a,b);
            break;
        case 6:
            kon(a,b);
            break;
        case 7:
            albit(a,b);
            break;
        case 8:
            altroz(a,b);
            break;
        case 9:
            neg(a,b);
            break;
        default:
            printf("Zły wybór!");
        }
    
    return 0;
}
edytowany 1x, ostatnio: Riddle
Spine
  • Rejestracja:prawie 22 lata
  • Ostatnio:około 3 godziny
  • Postów:6635
4
  1. Nazewnictwo. ode(), dod()... Po ludzku można to nazwać.
  2. Funkcję text() można nazwać menu() i switch przenieść do tej funkcji.
  3. Wszystkie funkcje możesz sobie napisać krócej. Nie trzeba tworzyć dodatkowych zmiennych.
    Np.
    Kopiuj
    void ode(int a, int b){
        printf("%d - %d = %d \n", a, b, a - b);
    }
    
  4. menu() możesz wykonywać w pętli while. Żeby można było więcej liczyć w czasie pojedynczego uruchomienia programu. Wyjście z programu byłoby przypisane do kolejnej pozycji menu.
  5. Cały kalkulator możesz usprawnić tak, żeby potrafił obliczać wartości wyrażeń matematycznych. Poczytaj o ONP.

🕹️⌨️🖥️🖱️🎮
edytowany 1x, ostatnio: Riddle
SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

@Spine Fajnie zastosowałem się do pierwszych trzech punktów ale nie wiem jak ugryźć czwarty...

Kopiuj
while(??){
  menu(a,b); 
}

Od czego uzależnić warunek?

edytowany 1x, ostatnio: Riddle
Spine
  • Rejestracja:prawie 22 lata
  • Ostatnio:około 3 godziny
  • Postów:6635
1

@Sponczuu:

Kopiuj
do
{
    wpisz(&a,&b);
}
while (menu(a, b));

Menu może zwracać 0, jeśli wybrano opcję wyjścia z programu. W przeciwnym razie zwracać 1.

Albo w ogóle do menu dodać wpisz.
Zależy czy chcesz, żeby liczby podawać przed każdym działaniem, czy robić różne działania dla jednokrotnie podanych liczb.
Ja bym zrobił menu bez argumentów.


🕹️⌨️🖥️🖱️🎮
edytowany 4x, ostatnio: Spine
SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

@Spine:
Kurcze nie ograniam jak zwrócić wartość mojej funkcji menu(a,b) skoro ona jest funkcją void

Spine
  • Rejestracja:prawie 22 lata
  • Ostatnio:około 3 godziny
  • Postów:6635
1

@Sponczuu: Zmień jej typ na int.


🕹️⌨️🖥️🖱️🎮
SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

@Spine: No niby działa jak powinno ale czy o ten kod jest git?

Kopiuj
     case 9:
         negacja(a,b);
         return 1;
     case 10: // 10 - koniec programu(w menu)
         return 0;
     default:
         printf("Zły wybór!\n");
         return 1;
     }
 return 0;
edytowany 1x, ostatnio: Riddle
EL
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 12 godzin
  • Postów:138
1

Przede wszystkim zapewnij ze program dziala poprawnie. W szczegolnosci piszac znaczek / lub % zawsze (a co najmniej dla int) musisz sie zastanowic czy mozesz to zrobic.

SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

@eleventeen: No teraz wiem, że nie ;/ Dlaczego mi teraz zaczęło zapętlać program?

LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:około 7 godzin
  • Postów:8409
1
Kopiuj
 printf("Jakie działanie chcesz wykonać? \n1 - dodawanie\n2 - odejmowanie\n3 (...)

ta linia to jakiś potworek. Weź to jakoś podziel.

Kopiuj
void ode(int a, int b){

tworzenie skrótów od polskich nazw to słabiutki pomysł.
Pomyśl o czytelności, że twój kod czyta ktoś, kto widzi to pierwszy raz na oczy. Jak stosujesz skróty, to należy to robić w oczywisty sposób.

Zamiast ode - (jak już idziesz w polski) lepsze byłoby odejmij
ale lepiej napisać po angielsku subtract. Ew. nawet skrótowo sub, ponieważ mul, div czy sub są to utarte skróty i każdy je zrozumie.

natomiast ode to mi się kojarzy prędzej z tym: https://en.wikipedia.org/wiki/Ordinary_differential_equation

Kopiuj
void mnoz(int a, int b){
    int iloczyn;
    iloczyn = a * b;
    printf("%d * %d = %d \n", a, b, iloczyn);
}

Mieszasz logikę (operator mnożący dwie liczby) z ze sposobem prezentacji danych (wyświetlanie tekstu na standardowym wyjściu za pomocą printf). A co jeśli będziesz chciał policzyć coś cicho bez wyświetlania tego użytkownikowi? Żeby to osiągnąć, ta funkcja musiałaby wyglądać tak:

Kopiuj
int mnoz(int a, int b){
    return a * b;
}

A wywołania printf powinny znaleźć się w innym miejscu programu.

W ten sposób byś mógł oddzielić część programu, gdzie faktycznie coś jest liczone, od kodu, który prezentuje te dane np. wyświetlając je na wejściu.


edytowany 1x, ostatnio: LukeJL
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
2

Wyniesienie drukowania do subfunkcji (choć nie dziwi u początkujących) neguje (prawie) wszystkie zalety podziału na funkcje. Właściwie stają się zabetonowane jako tylko drukujące (i nie zwracające wyniku)

Popieram drugą część wypowiedzi @LukeJL - choć jest błędny typ funkcji voidint

Kopiuj
int  mnoz(int a, int b){
    return a * b;
}

Funkcje które przetwarzają dane (tutaj: obliczają) i zwracają wyniki dadzą się wykorzystać w innym zagadnieniu.

Mówiąc o taki kodzie mówimy o częściach kodu "klienckich", w sensie "klient poprosił o obliczenie" a wydrukuje sobie sam (albo nie wydrukuje, albo wydrukuje inaczej, na inny plik, na HTML itd )


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
LukeJL
dzięki, poprawiłem.
SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

@ZrobieDobrze: "Wyniesienie drukowania do subfunkcji (choć nie dziwi u początkujących) neguje (prawie) wszystkie zalety podziału na funkcje. Właściwie stają się zabetonowane jako tylko drukujące (i nie zwracające wyniku)" przez to mam rozumieć, że tworze osobnej funkcji gdzie jest praktycznie tylko drukowanie jakiegoś teksu jest bezsensowne?

H1
  • Rejestracja:prawie 5 lat
  • Ostatnio:ponad 2 lata
  • Postów:8
3

Jeśli stworzysz osobną funkcję, która jedynie drukuje jakiś tekst, np. w ładniejszy sposób i jest reużywalna to taka funkcja ma jak najbardziej sens (np. drukuj(), printNumber()). Dobra rada ode mnie: Jeśli Twoja funkcja mnoz mnożyła dwie liczby oraz je drukowała to robiła więcej niż wynikało by to z jej nazwy. Powinna robić jedynie mnożenie i zwracać wynik z operacji. W ten sposób wykonuje czynność zawartą w nazwie, robi to dobrze i robi tylko tyle. Notabene zmień tą nazwę, bo jest paskudna (na chociaż pomnoz, ale lepiej multiply ) .

SP
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:10
0

Teraz coś lepiej to wygląda?

Funkcja dzielenie() może być tak zapisana (return (float)a / b)?
Jak mogę zmienić funkcję negacja?
Czy w switch'u te return'y są git?
I jeszcze czy która opcja jest lepsza switch czy if'y?

Kopiuj
#include <stdio.h>
#include <stdlib.h>

void wpisz(int *a, int *b){
    printf("Podaj a = ");
    scanf("%d", a);
    printf("Podaj b = ");
    scanf("%d", b);
}

int dodawanie(int a, int b){
    return a + b;
}

int odejmowanie(int a, int b){
    return a - b;
}

int mnozenie(int a, int b){
    return a * b;
}

float dzielenie(int a, int b){
    return (float)a / b;
}

int modulo(int a, int b){
    return a % b;
}

int koniunkcja(int a, int b){
    return a & b;
}
int alternatywa(int a, int b){
    return a | b;
}

int alternatywaroz(int a, int b){
    return a ^ b;
}

void negacja(int a, int b){
    int neg1, neg2;
    neg1 = ~a;
    neg2 = ~b;
    printf("~%d = %d\n~%d = %d\n", a, neg1, b, neg2);
}

int menu(int a, int b){
    int n;
    scanf("%d", &n);
    switch (n){
        case 1:
            printf("%d + %d = %d\n", a, b, dodawanie(a,b));
            return 1;
        case 2:
            printf("%d - %d = %d\n", a, b, odejmowanie(a,b));
            return 1;
        case 3:
            printf("%d * %d = %d\n", a, b, mnozenie(a,b));
            return 1;
        case 4:
            printf("%d / %d = %.2f\n", a, b,dzielenie(a,b));
            return 1;
        case 5:
            printf("%d %% %d = %d\n", a, b, modulo(a,b));
            return 1;
        case 6:
            printf("%d & %d = %d\n", a, b, koniunkcja(a,b));
            return 1;
        case 7:
            printf("%d | %d = %d\n", a, b, alternatywa(a,b));
            return 1;
        case 8:
            printf("%d ^ %d = %d\n", a, b,alternatywaroz(a,b));
            break;
        case 9:
            negacja(a,b);
            return 1;
        case 10:
            return 0;
        default:
            printf("Zły wybór!\n");
            return 1;
        }
    return 0;
}

int main(){
    int a;
    int b;
    do
    {
        wpisz(&a,&b);
        printf("Jakie działanie chcesz wykonać? \n1 - dodawanie\n2 - odejmowanie\n3 - mnozenie\n4 - dzielenie\n5 - reszta z dzielenia\n6 - koniunkcja bitowa(AND)\n7 - alternatywa bitowa(OR)\n8 - alternatywa rozłączna(XOR)\n9 - negacja bitowa\n10 - Koniec programu\nPodaj numer operacji: ");
    }
    while (menu(a, b));
    return 0;
}
edytowany 1x, ostatnio: Sponczuu
Spine
Dostałeś już od bota upomnienie na początku tematu. Używaj znaczników, jak wklejasz kod!
p_agon
@Spine: Nie krzycz na niego.
SP
Przepraszam, ale nie dokonać jeszcze ogarniam tego bloga. Jak zrobić by ten kod był dobrze sformatowany?
Spine
Kliknij tekst Markdown jest obsługiwany w prawym dolnym rogu pola tekstowego, jak piszesz posta.
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:około 7 godzin
  • Postów:8409
0
Kopiuj
case 1:
     printf("%d + %d = %d\n", a, b, dodawanie(a,b));
     return 1;
 case 2:
     printf("%d - %d = %d\n", a, b, odejmowanie(a,b));
     return 1;
 case 3:
     printf("%d * %d = %d\n", a, b, mnozenie(a,b));
     return 1;

Zobacz, że tutaj masz duplikację kodu. Wszystkie te printfy odbywają się wg tego samego schematu a operator b = c . Da się to zapisać jako (poza dzieleniem, bo tam masz wynik we floatach*):

Kopiuj
printf("%d %s %d = %d\n", a, operator, b, c);

więc możesz ten printf wyciągnąć poza switcha, jedynie przypisując operator i wynik odpowiednio.

Kopiuj
void negacja(int a, int b){
    int neg1, neg2;
    neg1 = ~a;
    neg2 = ~b;
    printf("~%d = %d\n~%d = %d\n", a, neg1, b, neg2);
}

tutaj na siłę robisz z negacji operator dwuargumentowy, czyli twoja funkcja negacja liczy negację dwóch liczb naraz. trochę bez sensu

*swoją drogą czy nie lepiej przejść również na floaty w dodawaniu/mnożeniu/odejmowaniu? Tylko wtedy i tak by ci zostały inty w operacjach bitowych koniunkcja, alternatywa itp.


edytowany 2x, ostatnio: LukeJL
Manna5
  • Rejestracja:prawie 6 lat
  • Ostatnio:około 19 godzin
  • Lokalizacja:Kraków
  • Postów:639
2

Ładnie wykorzystujesz wskaźniki unikając zmiennych globalnych, tylko nazwy słabe jak inni już pisali no i nie masz zabezpieczenia przed dzielenie przez zero. A przy wyświetlaniu menu mógłbyś podzielić ten tekst, o ile oczywiście twój kompilator taką składnię obsługuje:

Kopiuj
printf ("Jakie działanie chcesz wykonać? \n"
        "1 - dodawanie\n2 - odejmowanie\n3 - mnozenie\n4 - dzielenie\n"
        "5 - reszta z dzielenia\n6 - koniunkcja bitowa(AND)\n7 - alternatywa bitowa(OR)\n"
        "8 - alternatywa rozłączna(XOR)\n9 - negacja bitowa\n10 - Koniec programu\n"
        "Podaj numer operacji: ");

@LukeJL:

Kopiuj
printf("%d %s %d = %d\n", a, operator, b, c);

Tutaj operator mógłby być znakiem, bo wśród zestawu operacji nie ma dwuznakowych operatorów - więc %c a nie %s.


edytowany 1x, ostatnio: Manna5
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)