1 / 9
May 2022

Mam mały problem z zadankiem: https://pl.spoj.com/WSDOCPP/problems/KOLEJKA/9
Napisałem nawet ciekawy kod z wykorzystaniem wskaźników i właśnie tutaj pojawił się problem. Testowałem go na ideone, zwraca prawidłowe wyniki ale tylko do ostatniego testu. Dodam, że na CodeBlocks wszystko hula, a na ideone pojawia się błąd “munmap_chunk(): invalid pointer”, albo “free(): invalid pointer”. Kod: https://ideone.com/Ytx0z110

  • created

    May '22
  • last reply

    May '22
  • 8

    replies

  • 472

    views

  • 2

    users

  • 6

    likes

  • 5

    links

Zobacz, co tu się dzieje:

int test,rozmiar;

Te zmienne są globalne, więc zostaną wyzerowane zanim program wystartuje

short* tablica=new short [test];
short* glowa=tablica;

Zaraz potem tworzysz tablicę na dane. Jaką wartość ma w tym momencie zmienna test? :arrow_up:

Potem Twój program odpala funkcję main. Jednak wczytanie wartości do zmiennej test nie już ma żadnego wpływu na utworzoną wcześniej tablicę. Czyli cały czas operujesz na tablicy o wiadomym rozmiarze :arrow_double_up:

Widzisz, gdzie jest problem?

Druga sprawa, to do czego potrzebujesz dwóch wskaźników tablica i glowa?

Dzięki za objaśnienie. Nie wiedziałem że zmiennym globalnym od razu są przypisywane zera, więc w sumie jasne jest, że ta dynamiczna tablica miała tak naprawdę zero elementów. Wskaźniki są mi potrzebne, by chociażby wyznaczyć “głowę” tej kolejki i jej “ogon” a potem długość w funkcji ‘size’. Jestem początkującym, więc pewnie dało by to radę zrobić to w prostszy sposób :smiley: Poprawiłem kod, tablice stworzyłem po wpisaniu już z klawiatury wartości “test”, a funkcjom “wysłałem” wartości potrzebnych argumentów. Kod dalej nie działa i taki sam rezultat: https://ideone.com/4lF1Qs1

Rezultat jest ten sam, bo najpierw tworzysz tablicę, zapisujesz jej adres w zmiennej tablica, a potem zmieniasz ten adres przez tablica++. Na koniec podajesz do skasowania adres, na którym akurat skończył się program. Skąd delete może wiedzieć, że chcesz skasować tablicę utworzoną na początku, skoro podajesz inny adres?

I już jest wszystko jasne. Zrozumiałem, że zmieniając adres pierwszego elementu tablicy “tablica” zmieniamy też jej cały adres, czyli takie “tablica++” nie wchodzi w grę, bo potem “delete [] tablica” wariuje. Kod poprawiony i tak wygląda: https://ideone.com/wOFXAr2

Ty nie zmieniasz adresu pierwszego elementu tablicy. To tak nie działa.
new tworzy tablicę w pamięci i zwraca jej adres. To tak jakbyś zbudował dom i zapisał jego adres na kartce.
tablica++ to nic innego, jak nadpisanie adresu na kartce na inny. Na kartce możesz napisać cokolwiek, dom pozostanie na swoim miejscy niezależnie od tego, co zrobisz.
Pod koniec programu, żeby zburzyć właściwy dom (delete), musisz pamiętać jego właściwy adres.

I jeszcze ciekawostka, jeśli w swoim programie skasujesz linię 9

wsk=wsk+*rozmiar;

to nadal będzie działać poprawnie. Zastanów się dlaczego

Faktycznie, po skasowaniu 9 linii program działa. Domyślam się, że dzieje się tak ponieważ w funkcji pop() nie operuje na oryginalnym adresie “wsk”, zatem to nie ma znaczenia jaką będzie miał wartość ten adres na końcu funkcji. Zmodyfikowałem też nieco wcześniejszy kod i wykorzystałem twoją radę. Zapisałem adres pierwszego elementu tablicy jeszcze przed pętlą for, a przed skasowaniem jej (delete) nadałem jej właściwy, czyli ten stary adres: https://ideone.com/N9Z0KG1
Zastanawiam się tylko, dlaczego zwróciłeś mi na początku uwagę, że używam dwóch wskaźników. Nie mam pomysłu jak można byłoby to zrobić inaczej.

Dokładnie tak

Drobna uwaga: wystarczyło napisać

delete [] adres

Ważny jest właściwy adres a nie zmienna, która go przechowuje.

A pytałem o dwa wskaźniki, żeby zwrócić uwagę na to, że tracisz adres tablicy. To podejście też powinno działać, o ile do kasowania podasz właściwy adres.

Dostałem już AC, więc wszystko jest jasne. Dzięki za poświęcenie uwagi :wink: