aula 235

Desafio da aula 231 – descobrir se uma expressão está mal formada

Na aula de hoje trago a resposta ao desafio deixado na aula 231 e explico porque nosso algoritmo para descobrir se uma expressão está mal formada ou não irá falhar ao avaliar uma expressão como esta: 3 * (5 – 2) / 5].

O que acontece aqui é um erro lógico, ou seja, um problema em tempo de execução. Este tipo de erro é difícil de ser solucionado e a melhor maneira de descobrir a causa é avaliar linha a linha com um exemplo que causa o erro.

Para isso vamos usar o exemplo que já sabemos que irá falhar, a expressão: 3 * (5 – 2) / 5]

Ao avaliar a expressão seguindo as instruções da nossa função identifica_formacao, estamos procurando por parênteses, chaves e colchetes, então nada será feito para o 3 e para a multiplicação. Ao encontrar o caracter (, ele será empilhado, pois é um caracter de abertura. Nada será feito para os caracteres 5 – 2. Quando encontramos o caracter ), ele é de fechamento, então iremos desempilhar o topo da nossa pilha e verificar se formam um par. Neste caso formam.

Perceba que neste momento a pilha está vazia novamente.

Seguindo a expressão, nada é feito para os caracteres / 5. Quando encontramos o caracter ], ele é de fechamento, então desempilhamos o topo da pilha para verificar se formam um par. Contudo, há alguém na pilha?

Perceba que a pilha está vazia. Assim, ao tentarmos obter o caracter desempilhado em remover->caracter teremos um erro, pois o ponteiro remover é nulo. Para resolver isso basta acrescentarmos mais um teste verificando se o ponteiro remover é diferente de nulo. Se for diferente de nulo, então verificamos se formam um par. Caso contrário, já sabemos que a expressão está mal formada pois há um fechamento sem abertura.

        else if(x[i] == ']' || x[i] == ')' || x[i] == '}'){
            remover = desempilhar(&pilha);

            if(remover){ // se o ponteiro remover for diferente de nulo, verificamos se formam um par

                if(forma_par(x[i], remover->caracter) == 0){
                    printf("\tEXPRESSAO MAL FORMADA!\n");
                    return 1; // expressao está mal formada
                }
                free(remover);
            }

            else{ //  senão, já sabemos que a expressão está mal formada
                printf("\tEXPRESSAO MAL FORMADA!\n");
                return 1; // expressao está mal formada
            }

        }

Código completo em C para verificar se uma expressão está mal formada ou não

/*

            Código escrito por Wagner Gaspar
            Julho de 2021

            Aula 231: Como descobrir se uma expressão matemática está mal formada?

            3 * [(5 - 2) / 5]
            3 * (5 - 2) / 5] <-- ao testar com esta expressão o programa trava. Descobriu o motivo?
*/


typedef struct no{
    char caracter;
    struct no *proximo;
}No;

No* empilhar(No *pilha, char valor){
    No *novo = malloc(sizeof(No));

    if(novo){
        novo->caracter = valor;
        novo->proximo = pilha;
        return novo;
    }
    else
        printf("\tErro ao alocar memoria!\n");
    return NULL;
}

No* desempilhar(No **pilha){
    No *remover = NULL;

    if(*pilha){
        remover = *pilha;
        *pilha = remover->proximo;
    }
    else
        printf("\tPilha vazia\n");
    return remover;
}

void imprimir(No *pilha){
    printf("\n\tPILHA\n");
    while(pilha){
        printf("\t%c\n", pilha->caracter);
        pilha = pilha->proximo;
    }
    printf("\tFIM PILHA\n\n");
}

int forma_par(char f, char d){
    switch(f){
    case ')':
        if(d == '(')
            return 1; // bem formada
        else
            return 0; // mal formada
        break;
    case ']':
        if(d == '[')
            return 1; // bem formada
        else
            return 0; // mal formada
        break;
    case '}':
        if(d == '{')
            return 1; // bem formada
        else
            return 0; // mal formada
        break;
    }
}

int identifica_formacao(char x[]){
    int i = 0;
    No *remover, *pilha = NULL;

    while(x[i] != '\0'){
        if(x[i] == '[' || x[i] == '(' || x[i] == '{'){
            pilha = empilhar(pilha, x[i]);
            imprimir(pilha);
        }
        else if(x[i] == ']' || x[i] == ')' || x[i] == '}'){
            remover = desempilhar(&pilha);
            if(remover){
                if(forma_par(x[i], remover->caracter) == 0){
                    printf("\tEXPRESSAO MAL FORMADA!\n");
                    return 1; // expressao está mal formada
                }
                free(remover);
            }
            else{
                printf("\tEXPRESSAO MAL FORMADA!\n");
                return 1; // expressao está mal formada
            }
        }
        i++;
    }
    imprimir(pilha);
    if(pilha){
        printf("\tExpressao mal formada!\n");
        return 1;
    }
    else{
        printf("\tEXPRESSAO BEM FORMADA!\n");
        return 0;
    }
}

int main(){
    char exp[50];

    printf("\tDigite um expressao: ");
    scanf("%49[^\n]", exp);
    printf("\nExpressao: %s\nRetorno: %d\n", exp, identifica_formacao(exp));
}

Deixe um comentário

um × cinco =

Wagner Gaspar

Capixaba de São Gabriel da Palha, Espírito Santo. Bacharel em Ciência da Computação pela Universidade Federal do Amazonas e mestre em informática pela Universidade Federal do Espírito Santo.