FIFO, bufor cykliczny

0

Witam,

Mam oto taki sobie kodzik:

#include <iostream>

using namespace std;
class Kolejka {
public:
    void create();
    void put(int k);
    int get();
    bool notempty();
    void clear();
    Kolejka();
    void increase();
private:
    int n;
    int *tab;
    int start;
    int end;
    int temp;
};

Kolejka::Kolejka(){
    n = 5;
    temp = 0;
    tab = new int[n];
}

bool Kolejka::notempty(){
    return end!=start;
}

void Kolejka::create(){
    start = 0;
    end = 0;
    int zadanie;
    int liczba;
    do{
        cout << "Wybierz zadanie: " << endl;
        cout << "1. Dodaj liczbe do kolejki" << endl;
        cout << "2. Zdejmij pierwszy element z kolejki" << endl;
        cout << "3. Wyczysz kolejke" << endl;
        cout << "0. Zakoncz program" << endl;
        cin >> zadanie;
        switch(zadanie){    
            case 0: cout << "Nastepuje zamkniecie programu" << endl; break;
            case 1: cout << "Podaj liczbe, ktora chcesz dodac do kolejki: "; 
                cin >> liczba;
                put(liczba);
                break;
            case 2: 
                if(notempty()){
                    cout << "Zdjety element: " << get() << endl;
                }
                else{
                    cout << "Brak elementow! Kolejka pusta" << endl;    
                }
                break;
            case 3: clear(); break;
        }
    } while(zadanie);
}

void Kolejka::clear(){
    for(int i=0; i<n; i++){
        tab[i] = 0;
    }
    start = 0;
    end = 0;
}

void Kolejka::put(int k){
    tab[end] = k;
    if((end+1)%n == start){ cout << "powiekszam";  increase();}    // powiekszanie tablicy o 10
    end = (end+1)%n;
}

int Kolejka::get(){
    if(notempty()){
        temp = tab[start];
        //tab[start]=0;
        start = (start+1)%n;
        return temp;    
    }
    else return 0;
}

void Kolejka::increase(){
    int *tempTab = new int[n+10];
    for(int i=0; i<n;i++){
        tempTab[i] = tab[i];
    }
    n = n + 10;
    delete [] tab;
    tab = tempTab;
    delete [] tempTab;
}

int main(){
    Kolejka* FIFO = new Kolejka();
    FIFO->create();



    system("PAUSE");
    return 0;
}

Program ma na celu utworzenie tablicy jednowymiarowej, początkowo o wielkości 5. Zmienna start to wskaznik poczatku bloku danych, end - koniec. Metoda put() odpowiada za wstawienie do kolejki w odpowiednim miejscu (http://en.wikipedia.org/wiki/Circular_buffer) elementu typu int, która jest parametrem tej metody. Zawsze pozostaje jedno miejsce wolne w tablicy, aby nie dopuścić do sytuacji, w której nie będzie można rozpoznać czy bufor jest pusty czy pełny (start = end w obu przypadkach). Jeśli zostaje już tylko to jedno miejsce wolne to tablica zostaje powiększona (odpowiada za to metoda increase() wywoływana w funkcji put() pod warunkiem (end+1)%n == start. Co do poprawnosci metody increase() wlasnie nie mam pewnosci czy jest dobrze wykonana. Ma ona stworzyc nowa tymczasowa tablice wieksza od poprzedniej o 10, skopiowac do niej wszystkie wartosci ze starej tablicy, skasowac stara tablice i utworzyc nowa o powiekszonym rozmiarze i ponownie skopiowac dane, tylko ze tym razem z tymczasowej do tej "nowej" a na koncu usunac tymczasowa. get() pobiera pierwszy element w buforze (jako że FIFO -> first in first out).

Program kompiluje sie poprawnie, jednak gdy dodaje wieksza liczbe elementow do buforu to program sie wykrzacza. Nie moge odnalezc w debbugerze zadnych informacji, ktore naprowadzilyby mnie na trop gdzie jest blad. Czasami dzieje sie to przy dodaniu 14 elementu, czasami 23, ale tylko i wylacznie przy dodawaniu liczby do kolejki.

Mam nadzieje, ze wypowiedzialem sie dosyc jasno i przejrzyscie :) Pisze w Visual C++ 2008. Bylbym wdzieczny gdyby ktos skopiowal ten kod zrodlowy, odpalil u siebie i pomogl mi odnalezc i naprawic blad ;)

Dodam, ze dopiero zaczynam swoja zabawe w programowaniu obiektowym.

Pozdrawiam

0

Wykrzacza się pewnie dlatego, że po utworzeniu nowej większej tablicy i skopiowaniu elementów usuwasz tą tablicę.

0

Ja bym rozdzielił tą Kolejkę na 2 części:
Kolejka -> klasa odpowiedzialna za kolejkę
Węzeł -> klasa odpowiedzialna za jeden węzeł

0

Jak więc zrobić prawidłowe powiększanie tablicy?

Shalom co rozumiesz pod pojęciem węzeł w tym przypadku?

0
gosciuuuu2323 napisał(a)

Jak więc zrobić prawidłowe powiększanie tablicy?

Nie usuwaj nowo stworzonej tablicy w metodzie increase

0

Tak wygląda teraz metoda increase()

void Kolejka::increase(){
	int *tempTab = new int[n+10];
	for(int i=0; i<n;i++){
		tempTab[i] = tab[i];
	}
	n = n + 10;
	//delete [] tab;
	tab = new int[n+10];
	for(int i=0; i<n;i++){
		tab[i] = tempTab[i];
	}
	delete [] tempTab;
}

I wydaje się, że działa. Teraz moje pytanie brzmi - czy kopiowanie danych z jednej tablicy do drugiej musi być zrobiona tak jak powyżej czyli w pętli i każdą komórkę po kolei kopiuje czy można zrobić coś w tym stylu:

tab = tempTab

, kiedy tab i tempTab są tego samego rozmiaru?</cpp>

0

Ech zepsułeś jeszcze bardziej... Najpierw tworzysz tablicę o rozmiarze n+10 i kopiujesz do niej n elementów z tablicy tab. Potem zwiększasz wartość n o 10 i tworzysz tablicę o rozmiarze n+10 (czyli de facto powiększasz ją o 20 elementów). Potem kopiujesz z tempTab n (które już jest powiększone o 10) elementów na do tablicy na którą pokazuje tab, 10 ostatnich elementów to będą jakieś śmieci.

...a wystarczyło z pierwotnej wersji funkcji usunąć linijkę delete [] tempTab;

Poczytaj o wskaźnikach i tablicach dynamicznych to się dowiesz co robi takie przypisanie:
wskaźnik1 = wskaźnik2;
i nie, to nie skopiuje tablicy

0

Trochę chyba nie rozumiesz moich zamiarów.

Najpierw tworzę tymczasową tablicę większą o 10 od poprzedniej. n pozostaje niezmienione. Nastepnie kopiuje zawartosc starej tablicy do nowej (koncowe 10 elementow nowej tablicy to owszem beda smieci, ale ja sie tym nie przejmuje). Dopiero wtedy powiekszam n o 10 i tworze "nową starą" tablice o rozmiarze identycznym do tej tymczasowej i kopiuje do niej dane.

Napisałeś, że wystarczyło usunać z pierwotnego kodu ta linijke:

    delete [] tempTab;

,jednak to problemu nie rozwiazalo i znow program sie wykrzaczal.

Teraz zmiksowalem troche tego co Ty mi powiedziales i tego co zrobilem w mojej drugiej wersji i wyszlo cos takiego i to dziala:

void Kolejka::increase(){
	int *tempTab = new int[n+10];
    for(int i=0; i<n;i++){
        tempTab[i] = tab[i];
    }
    n = n + 10;
	tab = new int[n+10];
    for(int i=0; i<n;i++){
        tab[i] = tempTab[i];
    }
}

Sprawdzałem na pętli, w ktorej milion razy powtorzylem wywolanie metody put(losowa wartosc). Poprzednia wersja rowniez ten test przeszla

0

po co kopiujesz dwa razy? do czego ci ta tablica tymczasowa? którą tworzysz a nie niszczysz, poprzedniej tablicy też nie niszczysz, pamięć ci cieknie...

0

Byku - co do powiększania o 20 to zwracam honor, przez moją nieuwagę tak było.

Azarien - sugerujesz, że można powiększyć tablicę nie tworząć żadnej tymczasowej?

void Kolejka::increase(){
	int *tempTab = new int[n+10];
    for(int i=0; i<n;i++){
        tempTab[i] = tab[i];
    }
    n = n + 10;

	delete [] tab;

	tab = new int[n];
    for(int i=0; i<n;i++){
        tab[i] = tempTab[i];
    }

	delete [] tempTab;
}

Czy to według Ciebie jest ok? Również to działa.

0

Nie tyle nie tworząc tymczasowej, co tworząc nową, a starą usuwając po przekopiowaniu elementów.

void Kolejka::increase()
{
    int *tempTab = new int[n+10];

    for(int i = 0; i < n; i++)
        tempTab[i] = tab[i];

    delete [] tab;

    tab = tempTab;
    n += 10;
}
0

Kolejne pytanie :(

Teraz chcę napisać ten program proceduralnie i mam problem z funkcją increase().

void increase(int& n, int* tab){
	int *tempTab;
	tempTab = new int[n];

    for(int i=0; i<n;i++){
        tempTab[i] = tab[i]+5;
    }
    
	delete [] tab;
    
	tab = new int[n+10];
	for(int i=0; i<n;i++){
        tab[i] = tempTab[i];
    }

	delete [] tempTab;

	n = n + 10;
}

Wygląda analogicznie tak jak wcześniej, jednak tutaj jako argument funkcji użyty jest wskaźnik tab, który później usuwam i tworzę nowy o tej samej nazwie i przypisuje mu nową, zwiększoną tablice, jednak później nie wydostaje się on już jakby do funkcji main(), nie wiem jak to nazwać. Po prostu jest on tworzony tylko lokalnie w tej funkcji i nie jest przekazywany dalej. A chciałbym, żeby tak się stało :) Szukałem trochę na zagranicznych stronach podobnego problemu, ale nic konkretnego nie znalazłem.
PS. Prosze nie czepiac sie o slownictwo, nie jestem teoretykiem, a praktykiem i wole uczyc sie z przykladow niz z suchego tekstu, totez nie potrafie wytlumaczyc fachowo czym jest np wskaznik, a czym... zreszta nvm.

0

Byku już rozumiem co miałeś na myśli, moja wersja też nie była zła, ale zdecydowanie bardziej optymalna jest Twoja, to fakt ;)

0

Poczytaj o przekazywaniu do funkcji argumentów przez wartość, wskaźnik, referencję. W tym wypadku przekazujesz przez wartość.
Jednak dobrze by było jakbyś jednak poczytał o wskaźnikach. Nie wiem czemu, ale wiele ludzi ma problemy z nimi ;)

/spróbuj int **tab albo int &*tab

0

Czytałem o przekazywaniu do funkcji i zwracaniu przez nią argumentów, ale nie znalazłem niczego co mogłoby mi pomóc ;/

To co dodałeś na dole to (**tab) to wskaźnik do wskaźnika tak?

0

A co do kiepskiego ogarnięcia przeze mnie wskaźników - najpierw bawiłem się w php, potem w szkole narzucili mi Pythona, na pierwszym roku studiow mialem Jave, a teraz mam C++. Proces odzwyczajania trwa u mnie dosc dlugo :)

0
gosciuuuu2323 napisał(a)

Czytałem o przekazywaniu do funkcji i zwracaniu przez nią argumentów, ale nie znalazłem niczego co mogłoby mi pomóc ;/

To co dodałeś na dole to (**tab) to wskaźnik do wskaźnika tak?

Tak.

Bez bdb ogarnięcia wskaźników z c++ będzie bardzo ciężko

0

Mógłbyś przytoczyć jakiś przykład jak powinno się coś takiego wykonywać?

0

Np. właśnie po to, żeby przekazać wskaźnik do funkcji przez wskaźnik - dzięki temu w funkcji operujesz na oryginalnym wskaźniku, a nie jego kopii, więc możesz zmieniać adres na który pokazuje i ta zmiana będzie widoczna poza funkcją.

//IMHO bez książki się nie obędzie

0

Rozumiem ideę, na zwykłych zmiennych nawet to ogarnąłem, ale nie mam pojęcia jak to wykonać w przypadku tablicy (która jest jednocześnie wskaźnikiem, musze się do tego przyzwyczaić :))

0

Azarien - sugerujesz, że można powiększyć tablicę nie tworząć żadnej tymczasowej?

Tworzysz nową, kopiujesz dane, niszczysz starą – i już.
A ty tworzyłeś nową, kopiowałeś dane, tworzyłeś jeszcze jedną i kopiowałeś dane drugi raz. Zupełnie niepotrzebnie.

0

Podpowie ktoś jak poradzić sobie z moim problemem? Chodzi mi o konkretny kod, nie potrafię wykonać poprawnej operacji ustawienia i operowania na wskaźniku do wskaźnika (tablicy), w przypadku zmiennej to potrafię.

0
void increase(int& n, int** tab)
{
    int *tempTab;
    tempTab = new int[n];

    for(int i = 0; i < n; i++)
        tempTab[i] = (*tab)[i];
   
    delete [] (*tab);   
    (*tab) = tempTab;
    n += 10;
}

wystarczy odpowiednio użyć operator wyłuskania (*)

0

Dzięki wielkie kolego!

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