Wyrażenie arytmetyczne na wskaźnikach

0

Hej! Mam za zadanie napisać program, w którym użytkownik na wejściu wprowadza wyrażenie arytmetyczne, gdzie dozwolone są (również naprzemienne) operacje dodawania, odejmowania, mnożenia i dzielenia. Zwracany jest wynik tego wyrażenia. Program liczy, biorąc pod uwagę znaki arytmetyczne od lewej do prawej (celowo), a nie poprawność matematyczną działań. Całe wyrażenie jest sprawdzane czy liczba zaczyna się i kończy cyfrą oraz czy w wyrażeniu arytmetycznym nie występują błędy typu podwójny znak ++.

Wszystko działa, program liczy i jak zwykle te testy maszynowe... Test maszynowy wyrzuca błąd:

Test został przerwany; Jaka funkcja pozwoli odnaleźć w jednym ciagu znaków dowolny znak z drugiego ciągu znaków?
Należy z niej skorzystać.

Macie pomysł o jaką funkcję chodzi i gdzie mam z niej skorzystać?

Poniżej kompletny, działający kod programu:

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

int validate_expression(const char *expr);
int calculate(const char* expr, float *result);
int czyToJestLiczba(const char *spr);

int main()
{
    char napis1[1010];
    char *wskaznik1 = napis1;
    float napis2[1010];
    float *wskaznik2 = napis2;

    printf("Wprowadz wyrazenie arytmetyczne, dostepne sa liczby oraz znaki +,-,/ oraz *:\n");
    scanf("%1009s", wskaznik1);
    int tryME = calculate(wskaznik1, wskaznik2);
    if (tryME != 1)
        return 1;
    printf("%.2f\n", *wskaznik2);
    return 0;
}

int validate_expression(const char *expr)
{
    if (expr == NULL)
        return -1;
    int przesun;
    for (przesun = 0; *(expr + przesun) != '\0'; ++przesun)
    {
        if ((*(expr + przesun) < '0' || *(expr + przesun) > '9') && *(expr + przesun) != '+' && *(expr + przesun) != '-'
            && *(expr + przesun) != '*' && *(expr + przesun) != '/' && *(expr + przesun) != '.')
            return 0;
        if (*(expr + przesun) == '.' && *(expr + przesun + 1) != '\0' && (*(expr + przesun + 1) == '-' || *(expr + przesun + 1) == '+'
            || *(expr + przesun + 1) == '/' || *(expr + przesun + 1) == '*' || *(expr + przesun + 1) == '.'))
            return 0;
        if (*(expr + przesun) == '.' && przesun>0 && (*(expr + przesun - 1) == '-' || *(expr + przesun - 1) == '+'
            || *(expr + przesun - 1) == '/' || *(expr + przesun - 1) == '*' || *(expr + przesun - 1) == '.'))
            return 0;
        if (*(expr + przesun) == '+' && *(expr + przesun + 1) != '\0' && (*(expr + przesun + 1) == '-' || *(expr + przesun + 1) == '+'
            || *(expr + przesun + 1) == '/' || *(expr + przesun + 1) == '*' || *(expr + przesun + 1) == '.'))
            return 0;
        if (*(expr + przesun) == '+' && przesun>0 && (*(expr + przesun - 1) == '-' || *(expr + przesun - 1) == '+'
            || *(expr + przesun - 1) == '/' || *(expr + przesun - 1) == '*' || *(expr + przesun - 1) == '.'))
            return 0;
        if (*(expr + przesun) == '-' && *(expr + przesun + 1) != '\0' && (*(expr + przesun + 1) == '-' || *(expr + przesun + 1) == '+'
            || *(expr + przesun + 1) == '/' || *(expr + przesun + 1) == '*' || *(expr + przesun + 1) == '.'))
            return 0;
        if (*(expr + przesun) == '-' && przesun>0 && (*(expr + przesun - 1) == '-' || *(expr + przesun - 1) == '+'
            || *(expr + przesun - 1) == '/' || *(expr + przesun - 1) == '*' || *(expr + przesun - 1) == '.'))
            return 0;
        if (*(expr + przesun) == '/' && *(expr + przesun + 1) != '\0' && (*(expr + przesun + 1) == '-' || *(expr + przesun + 1) == '+'
            || *(expr + przesun + 1) == '/' || *(expr + przesun + 1) == '*' || *(expr + przesun + 1) == '.'))
            return 0;
        if (*(expr + przesun) == '/' && przesun>0 && (*(expr + przesun - 1) == '-' || *(expr + przesun - 1) == '+'
            || *(expr + przesun - 1) == '/' || *(expr + przesun - 1) == '*' || *(expr + przesun - 1) == '.'))
            return 0;
        if (*(expr + przesun) =='.' && *(expr + przesun + 1) != '\0' && (*(expr + przesun + 1) == '-' || *(expr + przesun + 1) == '+'
            || *(expr + przesun + 1) == '*' || *(expr + przesun + 1) == '/' || *(expr + przesun + 1) == '.'))
            return 0;
        if (*(expr + przesun) == '.' && przesun>0 && (*(expr + przesun - 1) == '-' || *(expr + przesun - 1) == '+'
            || *(expr + przesun - 1) == '*' || *(expr + przesun - 1) == '/' || *(expr + przesun - 1) == '.'))
            return 0;
        if (*(expr + przesun) == '/' && *(expr + przesun+1) == '0')
            return 0;
        if (*(expr + przesun) == '*' && *(expr + przesun+1) == '*')
            return 0;
        if (*(expr) == '-' || *(expr) == '+' || *(expr) == '/' || *(expr) == '*')
            return 0;
        if (*(expr + przesun + 1) == '\0' && (*(expr + przesun) == '+' || *(expr + przesun) == '-' || *(expr + przesun) == '/' || *(expr + przesun) == '*'))
            return 0;
        if (*(expr + przesun) == '.')
            return 0;
    }
    return 1;
}

int calculate(const char* expr, float *result)
{
    if (expr == NULL || result == NULL){
        return 0;
        }

    if (validate_expression(expr) != 1){
        printf("Error\n");
        return 0;
    }

    int zm1 = 0;
    int znacznik1 = 0;
    float wyn1 = 0;
    float pam = 0;
    float temporary = 0;
    char znaczek = '+';

    for (zm1 = 0; *(expr + zm1) != '\0'; ++zm1)
    {
        if (czyToJestLiczba(expr + zm1) == 1 && znacznik1 == 0)
            pam = pam*10 + (int)*(expr + zm1) - 48;
        else if (*(expr + zm1) == '.')
            znacznik1 = 1;
        else if (czyToJestLiczba(expr + zm1) == 1 && znacznik1 == 1)
            temporary= temporary * 10 + (int)*(expr + zm1) - 48;
        if (znaczek == '+' && (*(expr+zm1)=='+' || *(expr + zm1) == '-' || *(expr + zm1) == '*' ||
            *(expr + zm1) == '/' || *(expr + zm1+1) =='\0'))
        {
            while (temporary >= 1)
                temporary = temporary / 10;
            wyn1 = wyn1 + pam + temporary;
            pam = temporary = 0;
        }
        else if (znaczek == '-' && (*(expr + zm1) == '+' || *(expr + zm1) == '-' || *(expr + zm1) == '*' ||
            *(expr + zm1) == '/' || *(expr + zm1 + 1) == '\0'))
        {
            while (temporary >= 1)
                temporary = temporary / 10;
            wyn1 = wyn1 - (pam + temporary);
            pam = temporary = 0;
        }
        else if (znaczek == '/' && (*(expr + zm1) == '+' || *(expr + zm1) == '-' || *(expr + zm1) == '*' ||
            *(expr + zm1) == '/' || *(expr + zm1 + 1) == '\0'))
        {
            while (temporary >= 1)
                temporary = temporary / 10;
            wyn1 = wyn1 / (pam + temporary);
            pam = temporary = 0;
        }
        else if (znaczek == '*' && (*(expr + zm1) == '+' || *(expr + zm1) == '-' || *(expr + zm1) == '*' ||
            *(expr + zm1) == '/' || *(expr + zm1 + 1) == '\0'))
        {
            while (temporary >= 1)
                temporary = temporary / 10;
            wyn1 = wyn1 * (pam + temporary);
            pam = temporary = 0;
        }
        if (*(expr + zm1) == '+')
            znaczek = '+';
        else if (*(expr + zm1) == '-')
            znaczek = '-';
        else if (*(expr + zm1) == '*')
            znaczek = '*';
        else if (*(expr + zm1) == '/')
            znaczek = '/';
    }

    *result = wyn1;
    return 1;
}

int czyToJestLiczba(const char *spr)
{
    if (spr == NULL || *spr<'0' || *spr>'9')
        return 0;
    return 1;
}
1

Zapewne chodzi o strstr, a skorzystać zamiast tych potworków, które masz w validate_expression i calculate

0

@kq: oki, zrobię to z wykorzystaniem tej funkcji i zobaczymy czy przechodzi. Dziękuję za naprowadzenie. ;)

0

Podaj jakieś przykłady wyrażeń i poprawnych wyników programu. Wyjaśnij co znaczy "Program liczy, biorąc pod uwagę znaki arytmetyczne od lewej do prawej (celowo), a nie poprawność matematyczną działań.", nie przestrzega koeljności działań, poprawności matematycznej? W jakim sensie? Bo sorry, ale tego kodu (przynajmniej ja nie potrafię) nie da się analizować.

0

@lion137:
Chodzi o wyrażenia gdzie (przykłady):

2+2*2 zwraca 8.00
345+324*22 zwraca 14718.00
123-33/4 zwraca 22.50

Program nie przestrzega kolejności działań matematycznych, bo tak było zaznaczone w poleceniu.

1

Żeby Ci to działało to Musisz mieć mini parser, idea jes taka:
Sprawdzasz czy poprawne, wspomniane przez @kq strstr plus ewentualnie string::find lub/i regexy.
Rozdzielasz wyrażenie do listy stringów , żeby się pozbyć spacji: "2 + 6-3" -> ['2', '+', '6', '-', '3']
Potem ewaluacja, Tworzysz stos liczb i Iterujesz po liście do przedostatniego elementu (to musi być liczba więc będzie "zdjęta"):

  • Jak liczba, Dorzucasz do stosu;
  • Jak operator: Zrzucasz ze stosu, Pobierasz następny element, Wykonujesz działanie i teraz stos liczb równa się wynikowi [działania].
  • I tak dalej...
    Na końcu, Zrzucasz ze stosu i Zwracasz wynik.
    Pseudokod (Python):
def do_math(t, a, b):
    if t == "+":
        return a + b
    if t == "-":
        return a - b
    if t == "*":
        return a * b
    if t == "/":
        return a / b

def evaluate(e):
    st = []
    e = e.replace("+", " + ").replace("*", " * ").replace("-", " - ").replace("/", " / ").split()
    n = 0
    while n < len(e) - 1: # len(e) = length(e)
        if e[n] not in "+-*/ ":
            st.append(e[n])
            n += 1

        elif e[n] in "+-*/":
            leftOp = st.pop()
            rightOp = e[n + 1]
            res = do_math(e[n], int(leftOp), int(rightOp))
            st = [res] 
            n += 2
        else:
            return("evaluate: Parse Error!")
    return st.pop()

expr = "2 + 2 *2-3"

print(evaluate(expr)) # -> 5
0

@kq: @lion137 zrobiłem to z wykorzystaniem funkcji strstr i nadal to samo.
Komunikat:

Test został przerwany; Jaka funkcja pozwoli odnaleźć w jednym ciagu znaków dowolny znak z drugiego ciągu znaków?
Należy z niej skorzystać.

Nie potrzebuję rozdzielać wyrażeń, a nawet nie powinienem tego robić. Cały myk polega na tym, że mamy narzucone wykonanie tego wyłącznie na wskaźnikach.
Wykorzystałem tę funkcję strstr do wyłapania dzielenia przez zero, uwzględniając w tym poszukiwanie znaku "/0". Nie wiem, co z tym dalej począć.

0

Zapomniałem napisać, że udało mi się poprawić program, a właściwie to napisałem go od nowa z funkcjami opartymi o Wasze wskazówki. :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0