xmitz xmitz - 1 month ago 14
C Question

Rearrange array for calculator BODMAS

Im trying to rearrange my calculator array to escape the BODMAS conditions. Basicly, I read a string, I add the numbers and operatores into diferent arrays and then I try to rearrange each array to make the operations that have priority (from right to left in the array). I make this changes on "priorizar" function. I guess the rearrange is not working. Is something wrong in my code? Thanks in advance

#include <stdio.h>

#define MAX 100

struct stacknum{
float nums[MAX];
int topnum;
}sn; //'stack' de numeros - nao prioritaria

struct stackops{
char ops[MAX];
int topop;
}so; // 'stack' de operadores - nao prioritaria

struct stacknum1{
float nums1[MAX];
int topnum1;
}sn1; // 'stack' de numeros - prioritaria

struct stackops1{
char ops1[MAX];
int topop1;
}so1; // 'stack' de operadores - prioritaria

float calculo(float vlr, float vlr2, char op) // funçao de operaçoes
{
if ('+' == op)
return vlr + vlr2;

if ( '-' == op)
return vlr2 - vlr;

if ( '*' == op)
return vlr * vlr2;

if ('/' == op)
return vlr2 / vlr;
else
return 0;
}

void priorizar()
{
int i, k = 0;
char aux;
float aux1, aux2;

for (i = 0; i < MAX; i++)
{
if (so.ops[i] == '*' || so.ops[i] == '/')
{
aux = so.ops[so.topop - k];
so.ops[so.topop - k] = so.ops[i];
so.ops[i] = aux;
aux1 = sn.nums[sn.topnum - (k + 1)];
aux2 = sn.nums[sn.topnum - k];
sn.nums[sn.topnum - (k + 1)] = sn.nums[i];
sn.nums[sn.topnum - k] = sn.nums[i + 1];
sn.nums[i] = aux2;
sn.nums[i + 1] = aux1;
k++;
}
}
}

float emptystack(int k) // faz operaçoes a partir da stack , esvazia-a fazendo todas as operaçoes dentro dela
{ // buffer size excedido quando 20+20*30 ????
float v1, v2;
char op;

if (k == 0)
{
while (so.topop != 0) // esvaziar stack
{
v1 = sn.nums[--(sn.topnum)];
v2 = sn.nums[--(sn.topnum)];
op = so.ops[--(so.topop)];
sn.nums[sn.topnum++] = calculo(v1, v2, op);
}

return sn.nums[sn.topnum - 1];
}
else
{
while(so1.topop1!=0) // esvaziar stack prioritaria
{
v1 = sn1.nums1[--(sn1.topnum1)];
v2 = sn1.nums1[--(sn1.topnum1)];
op = so1.ops1[--(so1.topop1)];
sn1.nums1[sn1.topnum1++] = calculo(v1, v2, op);
}

return 0;
}
}

int IsDigit(char str[], int i) // se é digito ou nao lel kek
{
if(str[i] >= '0' && str[i] <= '9')
return 1;
else return 0;
}

float analisa(char str[]) // analise de string, BODMAS + parenteses
{
int i;
float valor;
char op;

for (i = 0; str[i] != '\0'; i++)
{
if (IsDigit(str, i)) // Ñ PARENTESES
{
sscanf(str + i, "%f", &valor); // le e passa para float
sn.nums[sn.topnum++] = valor; // empilha numero

while (str[i + 1] == '.' || (str[i + 1] >= '0' && str[i + 1] <= '9'))
i++;
} else if (str[i] == '+' || str[i] == '-' || str[i]=='*' || str[i] == '/') // empilha se for operaçao nao prioritaria
so.ops[so.topop++] = str[i];
}

priorizar();
return emptystack(0); // esvazia stack nao prioritaria e retorna o resultado final
}

int main()
{
char str[100] = "3*3+2";
float resultado;
//printf("Expressao: ");
//scanf("%s",str);
resultado = analisa(str);
printf("%g\n",resultado);
return 0;
}

Answer

The low level problem is the priorizar() function doesn't manage the stacks correctly -- it looks for things in the wrong places:

aux = so.ops[so.topop - k];

When k = 0, this is garbage memory, it should be:

aux = so.ops[so.topop - k - 1];

which is the top item on the stack. And it doesn't correctly account for the fact that the sn stack grows at a varying rate compared to the so stack, sometimes twice as fast, sometime at the same rate. So you can't use a fixed offset to index both:

sn.nums[i] = aux2;
sn.nums[i + 1] = aux1;

At times this would be:

sn.nums[2 * i] = aux2;
sn.nums[2 * i + 1] = aux1;

and at others there is only one number that can be manipulated as the other half of the equation is an expression.

The high level problem is the logic is wrong. If we visualize the stacks:

so: * +
sn: 3 3 2

Then what priorizar() does is first:

so: + *
sn: 3 2 3

Which give us 9 ((2 * 3) + 3) instead of the desired 11. But since the search up the operator stack continues all the way, it reencounters the '*' again and transforms it once more by mistake:

so: * +
sn: 3 garbage 3

Giving us (3 + garbage) * 3). Even if you fix the mistake and keep i and so.topop - k from crossing, you still end up with the wrong answer.

You can rearrange the code in priorizar() as much as you want, but I don't believe you can get there from here.

Comments