KULATOR Cpp
Evo,ponukan raspravom na temu kalkulator u C-u,ovdje ću postati kalkulator u C++-u.
Možda nekom zatreba a možda ne,napominjem da je rađen u MS VisualStudio IDE,Windows OS
i neka se to uzme u obzir,također je to za one koji su se odmakli od početaka učenja C++-a!
Naravno samo objašnjavanje je zasad unutar koda jer je još uvijek u beta verziji jer nemam sad
vremena na uređivanje i jasniji pogled u editiranje sadržaja ali poraditi ću na tome ,stoga
se ispričavam ako na početku bude problema u snalaženju.Još dugujem objašnjenja pojedinih dijelova koda
ali kad budem imao vremena objasnim.Također će biti i onih koji će svaki dio koda ili rečenice analizirati,stoga
napominjem da je ovo beta verzija podložna promjenama.
Meni je razumijevanje kad sam prvi put radio kalkulator bilo sasvim dovoljno znati raditi s funkcijama
i uvjetima.Nadam se i vama.
/*NAPOMINJEM DA SAM RADIO U VISUAL STUD. 2008 I IMA NEKE SPECIFICNOSTI
I PRIMJENIO SAM SYSTEM NAREDBE I WINDOWS ZAGLAVLJE I OKRUZENJE
MOLIM DA SE TO UZME U OBZIR KAD SE BUDE KRITIZIRALO! */
#include<iostream>
#include<cstdlib>
#include<cctype>
#include<windows.h>
#include<cstring>
using namespace std;
//-----------------------------------------------------
const int MAX =80; //treba nam constantna vrijednost koju cemo
//unositi preko tipkovnice,a ako vi zelite nesto drugo tad samo to ovdje izmjenite
//------------------------------------------------------------
//-------deklaracije funkcija------------------------------
//------------------------------------------------------------
void praznine(char* praznine);
double izraz_gotov(char* znak);
double uvjet(char* izraz,int& index);
char* izdvoji(char* izraz,int& index);
double brojevi(char* izraz,int& index);
//------------------------------------------------------------------
int main()
{
system("TITLE K a l k u l a t o r ,Windows OS"); //naslov
system("COLOR 6f"); //za pozadinu i slova
char spremiste[MAX] = {0};//napravili smo polje znakova velicine MAX
cout<<"Dobro dosli u kalkulator!"<<endl;
cout<<"Unesite izraz koji zelite i enter na kraju kao i za izlaz:"<<endl;
for(;;) //opet beskonacna petlja koja treba uvjete
{
cin.getline(spremiste,sizeof spremiste);
/*ovdje unosimo nase brojeve
velicine spremista jer funkcija getline ima ovaj izgled getline(ime_varijable,velicina)
a velicina je odredjena sizeof-om a to je 80,mogli smo i to
napisati ali ako bismo mijenjali velicinu i tu bi morali intervenirati
i zato je lakse napisati sizeof kao odrednicu velicine*/
praznine(spremiste);//pozovemo funkciju praznine
if(!spremiste[0])//valjda razumijete
return 0;
cout<<"\t = "<<izraz_gotov(spremiste)<<endl<<endl;/*i evo rezultata
ova funkcija poziva sve nase funkcije
koje joj trebaju unutar nje same*/
}
return 0;
}
//-------------------------------------------------------------
//----------------definicije funkcija------------------------------
//----------------------------------------------------------------
void praznine(char *praznine)
{
int i = 0;
int j= 0;
while((*(praznine + i) = *(praznine + j++)) !='\0')
if(*(praznine + i) !=' ')
i++;
}
//----------------------------------------------------------
/*ova funkcija void praznine kao sto joj i ime govori eliminira
praznine u unosu neseg teksta(brojeva) s tipkovnice.
prvo sto napravimo je deklaracija i inicijalizacija varijabli
koje ce nam sluziti za prolazak kroz nas unos s tipkovnice ,
primjetite da u varijablu i sprememo varijablu j u while petlji
,j varijablu zatim povecavamo sve dok ne dodjemo do kraja naseg unosa('\0')
a u if uvjetu povecavamo samo 'i'koje nema praznine u sebi ,i tako dobijemo
izraz bez praznina!
npr. 2 + 6 * 5
i sad uvecavajuci j dolazimo do kraja ali pamti se samo ono sto
nema praznine i na karaju izraz ima oblik....2+6+5
Naravno funkcija kao argumente ima char* pokazivac na znakovni niz
i kao takav nam koristi unutar funkcije i proslijedjujemo ga
u while petlji na analizu
*/
//---------------------------------------------------------------
double izraz_gotov(char* znak)
{
double broj = 0.0;
int index= 0;
broj = uvjet(znak,index);
for(;;)
{
switch(*(znak + index++))
{
case '\0':
return broj;
case '+':
broj = broj + uvjet(znak,index);
break;
case '-':
broj = broj - uvjet(znak,index);
break;
default:
cout<<"Greska!"<<endl;
exit(1);
}
}
}
//----------------------------------------------------------------------
double uvjet(char* izraz,int& index)
{
double broj = 0.0;
broj = brojevi(izraz,index);
while((*(izraz + index)== '*' )|| (*(izraz + index) == '/'))
{
if(*(izraz + index)=='*')
broj = broj*brojevi(izraz,++index);
if(*(izraz + index)=='/')
broj = broj/brojevi(izraz,++index);
}
return broj;
}
char* izdvoji(char* izraz,int& index)
{
char spremiste[MAX];
char* pok = 0;
int br = 0;
int sprempok = index;
do
{
spremiste[index - sprempok] = *(izraz + index);
switch(spremiste[index-sprempok])
{
case ')':
if(br == 0)
{
spremiste[index-sprempok] = '\0';//zamjena ) s znakom za kraj
++index;
pok = new char[index-sprempok];
if(!pok)
{
cout<<"Alokacija memorije nije uspjela!"<<endl;
exit(1);
}
strcpy_s(pok,index-sprempok,spremiste);
return pok;
}
else
br--;
break;
case '(':
br++;
break;
}
}while(*(izraz+index++) !='\0');
cout<<"Sigurno los unos !"<<endl;
exit(1);
return pok;
}
//--------------------------------------------------------------------------
double brojevi(char* izraz,int& index)
{
double vrijednost = 0.0;
if(*(izraz + index)=='(')
{
char* pokizraz =0; //pokazivac tipa char*
pokizraz = izdvoji(izraz,++index);
vrijednost = izraz_gotov(pokizraz);
delete [] pokizraz;
return vrijednost;
}
while(isdigit(*(izraz + index)))
vrijednost = 10*vrijednost + (*(izraz + index++)-'0');
if(*(izraz +index) !='.') //ako naidje na tocku tad ovo ispod racuna
return vrijednost; //vrati vrijednosti
double faktor = 1.0;
while(isdigit(*(izraz +(++index)))) //ovo je za decimale
{
faktor *=0.1;
vrijednost = vrijednost + ( *(izraz + index)-'0')*faktor;
} //na kraju mnozimo s 0.1 da bismo dobili parvi izraz koji nama
//odgovoara.
return vrijednost; //vrati vrijednosti
}
//-------------------------------------------------------------------------------
/*
,zbog ove funkcije(isdigit) morate ukljuciti <cctype> zaglavlje
radi ispitivanja znakova.
Na pocetku deklariramo varijablu tipa double jer ispitijujemo i
brojeve s zarezima tj. cijeli izraz broja koji unesemo .
Ispiitivanje se svodi na dvije faze.
Prva ispituje brojeve s konsole lijevo od tocke(zareza) a drugi
dio ispituje one poslije zareza(desno).
Sve to radimo kroz while petlju (opet).
funkciji isdigit() proslijedjujemo nas argument...izraz i posto
se radi o decimalama lijevo od zareza mi vrsimo mnozenje s deset
jer ovaj izraz (*(izraz+index++)-'0') znaci :
Ako smo unijeli recimo s tipkovnice broj 635
njegova analiza kao znak se sprema i analizira u nasoj while
petlji i rezultat toga se pohranjuje u varijablu vrijednost
i posto je to funkcija s return oblikom tako je i zavrsavamo
return vrijednost.
sad korak po korak:
ASCII kodovi za nas broj su broj 6 = 48+6 = 54
3= 48+3 = 51
5= 48+5 = 53
znaci sad smo samo pokazali kako su prikazani
nasi brojevi u ASCII obliku jer s tim oblicima radimo.
i sad to samo uvrstimo u onu nasu while petlju:
vrijednost = 10 * vrijednost +(54-48)
a to je 10*0.0 + 6
i imamo vrijednost = 6 za nasu prvu znamenku i tako za sve tri
jer imamo index++ koji nas pomice kroz nas izraz.Tako dobijemo
635.0 i ako nema tocke tad se ispitivanje zavrsava a ako ne:
Sad idemo na drugu fazu base funkcije.
Postavljamo varijablu faktor na 1.0
jer ce nam trebati da bi izracunavali ono sto nam ide poslije tocke
jer faktor mnozimo s 0.1 da bi smo dobili decimalna mjesta.
recimo da smo napisali ovaj broj : 635.123
Znaci ispitivanje se nastavlja jer je program (funkcija naisla na
decimalna mjesta i sad ide ponovo while petlja i opet ispitivanje
znakova naseg izraza ali sad nakon decimalnog znaka tocke
.
Znaci vec imamo nasu vrijednost koju smo prije dobili
vrijednost = 635.0;
faktor = 1.0;
faktor = 0.1*faktor;
vrijednost = vrijednost + faktor(49-48)
= 635 + 0.1* 1;
= 635.1
i tako za svaku nasu vrijednost i na kraju je logicno
return vrijednost i tako smo dobili nas broj
635.123.*/
//----------------------------------------------
/* zbrajanje i oduzimanje je poslije
jer smo mnozenje rijesili a i dijeljenje,.
Ovo rjesavamo preko switch() case uvjeta u beskonacnoj petlji
koja mora uvijek imati neki uvjet da ne bi bila beskonacna
a nama najpogodnija za kalkulator,sistem rada je poznat
u varijablu broj spremamo ono sto smo izracunali s proslom funkcijom
a u switch stavljamo ono sto se unosi
preko tipkovnice i ako naidje na znak + tad se zbarajanje izvrsava
i tako dalje i za naredbu exit(1) nam treba zaglavlje <cstdlib>
Sad imamo sve gotove funkcije koje smo poslagali i idemo na glavni program*/
Ne želim se obazirati na komentare jer to mi nije namjera.Rekao sam da dugujem objašnjenje još kojeg
dijela koda a to sad dolazi na red.
Funkciju koja izdvja zagrade smo ubacili u funkciju broj,ali prvo da objasnimo kako radi
funkcija koja izdvaja zagrade.
Prvo naravno pravimo privremeni niz koji će držati naš izraz koji
provjeravamo.Mi ne znamo koliko će taj izrai biti veliki(MAX) ali ne smije biti veći od naše konstante.
Također ne možemo vraćati adresu od spremišta koja se nalazi u samoj funkciji jer je lokalno,i uništava se čim izađemo iz funkcije.
Zato ,moramo alocirati memoriju kad saznamo koliki je izraz.
Ovo radimo deklarirajući pokazivač tipa char ,znači pokazivač na niz znakova,i alociramo memoriju veličine u uglatim zagaradma.
Slijedi izraz koji nam govori ako to nije istina tad nismo uspjeli s alokacijom.
Ako je istina tad kopiraj izraz i spoji sve pomoću funkcije strcpy_s().
strcpy_s() je funkcija koja treći argument kopira u prvi dužine drugog.
Naravno ,moramo uključiti zaglavlje <cstring> za tu funkciju.
Sad naravno možemo napistai return pok.Deklarirali smo također brojač br koji "pamti "zagrade ,
i kad dođe do kraja tad je to kraj našeg izraza.U biti glavnina funkcije je u do-while petlji,
i počinje naravno s nalaženjem prve lijeve zagrade i taržimo sve lijeve zagarde dok ne dođemo do prve desne
zagrade,kad naiđemo do prve desne uparimo s zadnjom nađenom lijevom
i izračunamo izraz koji je u njoj,zatim nađemo slijedeći par i izračunamo taj
izraz i tako dok sve ne uparimo i dođemo do kraja.
Sve je dakle u switch() case uvjetima samo slažemo i pomićemo se u do while petlji
a sve dobiveno spremamo u privremenu memomriju u kojoj vršimo izračune i naravno sve spremamo u varijablu vrijednost ,
a sve se izvršava dok u funkciji brojevi () if uvjet više ne bude točan.
Tad funkcija brojevi ide dalje.
Sam redoslijed izvršavanja radnji množenja i djeljenja je riješen u funkciji
izraz_gotov() jer unutar nje je funkcija uvjet () koja se prva poziva a tek se onda rješava zbrajanje i oduzimanje,
tako da u glavnom programu pozivamo samo tu funkciju jer je unutar nje funkcija koja rješava djeljenje i množenje.
Naravno ,tu su switch() i case uvjeti koji su sami po sebi valjda jasni.
Znači,mi smo prvo rješavali praznine ,zatim smo se uhvatili rješavanja naših
izraza brojeva i o čem se radi da bi gotov izraz proslijedili funkciji koja je u glavnom progarmu.
Funkcija izdvoji_gotov() poziva dakle sve.Prvo poziva naravno funkciju uvjet() ,
jer ona vrši množenje i dijeljenje i onda zbrajanje i oduzimanje jer smo to
postavili u switch() case uvjetima a unutar te funkcije je pozvana funkcija brojevi.
Znači sam redoslijed aritmetike množenje ,dijeljenje pa zbrajanje i oduzimanje je riješeno funkcijom izraz_gotov(),
koja unutar sebe poziva funkciju koja rješava množenje i djeljenje.
Zagrade su rješenje znači običnim brojčem i nalaženjem odgovarajućeg para i
smješatnjem u privremenu memoriju gdje vršimo izračun tog nađenog izrazai u do-while uvjetu to radimo(uparivanje) dok ne dođemo do kraja.
A sve to započinje uvjetom u funkciji brojevi()....onaj if uvjet.
Na taj način rješimoprvi unutarnji par zagarad() pa onda slijedeći i slijedeći i dok ne dođemo do
znake za kraj.Eto ,nadam se da je sad malo jasnije.
U izrazu:
10/((2+4)/3+3)
dakle program prvo nailazi na prvu lijevu pa se pomiče na drugu lijevu zagardu
i dolazi do prve desne i izračuna taj izraz koji je 6 i zatim nailazi na znak dijeljenja
i izvrši dijeljenje s brojem tri i zatim tarži par za ostatak od lijeve zagrade
i nađe i sad izvršava taj izraz znači 2+3 i to je pet i tek onda izlazi iz izraza sa zagradama
i izvršava djeljenje i evo rezultat dva.
Znači funkcija brojevi ide dalje tek kad riješi zagrade u if uvjetu
i onda je to "normalni" dio.
Prioritet je riješen u funkciji uvjet().
Koja je pozvana za svaki nađeni izraz u priovremenoj memoriji.
Edit: Ne razumijem tvoje zaključke i slične primjedbe,stalno si u napadu prema meni,naravno
postavljajući se s visoka ,a to dakako nemaš pravo ako ti nisam student ili zaposlenik.
Pogledaj malo moje postove...nikoga ne omalovažavam jer to mi nije cilj na niti jednom postu a trudim se
i na drugim forumima.Ako ti se ne sviđa baš kod ili slično napiši drugi post i tamo objasni sve što
timleži na duši a ja pogriješio u kodu ili ispustio ,zaboravio ili ne znao.
stoga ako češ pljuvati po bilo čijem radu a ne lijepim riječima objašnjavati
ili ispravljati(bilo koga)...na komentare ne želim niti odgovarati.
....i kad ga pokrenete......slika(boje se mijenjaju samo izmjenom broja i slova,kao u HTML: