MDK Temat założony przez niniejszego użytkownika |
Stos na wskaźnikach. Czy używać delete i jak to zrobić. » 2017-02-14 22:58:40 Napisałem sobie program stos i zastanawiam się, czy powinienem użyć funkcji delete przy usuwaniu elementu, a jeśli tak, jak to właściwie zrobić i po co. Chodzi mi o funkcję "pop". Czy jak nie usunę elementu, to on może wywołać jakąś ucieczkę pamięci, albo zawieszenie się czegoś? Poniżej wklejam kod - wszelkie dodatkowe rady też mile widziane. #include <iostream>
using namespace::std;
class poleSt { public: int wartosc = 0; int licznik = 0; poleSt * wsk = nullptr; };
poleSt * push( poleSt * wsk2, int & licznik2 ) { poleSt * wsk1; wsk1 = new poleSt; wsk1->licznik = ++licznik2; cout << "Podaj wartosc: " << endl; cin >> wsk1->wartosc; wsk1->wsk = wsk2; return wsk1; }
poleSt * pop( poleSt * wsk2 ) { if( wsk2 == nullptr ) { cout << "Brak elementow do usuniecia " << endl; } if( wsk2 != nullptr ) wsk2 = wsk2->wsk; return wsk2; }
void show( poleSt * wsk2 ) { do { if( wsk2 == nullptr ) { cout << "Brak elementow na stosie " << endl; break; } if( wsk2->wsk == nullptr ) { cout << "Pozycja: " << wsk2->licznik << " ma wartosc: " << wsk2->wartosc << endl; break; } cout << "Pozycja: " << wsk2->licznik << " ma wartosc: " << wsk2->wartosc << endl; wsk2 = wsk2->wsk; } while( wsk2->wsk != nullptr ); }
int main() { int licznikI = 0, wybor = 0; poleSt * wsk0; wsk0 = nullptr; do { cout << "Wybierz, co chcesz zrobic: " << endl; cout << " 1 - push, 2 - pop, 3 - pokaz, 4 - wyjdz " << endl; cin >> wybor; switch( wybor ) { case 1: wsk0 = push( wsk0, licznikI ); break; case 2: wsk0 = pop( wsk0 ); break; case 3: show( wsk0 ); break; case 4: cout << " Koniec " << endl; } } while( wybor != 4 ); return 0; }
|
|
mokrowski |
» 2017-02-15 04:14:41 Jeśli chodzi o delete to oczywiście że należy go użyć. Teraz w programie wycieka pamięć. W push(), masz także niezbyt faje odkładanie skutków ubocznych w licznik2. Funkcja coś zwraca ale jednocześnie zmienia argument bo jest przekazany przez referencję. W każdym węźle poleSt, odkładasz teraz nadmiarowo licznik a powinien być 1 dla całości stosu. |
|
MDK Temat założony przez niniejszego użytkownika |
» 2017-02-16 00:05:36 Dzięki za radę z licznikiem. Rzeczywiście, to było zupełnie bez sensu. Dodałem też delete. Poniżej wstawiam poprawiony kod i proszę o opinię, czy dobrze go zastosowałem. I czy nic więcej nie trzeba zrobić. #include <iostream>
using namespace::std;
class poleSt { public: int wartosc = 0; poleSt * wsk = nullptr; };
poleSt * push( poleSt * wsk2, int & licznik2 ) { poleSt * wsk1; wsk1 = new poleSt; licznik2++; cout << "Podaj wartosc: " << endl; cin >> wsk1->wartosc; wsk1->wsk = wsk2; return wsk1; }
poleSt * pop( poleSt * wsk2, int & licznik2 ) { if( wsk2 == nullptr ) { cout << "Brak elementow do usuniecia " << endl; } if( wsk2 != nullptr ) { delete wsk2; wsk2 = wsk2->wsk; licznik2--; } return wsk2; }
void show( poleSt * wsk2, int licznik2 ) { do { if( wsk2 == nullptr ) { cout << "Brak elementow na stosie " << endl; break; } if( wsk2->wsk == nullptr ) { cout << "Pozycja: " << licznik2 << " ma wartosc: " << wsk2->wartosc << endl; break; } cout << "Pozycja: " << licznik2 << " ma wartosc: " << wsk2->wartosc << endl; wsk2 = wsk2->wsk; licznik2--; } while( wsk2 != nullptr ); }
int main() { int licznikI = 0, wybor = 0; poleSt * wsk0; wsk0 = nullptr; do { cout << "Wybierz, co chcesz zrobic: " << endl; cout << " 1 - push, 2 - pop, 3 - pokaz, 4 - wyjdz " << endl; cin >> wybor; switch( wybor ) { case 1: wsk0 = push( wsk0, licznikI ); break; case 2: wsk0 = pop( wsk0, licznikI ); break; case 3: show( wsk0, licznikI ); break; case 4: cout << " Koniec " << endl; } } while( wybor != 4 ); return 0; }
|
|
mokrowski |
» 2017-02-16 11:55:33 Ok, pamięć Ci już nie cieknie ale... Przeczytaj jeszcze raz kod... if( wsk2 != nullptr ) { delete wsk2; wsk2 = wsk2->wsk; licznik2--;
Widać gołym okiem że najpierw dealokujesz (delete) pamięć pod wskaźnikiem wsk2 a linijkę później go używasz! Na nieszczęście często to działa ale to duży błąd! ... i zacytuję jeszcze komunikat narzędzia cppcheck które informuje że ... Checking x.cpp ... [x.cpp:27]: (error) Dereferencing 'wsk2' after it is deallocated / released [x.cpp:30]: (error) Returning/dereferencing 'wsk2' after it is deallocated / released
Interesuje Cię zapamiętanie wsk2->wsk w zmiennej tymczasowej, usunięcie (delete) wsk2, przypisanie do wsk2 wartości zmiennej tymczasowej. |
|
MDK Temat założony przez niniejszego użytkownika |
» 2017-02-16 18:05:00 Chyba powinno być dobrze. Tylko zastawiam się, czy powinienem też używać delete na wskaźniku tymczasowym (w poniższym kodzie używam), który utworzyłem. W końcu dostaje on adres obiektu stworzonego dynamicznie. #include <iostream>
using namespace::std;
class poleSt { public: int wartosc = 0; poleSt * wsk = nullptr; };
poleSt * push( poleSt * wsk2, int & licznik2 ) { poleSt * wsk1; wsk1 = new poleSt; licznik2++; cout << "Podaj wartosc: " << endl; cin >> wsk1->wartosc; wsk1->wsk = wsk2; return wsk1; }
poleSt * pop( poleSt * wsk2, int & licznik2 ) { if( wsk2 == nullptr ) { cout << "Brak elementow do usuniecia " << endl; } if( wsk2 != nullptr ) { poleSt * wskTymczasowy; wskTymczasowy = wsk2->wsk; delete wsk2; wsk2 = wskTymczasowy; delete wskTymczasowy; licznik2--; } return wsk2; }
void show( poleSt * wsk2, int licznik2 ) { do { if( wsk2 == nullptr ) { cout << "Brak elementow na stosie " << endl; break; } if( wsk2->wsk == nullptr ) { cout << "Pozycja: " << licznik2 << " ma wartosc: " << wsk2->wartosc << endl; break; } cout << "Pozycja: " << licznik2 << " ma wartosc: " << wsk2->wartosc << endl; wsk2 = wsk2->wsk; licznik2--; } while( wsk2 != nullptr ); }
int main() { int licznikI = 0, wybor = 0; poleSt * wsk0; wsk0 = nullptr; do { cout << "Wybierz, co chcesz zrobic: " << endl; cout << " 1 - push, 2 - pop, 3 - pokaz, 4 - wyjdz " << endl; cin >> wybor; switch( wybor ) { case 1: wsk0 = push( wsk0, licznikI ); break; case 2: wsk0 = pop( wsk0, licznikI ); break; case 3: show( wsk0, licznikI ); break; case 4: cout << " Koniec " << endl; } } while( wybor != 4 ); return 0; }
|
|
mokrowski |
» 2017-02-16 18:49:38 Oczywiście że nie. To w jaki sposób został zaalokowany ten wskaźnik to jedno. Drugie to czy ma tam być usuwany czy nie. W tym przypadku nie. Zostawiam komentarz. Linijka z komentarzem ma być usunięta. if( wsk2 != nullptr ) { poleSt * wskTymczasowy; wskTymczasowy = wsk2->wsk; delete wsk2; wsk2 = wskTymczasowy; licznik2--; }
|
|
MDK Temat założony przez niniejszego użytkownika |
» 2017-02-16 19:21:41 Dzięki za pomoc, dużo mi to dało. P.S. Mam jeszcze jedno pytanie. Czy przed zamknięciem programu, jak mam jakieś elementy na stosie, to muszę też je usunąć za pomocą delete? |
|
« 1 » |