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));
}
