Zamiana i obliczanie ONP - Problem

0

Witam. Wiem że podobne tematy już były ale nie admin usunął mi post jak chciałem odkopać pewien stary.

Otóż mój problem polega na tym że zjada mi ostatni znak przy zamianie.

dla przykładu (2+1)3-4(7+4) z algorytmów na ONP na 4programmers nie wyswietla ostatniego minusa...
nie mam pojęcia jak do tego dojść, co ruch wyswietlalem stos i "-"... i wiem tyle ze jest 7elelentem wyrazenia nie wiem gdzie się zagubił. Programuje niecałe pół roku i nie umiem się posługiwać debugerem :P Dlatego prosił bym o wprawne oko i nakierowanie mnie na błąd. Pozdrawiam

Kod:


#include <stdio.h>
#include "stdafx.h"
#include<fstream>
#include <iostream> 
#include <string> // do odczytu dlugosci stringa
#include<stack> 

using namespace std;


int main()
{
FILE *plik;
char znak;
stack<char>stos;
char wyrazenie[100];
char wyjscie[100];
int i;
for(i=0;i<100;i++)   // zerowanie wyrazenie[i], wyjscie[i]
		{	
		wyrazenie[i]=NULL;
		wyjscie[i]=NULL;
		}
i=0;



// --- otwarcie pliku
/*
fstream plik;
plik.open("plik.txt", ios::in);

	if(plik.good()==true)
	{
		while( !plik.eof())
		{
			plik>>znak;
			wyrazenie[i]=znak;
			i++;
		}
	
	}
	else
		cout<<"Blad otawrcia pliku!";

plik.close();
// -- zamkniecie pliku
*/

plik = fopen("plik.txt","r");
	if (plik == NULL)
	{
		cout<<"Blad otwarcia pliku"<<endl;
		return (-1);
	}


	//--------- odczyt pliku   
		while( (znak=fgetc(plik)) !=EOF) 
	{
		wyrazenie[i]=znak;  
		i++;
	}

cout<<"Wyrazenie: "<<wyrazenie<<endl;
cout<<" ONP: ";



int dlugosc=strlen(wyrazenie);
	for(i=0;i<dlugosc;i++)		
	{
			switch (wyrazenie[i])		
			{
							case '(':							//stos.top() - '('     stos.size() =1;
								stos.push( wyrazenie[i] ); // poprawne
							break;

							case ')': // jezeli ")" to zdjemuje wszystko ze stosu
								
								while( stos.empty() == false ) 
								{
									if(stos.top()!='(') // jezeli natrafisz na ')' zdejmij ale nie wyswietlaj
									{
										cout << stos.top();
									//	wyjscie[i]=stos.top();
										stos.pop();
									}
									stos.pop();
									
								}
							break;

							case '+':											
							case '-':
								while (stos.size()>0 && stos.top() != '(' ) 
								{
								cout << stos.top();
							//	wyjscie[i]=stos.top();
								stos.pop();
									
								}
								stos.push(wyrazenie[i]);
							
							break;

							case '*':												
							case '/':		
							case '%':
								while (stos.size() > 0 && (stos.top() == '*' || stos.top() == '/' || stos.top() == '%'))
								{
								cout << stos.top();
								//wyjscie[i]=stos.top();
								stos.pop();
								}
								stos.push(wyrazenie[i]);
							break;

							default:
								cout << wyrazenie[i];
							//	wyjscie[i]=wyrazenie[i];
							break;
						}
					}
			while ( stos.empty()== false)  
			{
				stos.pop();
				cout<< stos.top();
			}

			

cout<<endl;
system("pause");





	return 0;
	}


 

ps. wczytywanie znaków z pliku jest w jezyku c... w zapisie

// --- otwarcie pliku
/*
fstream plik;
plik.open("plik.txt", ios::in);

	if(plik.good()==true)
	{
		while( !plik.eof())
		{
			plik>>znak;
			wyrazenie[i]=znak;
			i++;
		}
	
	}
	else
		cout<<"Blad otawrcia pliku!";

plik.close();
// -- zamkniecie pliku
*/

plik = fopen("plik.txt","r");
	if (plik == NULL)
	{
		cout<<"Blad otwarcia pliku"<<endl;
		return (-1);
	}


	//--------- odczyt pliku   
		while( (znak=fgetc(plik)) !=EOF) 
	{
		wyrazenie[i]=znak;  
		i++;
	}

cout<<"Wyrazenie: "<<wyrazenie<<endl;


 

dubluje ostatni znak...

ps2

co do google... to znalazlem pelno informacji na temat stosu, wyswietlania plików, whatever ale w tym błędzie mi raczej nie pomoże. Pozdrawiam

0

Na pierwszy rzut oka masz dziwne warunki parsowania: powinny być tylko takie uwzględnione:

  • Lewy nawias
  • Prawy nawias
  • Przecinek (separator argumentów funkcji)
  • 0-9 . (cyfry i separator dziesiętny)
  • A-Z (nazwy funkcji)
  • Unarne operatory "+" i "-" jako funkcje . Jak je rozpoznać jest opisane w komentarz którymś tutku na 4p.
  • Operatory binarne
0
maciejmt napisał(a)

Na pierwszy rzut oka masz dziwne warunki parsowania:

mógł byś szerzej wyjaśnić ? algorytm jest dobry - zamienia tak jak powinien... tylko gubi gdzieś "-" ... w algorytmie na onp na 4p nie ma nic o przecinkach ;| - sory za moją nie kompetencje ale uczę się programowania w większości sam... - na labrokach "nie ma czasu" ;]

0

dubluje ostatni znak...

jeśli przy wczytywaniu z pliku to może spróbuj coś takiego:

 
i=0;
fstream plik("plik.txt", ios::in);
 
        if(plik.good())
        {
                for(;;)
                {
                        plik>>znak;
                        if(plik.eof()) break;
                        wyrazenie[i]=znak;
                        i++;
                }
        
        }
        else
                cout<<"Blad otawrcia pliku!";
 
plik.close();
0

cysiej: odczyt dobry/ nie dubluje ale nadal minus jest zagubiony ;P

1

Mi się nie podoba ten kod we switch-u, w którym już wykryłeś nawias zamykający. Dlaczego zdejmujesz wszystko ze stosu? Moim zdaniem, powinno być zdejmowane wszystko aż do nawiasu otwierającego '('. Dlatego chyba gubi minusa.

0

JEST

zmieniłem case ')' na

 
	case ')': // jezeli ")" to zdjemuje wszystko ze stosu
								while( stos.empty() == false) 
								{
									if(stos.top()!='(') // jezeli natrafisz na ')' zdejmij ale nie wyswietlaj
									{
										cout << stos.top();
									//	wyjscie[i]=stos.top();
									}
									stos.pop();	
								}
							break;

(USUNĄŁEM stos.pop(); zaraz po wyswietleniu)
mimo wszystko program wywala się przy zagniezdzonych 2 nawiasach ale to problem na później...

działa poprawnie ;) teraz tylko sposób aby wyjście do nowej tablicy zapisywał - żeby szło to dalej obliczyć ;) i po projekcie... dziękuję bardzo masz +

0

Przykładowa możliwość: ustalasz sobie zmienną dlugosc_wyjscia = 0 typu int. i po prostu, zamiast wypisywać znak, zapisz ten znak w komórce numer "długosc_wyjscia" (wyjscie[dlugosc_wyjscia] = stos.top() zamiast cout << stos.top()). Po wypisanym znaku należy, rzecz jasna, zwiększyć dlugosc_wyjscia o 1.

0
 

#include <stdio.h>
#include "stdafx.h"
#include<fstream>
#include <iostream> 
#include <string>
#include<stack> 

using namespace std;
const string autor = "xxxx yyyyy  \n\t\t nr.albumu:zzzzzz;

int main()
{
char znak;
stack<char>stos;
char wyrazenie[100];
char wyjscie[100];
char pom[100];
int i,j;

cout<<"Autorem programu jest:"<<endl<<endl;
cout<<"\t\t"<<autor<<endl<<endl;

cout<<"Projekt: Odwrotna Notacja Polska"<<endl;
cout<<"-----------------------------------------------------"<<endl<<endl;

for(i=0;i<100;i++)   // zerowanie wyrazenie[i], wyjscie[i],pom[i]
		{	
		wyrazenie[i]=NULL;
		wyjscie[i]=NULL;
		pom[i]=NULL;
		}
i=0;
j=0;

// otwieranie pliku
fstream plik("plik.txt", ios::in); 
        if(plik.good())
        {
                for(;;)
                {
                        plik>>znak;
                        if(plik.eof()) break;
                        wyrazenie[i]=znak; // pojedyncze znaki wpisywane do tablicy wyrazenie
                        i++;
                }
        }
        else
                cout<<"Blad otawrcia pliku!";
 
plik.close();
// -- zamkniecie pliku

cout<<"Wyrazenie: "<<wyrazenie<<endl;

int dlugosc=strlen(wyrazenie);
	for(i=0;i<dlugosc;i++)
	{j++;
			switch (wyrazenie[i])		
			{
							case '(':							//stos.top() - '('     stos.size() =1;
								stos.push( wyrazenie[i] ); // poprawne
							break;

							case ')': // jezeli ")" to zdjemuje wszystko ze stosu
								while( stos.empty() == false) 
								{
									if(stos.top()!='(') // jezeli natrafisz na ')' zdejmij ale nie wyswietlaj
									{
										wyjscie[j]=stos.top();
										j++;
									}
									stos.pop();	
								}
							break;

							case '+':											
							case '-':
								while (stos.size()!=0 && stos.top() != '(' ) 
								{
								wyjscie[j]=stos.top();
								j++;
								stos.pop();
									
								}
								stos.push(wyrazenie[i]);
							break;

							case '*':												
							case '/':		
							case '%':
								while (stos.size() && (stos.top() == '*' || stos.top() == '/' || stos.top() == '%'))
								{
								wyjscie[j]=stos.top();
								j++;
								stos.pop();
								}
								stos.push(wyrazenie[i]);
								break;

							default:
								wyjscie[j]=wyrazenie[i];
								j++;
							break;
						}
					}

while( stos.empty() == false) // reszta ze stosu
	{
		wyjscie[j]=stos.top();
		j++;
		stos.pop();
	}
cout<<endl;

j=0;

cout<<"Wyjscie: ";
for(i=0;i<100;i++)   // usuwanie zbednych spacji
	{
			if(wyjscie[i] != NULL)
			{
				pom[j]=wyjscie[i];
				j++;
			}
	}
for(i=0 ;i<100;i++)	// wyswietlanie wyjscia bez spacji
	cout<<pom[i];

//---------------- obliczanie
int a=0,b=0,c=0;
long int wynik=0;
stack<int>stos2;
dlugosc=strlen(pom);
	for(i=0;i<dlugosc;i++)
	{
			switch (pom[i])		
			{
							case NULL:
							break;
							
							case '+':
								a=stos2.top();
								stos2.pop(); 
								b=stos2.top();
								stos2.pop(); 
								wynik=b+a;
								stos2.push(wynik);
						  break;
							case '-':
								a=stos2.top();
								stos2.pop(); 
								b=stos2.top();
								stos2.pop(); 
								wynik=b-a;
								stos2.push(wynik); 
							break;

							case '*':
								a=stos2.top(); 
								stos2.pop(); 
								b=stos2.top();
								stos2.pop(); 
								wynik=b*a;
								stos2.push(wynik);
							  break;
							
							case '/':	
								a=stos2.top();
								stos2.pop(); 
								b=stos2.top();
								stos2.pop(); 
								wynik=b/a; 
								stos2.push(wynik);
							break;

							case '%':
								a=stos2.top();
								stos2.pop();
								b=stos2.top();
								stos2.pop();
								wynik=b%a;
								stos2.push(wynik);
							break;
	
							default:
								pom[i]=pom[i]-48; // zamiana na int
								stos2.push(pom[i]);
							break;
						}
					}
cout<<endl;

cout<<"Wynik: " << stos2.top();

cout<<endl<<endl;
cout<<"----------------------------------------------------------"<<endl;
cout<<endl;
system("pause");


		return 0;
}


Na razie program wygląda tak... aktualny problem jest taki że nie przelicza wiecej niz 1cyfrowych liczb... spowodowane to temu ze kazda liczba jest osobnym znakiem w tablicy pom (pomocniczej) .... na kazdym kroku wychodzi konflikt char->int wie ktoś jak to łatwo ominąć/zamienić?

pomysł:
w defaulcie zrobić licznik - jezeli pod rząd wczytam 3 chary... po zamianie ich na inty (-48) traktować jako 1int... tylko jak to zrobić ;] musiał bym miec setki,dziesiątki i jednosci... i skąd licznik będzie wiedział że ma zliczać od nowa :|

kod się komplikuje coraz bardziej... samo uzycie drugiego stosu (integerowego) denerwuje...

To by było na tyle - jeszcze raz dzięki za pomoc.

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