C++ - simulace obchodu na principu fronty
Ahoj! Tak jsme dostali zadání školního projektu, ze kterého nejsem moc chytrý :D Máme udělat simulaci obchodu na principu fronty, tj. mám zadán počet pokladen, počet zákazníků a max. počet položek, které můžou zákazníci koupit. Program má pak vypisovat u každého zákazníka "stav", tj. G"index""počet věcí co nakoupil" - po vygenerování, V"index""pokladna u které je nejkratší fronta - tam se zařadí""pořadí v té frontě", K"index""počet prvků co mu zbývá v košíku" - při každém průběhu hl. cyklu se za současného generování a zařazování nových zákazníků "odbaví" jedna položka z jeho nákupu. No a na závěr, po odbavení všech položek O"index""počet lidí, co zbývá ve frontě odkud zákazník odešel".
Myslím, že problém je v ukončovací podmínce hlavního cyklu, nebo u práce s hlavou fronty na konci programu - některé zákazníky mi to neodebírá a počítá s nimi dál, pak dochází k tomu, že se program ukončí předdčasně, aniž by všichni zákazníci odešli / jede do nekonečna / nevypisuje se nic (můj současný stav, ke kterému jsem po úpravách dospěl :D - to mě mate úplně, při krokování vidím, že program normálně pře výpisy jede, jen nic nevypisuje)...
Moc dík za veškeré rady, tady už fakt nevím :D
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
const int cashes = 5;
const int customers = 10;
const int max_items = 10;
struct cus{ //zakaznik
int id;
int items;
cus *next;
};
struct queue{ //fronta
cus *head, *tail;
int size;
};
bool isEmpty(queue arr[]){ //kontrola pole, jestli je prazdne
for(int i = 0; i < cashes; ++i){
if(arr[i].size != 0){
return false;
}else{
return true;
}
}
}
void init(queue arr[]){ //inicializace pole na zacatku
for(int i = 0; i < cashes; ++i){
arr[i].head = arr[i].tail = NULL;
arr[i].size = 1;
}
}
int main(){
queue arr[cashes];
init(arr);
int total = 0; //poradi zakazniku
srand(time(NULL)); //pro urceni nahodneho cisla nakupu
while(isEmpty(arr) == false){
//generovani noveho zakaznika
if(total <= customers){
cus *newC = new cus; //novy zakaznik
newC->id = total;
newC->items = rand() % (max_items + 1);
cout << "G" << newC->id << "[" << newC->items << "]" << " ";
++total;
//urceni nejkratsi fronty a zarazeni zakaznika
int qMin = 0; //index nejkratsi fronty
int lMin = arr[0].size; //delka nejkratsi fronty
for(int i = 0; i < cashes; ++i){
if(lMin > arr[i].size){
lMin = arr[i].size;
qMin = i;
}
}
//zarazeni zakaznika na konec nejkratsi fronty
cus *next_assist = new cus;
if(arr[qMin].tail == NULL){
arr[qMin].tail = newC;
}else{
arr[qMin].tail->next = newC;
}
//overim, jestli je head NULL
if(arr[qMin].head == NULL){
arr[qMin].head = arr[qMin].tail;
arr[qMin].tail = NULL;
}
++arr[qMin].size; //zvetsim velikost pole +1
cout << "V" << newC->id << "[F" << qMin << "]" << " ";
}
//"odbaveni" zakaznika na pokladne
for(int i = 0; i < cashes; ++i){ //prochazim pokladny a hledam, jestli je na headu hodnota - zakaznik
if(arr[i].head != NULL){
--arr[i].head->items; //odstranim polozku z kosiku
if(arr[i].head->items >= 0){
cout << "K" << arr[i].head->id << "[" << arr[i].head->items << "] ";
}/*else{
cout << "K" << arr[i].head->id << "[0] ";
}*/
if((arr[i].head->items) == 0){
--arr[i].size;
cout << "O" << arr[i].head->id << "[F" << i << "]" << "[" << arr[i].size << "] ";
if (arr[i].head->next == NULL){
arr[i].head = arr[i].head->next;
}
}
}
}
}
return 0;
}
Opravdu nikdo neví? :D Trochu jsem to upravil a jsem ve stavu, že to probíhá, ale ne úplně - program skončí a neodbaví všechny zákazníky...
Ja momentalne nemam cas to studovat a neviem ci niekto na to najde cas, ale v prvom rade snad ked to je tvoj program tak mas v hlave nejaky koncept ze co v ktorej premennej je a pri krokovani si snad pozeras tie premenne ze ci je v nich to co ocakavas a zistujes v ktorej neni to co ocakavas a nasledne sa zameras na to jak sa tam ta neocakavana hodnota dostala (pri dalsom krokovani od zaciatku, samozrejme pouzivas breakpointy a nekrokujes cely program po jednom riadku)
Ked ani sam nevies co kde ma byt tak bud si to nepisal ty, alebo program bez hlavy a paty (konceptu) mozes zmazat a zacat nanovo s nejakym konceptom v hlave alebo na papieri.
BTW. mimochodom u simulacii sa pocita aj s nahodnymi javmi (zakaznik sa nahodne rozhodne ze nejde do fronty najkratsej lebo je na druhom konci obchodu a vobec na nu nevidi) apod., neviem do akej miery po vas chcu v zadani nahodne javy apod.
Inac v C++ by som cakal triedy a OOP, a ne ze si v main testujes ci head je null, to je predsa zalezitost triedy fronta, ktora ma poskytovat metody "pridaj_prvok", "vyhod_prvok", apod., a ktora bude odladena tak aby tam nenastavali problemy. Tym si zancne zjednodusis main ktory bude logicky a prehladny a nebude problem tam najst chybu, atd. To je zakladny vyznam OOP.
prvy bug
P.S. jaj to uz si opravil v tom prispevku, takze odteraz pozeram len to co si sem dal v tom prispevku, ne v dotaze
Jeden problem je v tomto
a to ten ze ak si mal predtym head uz nastaveny a tail bol NULL, a pridavas tam prvok tak urobis len
arr[qMin].tail = newC;
a nenstavis head->next = newC, ak head neni null.
Cele to pridavanie prvku je chaoticky navrhnute, logicky rozmyslajuci clovek to snad napise od hlavy k pate, t.j.:
A este toto je uplna hovadina
naco robis novy objekt pomocou new? A odkaz na neho si naveky prepises a teda ten novy objekt nikdy nezmazes? Testujes ze kedy ti dojde cela volna RAM? :)
A ten druhy riadok je tiez nezmysel, uvolnujes uplnu hovadinu. V head mas predsa pointer.
T.j. spravne ma byt
A este na zvysenie citatelnosti pouzivaj ++ a --, napr.
je
a stejna vec u arr[i].head->items = (arr[i].head->items - 1);
programator neni sekretarka, setri klavesy ;)))
A este jeden problem tam vidim, a to ten ze ak vytvaras prve prvky v prazdnej fronte alebo ak ich mazes, tak nikde nenastavujes ->next=NULL, to ale musis robit, inac tam budes mat nahodne alebo neplatne adresy a program ti crashne s exception (program proved neplatnou operaci) v urcitych situaciach. To sa mi uz nechce teraz osetrovat to si urob sam.
Kazda operacia s frontou musi nastavovat vsetky premenne prvkov fronty spravne (tie ktore sa menia samozrejme), za kazdych okolnosti aj ked je to uz posledny prvok atd, preto som aj pisal ze je lepsie ak je to extra v triede s privatnymi head a tail a next, a ked robis tu triedu tak sa sakramentsky zamyslis nad tym aby si inicializoval a spravne nastavil vsetko za kazdej situacie.
... aby si mal predstavu tak ti to napisem, pri pridavani prvku musis nastavit vzdy aj next u kazdeho aj u noveho prvku
- to sa dalo nastavit aj predtym raz ako newC->next=NULL, aby to tam potom nemuselo byt 3x :)
pri odstranovani tiez treba osetrit vsetky situacie
myslim ze som tym vystihol vsetky mozne siutuacie
Strašně moc díky, už mi to funguje Jinak, původní kód jsem psal s asistencí jednoho známého, protože ve škole se to tak nějak proletělo a pointery mi nebyly moc jasné... Jo a OOP se tu nesmí používat, fakt jenom struktury :D Jakmile bude pondělí, tak pokud to bude dobře, mrsknu tu celý kód, třeba to někomu pomůže
He? Uz mi je asi jasne odkial MS bere tolkych ludi co potom robia ten deravy OS. Asi studovali tiez tam :D
Ono OOP přijde, ale zatím byl jenom zmíněn na přednášce, takže musíme projekt dělat jen s pomocí struktur... No a pak to takhle dopadá :D
Ono sa to da urobit slusne aj so strukturami, mal si si urobit funkcie pridatprvok vymazatprvok tie by sa zaoberali len tou FIFO frontou t.j. len tymi 3 premennymi v strukture takze pri tvorbe tych fcii sa clovek moze zamerat len na tie 3 premenne v strukture a urobit tie 2 funkcie dokonale. Potom samozrejme vo vacsom/zlozitejsom programe by boli tie funkcie volane aj viackrat, preto su nakoniec v zlozitom programe tie funkcie aj nutne. Hlavny program by bol prehladny (malo riadkov - len volania funkcii) a citatelny.
Ono OOP trieda neni nic ine len sada struktur a funkcii, len je to v OOP trochu syntakticky (opticky) uhladenejsie aby to bolo lepsie a jednoduchsie citatelne.
Jo, tak to mě napadlo, až jsem měl napsanou většinu kódu a nechtělo se mi to měnit :D
Tak mě napadá, ty struktury newC a arr bych měl asi před returnem uvolnit pomocí delete, že? :D
Tak, tady je ten finální kód