Dodawanie do listy jednokierunkowej

0

Cześć,
Mam problem z dodawaniem elementów do listy jednokierunkowej. Czy moglibyście spojrzeć na kod tych funkcji i spojrzeć co jest źle? Bo ja patrze od godziny i nie umiej do tego dojść.
Problem polega na tym, że wskaźnik na głowę listy przesuwa się z jakiegoś powodu na jej koniec. Próbowałem dodać wskaźnik na poprzedni element, ale niestety on wynosi NULL. Podejrzewam, że problem tkwi w funkcji listaPush albo w błędnym zarządzaniu elementami listy w pętli wczytującej dane z pliku.
Poniżej podrzucam kod:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct slowa {
  char *slowoPrzed;
  char *slowoPo;
  struct slowa *nast;
} Wezel;

Wezel *utworzWezel() {
  Wezel *nowy = (Wezel*)malloc(sizeof(Wezel));
  nowy->slowoPrzed = NULL;
  nowy->slowoPo = NULL;
  nowy->nast = NULL;
  return nowy;
}

Wezel *listaPush(Wezel **glowa, Wezel *wezel) {
  if (!(*glowa)) {
    glowa = &wezel;
    return (*glowa);
  } else {
    wezel->nast = (*glowa);
    glowa = &wezel;
    return (*glowa);
  }
}

Wezel *wczytajListeSlowZPliku(char *sciezka) {
  Wezel *listaSlow = NULL;
  Wezel *temp = NULL;
  FILE *plik = fopen(sciezka, "r");
  char bufor[512];
  if (!plik) {
    printf("Blad otwarcia pliku %s", sciezka);
    return NULL;
  }
  while (feof(plik) == 0) {
    if (fgets(bufor, 512, plik) == NULL) {
      printf("Blad wczytania linii z pliku %s", sciezka);
      return NULL;
    }
    temp = utworzWezel();
    temp->slowoPrzed = strtok(bufor, " ");
    temp->slowoPo = strtok(NULL, " ");
    listaSlow = listaPush(&listaSlow, temp);
  }
  fclose(plik);
  return listaSlow;
}

int main (int argc, char *argv[]) {
  Wezel *listaSlow = wczytajListeSlowZPliku("lista.txt");
  printf("%s, %s", listaSlow->slowoPrzed, listaSlow->slowoPo);

  return 0;
}
1

Twoim problemem jest całkowicie błędna implementacja listy jednokierunkowej.
W strukturze powinieneś mieć tylko przechowywaną wartość i następnik :)

0

Wprawdzie pisany w języku C++, ale sposób działania jest widoczny. Tak jak @dub.raf napisał w strukturze mam przechowywaną tylko wartość i wskaźnik na następny element.

template <class T>
class List {
public:
    List():
        first(nullptr),
        counter(0){}
    unsigned int size() const;
    void pushBack(T const &value);
    void erase (unsigned int where);
    T get(unsigned int position) const;
    void set(T value, unsigned int position);

private:
    struct item{
        T value;
        item *next;
        item():
            next(nullptr){}
    };
    item *first;
    unsigned int counter;
};

template <class T>
void List<T>::pushBack(T const &value)
{
    item *newItem = new item();
    newItem->value = value;

    if (!first)
        first = newItem;
    else
    {
        item *temp = first;
        while (temp->next)
            temp = temp->next;
        temp->next = newItem;
    }

    this->counter++;
}

template <class T>
T List<T>::get(unsigned int position) const
{
    if (position >= this->size())
        throw std::string("err:: get() position is out of range");
    item *temp = first;
    for (unsigned int i = 0; i<position; i++)
        temp = temp->next;

    return temp->value;
}
0

Nie rozumiem, czemu miałbym tą listę interpretować źle. Przecież nie każda lista musi przechowywać w sobie inta, prawda? Mogą to być, na przykład, 2 stringi... I wskaźnik na następny element. Równie dobrze mógłbym przechowywać tam pointer na strukturę danych w której będą 2 stringi oraz pointer na następny. Może doprecyzuje o co mi chodzi:
Dla danych w pliku "lista.txt": (program wczytuje każdą linię z tego pliku i zapisuje słowa w "wartościach" listy)
Gdzie Tu
Abc Def
Mam Wam
W tym printf w funkcji main SPODZIEWAŁBYM się takiego rezultatu (głowa faktycznie ustawiona na głowę):
Gdzie, Tu
A dostaje taki (głowa ustawiona na ostatni element listy):
Mam Wam

Kiedy przerobiłem tą listę na listę dwukierunkową i po prostu próbowałem się cofnąć wskaźnikiem po liście żeby wyświetlić dane, program wywala błąd dostępu do pamięci. Tak więc myślę, że problem polega na błędnym przepisywaniu wskaźników lub alokowaniu pamięci. Jednak ja nie potrafię go dostrzec.

0

Nie zrozumiałeś nas, zamknij sobie te słowoPrzed i SlowoPo w strukturę.
W takim razie nie możesz zmieniać wartości glowa, a ty ją zmieniasz za każdym razem kiedy wywołujesz push().

0

Bo jeśli dodajesz na początek (listaPush), to musisz przypisywać głowie aktualnie dodawany element, prawda? Więc muszę ja edytować, ale w konkretny sposób. Tak, zrozumiałem was, że chodzi o to, że powinienem mieć dane i wskaźnik na następny. Przepisze zaraz słowa w strukturę.

0

Nie moze byc coś takiego ?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct words {
	char word[30];
	struct words* next;
} Node;

Node* createNode() {
	Node* node = (Node*)malloc(sizeof(Node));
	node->next = NULL;
	return node;
}

Node* push(Node* head, Node* node) {

	if (head != NULL) {
		node->next = head;
	}
	head = node;
	return head;
}
void displayTheList(Node* head) {
	Node* temp = head;
	while (temp != NULL) {
		printf("%s ", temp->word);
		temp = temp->next;
	}
}
void cleanTheList(Node* head){
	Node* temp = head;
	while (temp != NULL) {
		temp = temp->next;
		free(head);
		head = temp;
	}
}
Node* enterWordsFromFile(char* path) {
	char bufor[512];
	char* clipboard;
	Node* listOfWords = NULL;
	Node* temp = NULL;
	FILE* file = fopen(path, "r");

	if (!file) {
		printf("Cannot open the file %s", path);
		return NULL;
	}
	while (feof(file) == 0) {
		if (fgets(bufor, 512, file) == NULL) {
			printf("Cannot read a line");
			return NULL;
		}

		clipboard = strtok(bufor, " ");

		while (clipboard != NULL)
		{
			temp = createNode();
			strcpy(temp->word, clipboard);
			listOfWords = push(listOfWords, temp);
			clipboard = strtok(NULL, " ");
		}
	}
	fclose(file);
	return listOfWords;
}

int main(int argc, char *argv[]) {
	Node* listOfWords = enterWordsFromFile("lista.txt");
	displayTheList(listOfWords);
	cleanTheList(listOfWords);
	system("pause");
	return 0;
}

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