Błąd podczas zwalniania elementu z listy w C

0

Witam, niedawno zacząłem używać deklaracji wskaźnik na wskaźnik żeby trochę ułatwić sobie życie, ale niestety tak do końca się nie stało.
Mój problem polega na tym że gdy chcę zwolnić jakiś wskazany element przez użytkownika to wywala mi błąd w visualu, chociaż po pomięciu go, program wykonuje poprawnie usunięcie(po wydrukowaniu listy nie ma już tego elementu który miał zostać usunięty ).

Tutaj prezentuje kod dla akurat dla listy jednokierunkowej cyklicznej ale to objawia się też w innych moich programach:


typedef struct lista
{
	int dane;
	struct lista *nast;
};

typedef struct lista *point;

void usun_1(point *lista, int liczba)
{
	int pomoc;
	point p = *lista,usun=NULL;
	if (p)
	{
		do
		{
			if (p->dane == liczba)
			{
				p->dane = p->nast->dane;
				p->nast->dane = liczba;
				usun = p->nast;
				p->nast = p->nast->nast;
				free(usun);
				return;
			}
			else
			p = p->nast;
		} while (p != (*lista));
	}
	printf("Nie znaleziono elementu do usuniecia\n");
}

 

Sam błąd wygląda następująco
zd.jpg
i break point pojawia się przy linii free(usun).

Czy ktoś jest mi w stanie odpowiedzieć dlaczego taki błąd występuje ?

0

Pokaż jak tworzysz tę listę.

po pomięciu go, program wykonuje poprawnie usunięcie(po wydrukowaniu listy nie ma już tego elementu który miał zostać usunięty
Po pominięciu masz wyciek pamięci, a wydruk listy wygląda poprawnie bo lista już nie ma dostępu do tego elementu.

Szczerze powiedziawszy to nie wiem jak to może działać, bo to wygląda mocno podejrzanie:

point p = *lista
...
do {
...
} while (p != (*lista))

Edit: nie zauważyłem, że lista jest cykliczna. W tym przypadku już jest mniej podejrzanie.

0

Czyli jezeli zwalniam pamiec p to nie oznacza to ze jednoczesnie zwalniam pamiec tej listy *lista ?
#twontek petla dziala dobrze bo przed dojsciem do while zostaje juz przesunieta lista o jedna pozycje i sam program ma dzialac dopoki nie dojdzie z powrotem do 1 elementu ( czyli poczatku listy 1 cyklicznej).
Moglby ktos mi podpowiwdziec / opisac jak zwalniac jakis element z listy nie zmieniajac kolejnosci tej listy ( bo jakbym operowal na *lista to drukowana by byla od tego elementu ktory zostal zwolniony)

0

Lista jest tworzona w taki sposob ze zawsze nowy element jest dodawany na poczatek listy ( tzn zawsze bedzie tym elementem pierwszym i elementem na ktory wskazuje pole nast ostatniego elementu, na razie nie mam dostepu do komputera kod moge wstawic po 16 ) funkcja void otrzymujaca point *lista.

2
lupek123 napisał(a):

... zacząłem używać deklaracji wskaźnik na wskaźnik żeby trochę ułatwić sobie życie ...
I właśnie na tym poległeś.

  1. Nie obsługujesz sytuacji kiedy usunięty element jest ostatnim.
  2. Jeżeli wewnątrz na końcu if'a masz return to else jest niepotrzebny.
  3. Wywal wszelkie printf'y z funkcji, niech zwraca int 1 - usunięto; 0 - nie usunięto
0

Myślałem że może taki zabieg coś pomoże ale niestety jest to samo:


void usun_1(point *lista, int liczba)
{
	int pomoc;
	point p = *lista,usun=NULL;
	if (p)
	{
		do
		{
			if ((*lista)->dane == liczba)
			{
				(*lista)->dane = (*lista)->nast->dane;
				(*lista)->nast->dane = liczba;
				usun = (*lista)->nast;
				(*lista)->nast = (*lista)->nast->nast;
				free(usun);
				*lista = p;
				return;
			}
			else
			*lista = (*lista)->nast;
		} while ((*lista)!=p);
	}
	printf("Nie znaleziono elementu do usuniecia\n");
}

 

tak wygląda funkcja która dodaje elementy


void dodaj_do_1(point *lista, int dane)
{
	int pomoc;
	point nowy,head=*lista;
	nowy = malloc(sizeof(point));
	nowy->dane = dane;
	nowy->nast = nowy;
	if (head == 0) *lista = nowy;
	else
	{
		nowy->nast = (*lista)->nast;
		(*lista)->nast = nowy;
		pomoc = (*lista)->dane;
		nowy->dane = pomoc;
		(*lista)->dane = dane;
	}
}
 

Proszę o pomoc bo muszę jeszcze wykonać jedno zadanie które nie obejdzie się bez użycia wskaźnika na wskaźnik( muszę zmienić dwa zadane parametry w jednej funkcji)

1
nowy = malloc(sizeof(point));

Rozmiar struktury to nie to samo co rozmiar wskaźnika.

0

Tyle męki przez takie coś ... Dziękuje za wszystkie odpowiedzi działa jak należy :)

#edit wiem wiem oczywiście zrobiłem zmiany i funkcja działa poprawnie, mam jeszcze problem inny :d gdy dochodzę do końca listy jednokierunkowej zwykłej i chcę zwolnić ten ostatni element sekwencją

free(*lista);
*lista=0;
 

to przy późniejszym wypisywaniu w miejsce ostatniego elementu pojawią się jakieś dziwne liczby jakby tam jednak nie została zwolniona pamięć...

0

Standardowa odpowiedź: - podaj kod lub idź do wróżbitów.

0

void dodaj(point *s, int x)
{
	point q = malloc(sizeof(struct el));
	q->dane = x;
	q->nast = *s;
	*s = q;
}



void drukl(point s)
{
	if (s == NULL) return;
	else
	{
		while (s)
		{
			printf("%d\n", s->dane);
			s = s->nast;
		}
	}
}


void usuwanie_powt(point *l1, point *l2)
{
	int pomoc, u = 1;
	point h1 = *l1, h2 = *l2, usun = NULL,p1=*l1;
	
	while (p1)
	{
		while ((*l2))
		{
			if ((*l1)->dane == (*l2)->dane)
			{
				if ((*l2)->nast)
				{
					(*l2)->dane = (*l2)->nast->dane;
					(*l2)->nast->dane = (*l1)->dane;
					usun = (*l2)->nast;
					(*l2)->nast = (*l2)->nast->nast;
					free(usun);
					u = 1;
				}
				else
				{
					free(*l2);
					*l2 = 0;
					u = 1;
				}
			}
			else
			{
				*l2 = (*l2)->nast;
			}
		}
		*l2 = h2;
		p1 = p1->nast;
	}
} 

Lista nr 1 ma tylko jedno pole ( np 1) a druga lista np trzy pola( 1 2 1) i po wyswietleniu drugiej listy dostaje (2 -2151costam).

0

Usuwasz ostatni element, ale ten poprzedni nadal ma wskaźnik, który wskazuje na ten obszar pamięci. Musisz również nullować nast w przedostatnim elemencie.

0

Jakąś podpowiedź jak to najlepiej zrobić ? Tzn chodzi mi o to że przeglądam sobie jakąś tam liste i chcę usunąć np same dwójki. Jak to najlepiej zapisać ?

1

Sprawdzaj wartość elementu następnego zamiast obecnego. Usuwanie elementu następnego jest proste. Jedyny kłopot to początek listy, ale możesz doczepić atrapę, która wskazuje na głowę, a pętla się zaczyna od atrapy.

point atrapa = ...
atrapa->nast = glowa;     // nazwij zmienne sensownie, a nie l1 l2 h1 h2

point obecny = atrapa;
while (obecny->nast)
{
    if (obecny->nast->dane == ...
}
1

Takie małe skrócenie funkcji:

void drukl(point s)
{
   for(;s;s=s->nast) printf("%d\n", s->dane);
}

Wydawało mi się że masz listę cykliczną, bo dla cyklicznej ani twoja wersja drukl ani ta powyższa nie będą działać poprawnie.

0

Na poczatku byla lista cykliczna ale tam nie mam problemu ze zwolnieniem ostatniego elementu , problem mam ze zwykla lista ale dobra przeanalizuje jutro ten wariant z ,, atrapa"

0

Działa :)
Samo usuwanie realizuje w ten sposób

				usun = obecny->nast;
				obecny->nast = obecny->nast->nast;
				free(usun); 

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