Forum: PC-Programmierung Elemente in einfache verkettete Liste speichern


von Johannes M. (Gast)


Lesenswert?

Hallo!

Ich hab ein Problem, hinter welches ich einfach nicht komm, obwohl's 
wahrscheinlich sehr einfach zu lösen ist.

Und zwar lese ich aus einer Binärdatei Datensätze aus (haben alle 
bestimmte Form aus Header und beliebig langen Content).

Nun schaffe ich es nicht, dass ich, nachdem ich einen Datensatz in das 
1. Listenelement gespeichert habe, auf das nächste Listenelement zu 
springen.

Wenn ich am Ende der While-Schleife, die zum Einlesen eines Datensatzes 
dient, folgendes schreibe:
1
 first_element_of_list = first_element_of_list->next;

dann bekomme ich jedes Mal einen Segmentation Fault -_-

Wie macht man das, dass man nach dem fertigen Hineinspeichern in das 1. 
Element auf das nächste springt?

von Zerf (Gast)


Lesenswert?

Such mal mit dem Debugger die Stelle, an der der Segfault auftritt. Dann 
geht Dir sicher ein Licht auf.

von Johannes M. (Gast)


Lesenswert?

So sieht mein Struct aus, das sollte so passen.

Im Programm mach ich jetzt 3 mal fread, einmal für den immer gleich 
großen Header, und zweimal für die beiden variabel langen strings.

1
typedef struct _Header_
2
{
3
  unsigned int identifier;
4
  double latitude;
5
  double longitude;
6
  unsigned int content_length;
7
}
8
Header;
9
10
typedef struct _Content_
11
{
12
  char *place_name;
13
  char *description;
14
}
15
Content;
16
17
typedef struct _List_
18
{
19
  struct _List_ *next;
20
  Header header;
21
  Content content;
22
}
23
List;

so im Programm unterhalb definiere ich dann in der Einlesefunktion die 
Liste.
1
List *first_element_of_single_linked_list;
2
3
while(...)
4
{
5
.... malloc, fread bla bla bla
6
7
?!? first_element_of_single_linked_list = first_element_of_single_linked_list->next;
8
}

dann mach ich halt die mallocs für den Header, und die beiden Strings 
und lies nach jedem malloc ein.

Zerf schrieb:
> Such mal mit dem Debugger die Stelle, an der der Segfault auftritt. Dann
> geht Dir sicher ein Licht auf.

Wies weiter geht, das weiß ich nicht bzw. schaffe ich es nicht, das 
herauszufinden, das kann doch kein Problem sein für euch, bitte helft 
mir!

von Noname (Gast)


Lesenswert?

>.... malloc, fread bla bla bla

ist doch ein bisschen lakonisch und bei der Aufzählung

>dann mach ich halt die mallocs für den Header, und die beiden Strings

vermisse ich das malloc für das Listenelement selbst.
Ich sehe hier bloss Zeiger.

Zeig mal den kompletten Code. Reduziere ihn auf das Notwendigste, so das 
der Fehler noch auftritt.

>Wies weiter geht, das weiß ich nicht bzw. schaffe ich es nicht, das
>herauszufinden, das kann doch kein Problem sein für euch, bitte helft
>mir!
Ist langfristig sowieso keine Lösung. Du kannst ja nicht jedesmal wenn 
ein Problem auftritt sagen: "Ich kann keinen Debugger bedienen, da frag 
ich in mikrocontroller.net".

von Zerf (Gast)


Lesenswert?

...nimm den Debugger, kämpf Dich bis zum Segfault und schau Dir die 
Pointer (also deren "Wert") an. Was willst du mit 
"first_element_of_single_linked_list = 
first_element_of_single_linked_list->next;" erreichen?

von Johannes M. (Gast)


Lesenswert?

Zerf schrieb:
> Was willst du mit
> "first_element_of_single_linked_list =
> first_element_of_single_linked_list->next;" erreichen?

Ich will damit nach dem Einlesen eines Binärfile-Datensatzes auf das 
nächste Element der Liste springen.
Ich weiß eben nicht, ob ich, wenn ich im nächsten Schleifendurchlauf bin 
und dort wieder ein malloc(sizeof(List)) mache, ob ich ohne die 
Codezeile von oben dann im nächsten Feld der Liste bin oder den 
vorherigen Eintrag überspeichere oder ins 1. Element der Liste noch 
einen zweiten Datensatz hineinspeichere.

von Zerf (Gast)


Lesenswert?

Erklär mal genauer. Woher kommt das neue Element?

von Vlad T. (vlad_tepesch)


Lesenswert?

warum tut man sich sowas freiwillig auf dem PC an?
nimm doch c++ und eine std::list

von Noname (Gast)


Lesenswert?

Ich möchte Dir ernsthaft empfehlen hier den vollständigen Code zu 
zeigen. Deine Erklärungen sind unklar, wozu nicht unwesentlich die 
Identifizierung Deiner Person mit dem Programm und mit Variablen 
beiträgt.

Reduziere ihn auf das zum traversieren der Liste und hinzufügen von 
Elementen notwendige ohne das Einlesen der Strings. Das hinzufügen muss 
auch ohne das funktionieren.

von Johannes M. (Gast)


Lesenswert?

1
List *readInput(char *name_of_file, int *error_code,
2
  int *number_of_entries)
3
{
4
  FILE *input_file;
5
  char *whole_content_string = NULL;
6
  List *list;
7
  int end;
8
  int counted_content_length = 0;
9
  int array_index_place_name = 0;
10
   array_index_description = 0;
11
  int end_of_word = 0;
12
  int entry_counter = 0;
13
  
14
  *error_code = allocateListMemory(&first_element_of_single_linked_list);
15
  *error_code = openFile(&input_file, name_of_file, "rb");
16
 
17
  do
18
  {
19
   fread(&(first_element_of_single_linked_list->header), sizeof(Header),
20
      1, input_file))    
21
    
22
   whole_content_string = malloc(sizeof(char) * 
23
      first_element_of_single_linked_list->header.content_length);
24
    
25
   fread(whole_content_string, list->header.content_length, 1, input_file);
26
27
    while(whole_content_string[counted_content_length] != '\0')
28
    {
29
      counted_content_length++;
30
    }
31
    
32
    end_of_Word = counted_content_length;
33
    counted_content_length++;
34
    
35
   list->content.place_name =  malloc(sizeof(char) * (end_of_Word + 1));
36
    
37
    for(array_index_place_name = 0; array_index_place_name < end_of_Word; array_index_place_name++)
38
    {
39
    list->content.place_name[array_index_place_name] = whole_content_string[array_index_place_name];
40
    }
41
    list->content.place_name[array_index_place_name] = '\0';
42
    
43
    while(whole_content_string[counted_content_length] != '\0')
44
    {
45
      counted_content_length++;
46
    }
47
    
48
    list->content.description = malloc(sizeof(char) * (counted_content_length - end_of_Word + 1));;
49
  
50
    array_index_place_name = end_of_word;
51
52
    for(array_index_description = 0; array_index_description <= (counted_content_length - (array_index_place_name + 1)); array_index_description++)
53
    {
54
      list->content.description[array_index_description] = whole_content_string[(end_of_Word + 1)];
55
      end_of_Word++;
56
    }
57
    free(whole_content_string); 
58
    counted_content_length = 0;
59
60
    entry_counter++;
61
  }
62
  while(ftell(input_file) != end);
63
}

von Zerf (Gast)


Lesenswert?

Wo findet man in dem Code die Zeile aus Deinem ersten Beitrag?

von Johannes M. (Gast)


Lesenswert?

Die sollte ganz unten vor dem Ende der do/while, nur wie schon jetz sehr 
oft von mir gesagt, ich weiß nicht, ob man die braucht. Diese Funktion 
liest Element für Element ein, aber speichert sie diese auch 
nacheinander in die Liste? Das will ich beantwortet haben!

von Johannes M. (Gast)


Lesenswert?

aja, ich hab das mit first_element_of_single_linked_list ins list 
umändern wolln, das steht aber leider noch 2-3 mal im code, soll beides 
das gleiche sein!

von Noname (Gast)


Lesenswert?

Das kann ja sein, aber ein L-Value der Form list->next erscheint 
nirgends.

Ich bitte Dich ein letztesmal, vollständigen, auf das notwendigste 
(Listenverkettung) Code zu posten und setzt hinzu das er kompilierbar 
sein muss.

So hat das keinen Zweck.

von Noname (Gast)


Lesenswert?

Ooops.

Es muss natürlich heissen:

Ich bitte Dich ein letztesmal, vollständigen, auf das notwendigste
(Listenverkettung) reduzierten Code zu posten und setze hinzu das er 
kompilierbar
sein mu

von Johannes M. (Gast)


Lesenswert?

So ich hab jetzt eine halbe Stunde lang gegoogelt und bin darauf 
gekommen, dass ich in meinem Programm ganz oben ja die Funktion

*error_code = allocateListMemory(&list);

aufrufe, welche den Befehl
1
list = malloc(sizeof(List));
beinhaltet.

Mit diese malloc(sizeof(List)) füge ich ja schon ein neues Element ein 
und diese Zeile mit
list = list->next;
ist ein Schwachsinn bzw. nicht notwendig.

von Zerf (Gast)


Lesenswert?

Irgendwo wirst du ein ->next hinschreiben müssen, sonst wird keine Liste 
draus.

von Vlad T. (vlad_tepesch)


Lesenswert?

Johannes M. schrieb:
> Mit diese malloc(sizeof(List)) füge ich ja schon ein neues Element ein
> und diese Zeile mit
> list = list->next;
> ist ein Schwachsinn bzw. nicht notwendig.

trotzdem macht sich die Verpointerung nicht von allein.

Mein Tip:
Trenne Nutzdaten und Struktur!
KApsel das Listeninterface gescheit
Dann wird das ganze auch übersichtlich

Denke dir die Typdefs bitte selbst dazu
1
struct List
2
{
3
  ListElement* first;
4
  ListElement* last;
5
}
6
7
8
struct ListElement
9
{
10
  ListElement* next;
11
  void*        data;
12
}
13
14
/**
15
 * adds an element at the end of the list
16
 * @param list  the list to manipulate
17
 * @param data  pointer to the data to add
18
 */
19
void List_pushBack( List* list, void* data)
20
{
21
  ListElement* e = malloc(sizeof(ListElement));
22
  if(list->last != 0) {
23
    list->last.next = e;
24
  }else{
25
    list->first = e;
26
  }
27
  e->next = 0;
28
  e->data = data;
29
  list->last = e;
30
}
31
32
/**
33
 * adds an element at the front of the list
34
 * @param list  the list to manipulate
35
 * @param data  pointer to the data to add
36
 */
37
void List_pushFront( List* list, void* data)
38
{
39
  ListElement* e = malloc(sizeof(ListElement));
40
  e->next = list->first;
41
  e->data = data;
42
  if(list->last == 0) {
43
    list->last = e;
44
  }
45
  list->first = e;
46
}
47
48
49
/**
50
  * frees the memory of all *following (next)* list elemnt.
51
  * @param le           pointer to listelement
52
  *                     if the first listelement of a list should be deleted
53
  *                     the list pointer can be casted to an Listelement*
54
  * @param deleteContent if true also the data of the list elemnt will be freed
55
  *                     obviously this only work on plain data structures with no
56
  *                     further pointer
57
  */
58
ListElement* List_deleteNextItem( ListElement* le , bool deleteContent)
59
{
60
  if(ls->next)
61
  {
62
    ListElement* n = ls->next.next;
63
    if(deleteContent)
64
    {
65
      free(ls->next.data);
66
    }
67
    free(ls->next);
68
    ls->next = n;
69
  }
70
  return ls->next;  
71
}
72
73
/**
74
  * frees the memory of all list elemnts.
75
  * @param list          pointer to list
76
  * @param deleteContent if true also the data of each list elemnt will be freed
77
  *                     obviously this only work on plain data structures with no
78
  *                     further pointer
79
  */
80
void List_deleteAll(List* list, bool deleteContent)
81
{
82
  while( List_deleteNextItem((ListElement*) list, deleteContent) )
83
  {};
84
}
85
86
87
88
89
List myList = {0,0};
90
PayLoad* filedata;
91
92
while( filedata = ReadDataFromFile(...) )
93
{
94
  List_pushBack(&myList, filedata)
95
}



hier das ganze in c++
1
#include <list>
2
3
std::list<PayLoad*> myList;  // wobei man hier normalerweise keinen Pointer nehmen würde.
4
5
PayLoad* filedata;
6
7
while( filedata = ReadDataFromFile(...) )
8
{
9
  List_pushBack(&myList, filedata)
10
}

von google (Gast)


Lesenswert?


von Zerf (Gast)


Lesenswert?

Perlen vor die Säue...

von google (Gast)


Lesenswert?

nur hinfummeln heisst nicht verstehen. wenn er lesen kann, wird 's noch 
was :-)

von Johannes M. (Gast)


Lesenswert?

Danke, Vlad Tepesch, eine super Erklärung und
@google (Gast)
Ja ich werde versuchen lesen zu lernen ;)

von Karl H. (kbuchegg)


Lesenswert?

Johannes M. schrieb:
>
1
List *readInput(char *name_of_file, int *error_code,
2
...
3
> }


Entschuldige.
Aber das ist doch alles Mist!


Trenne die Dinge auf!

Mach dir eine Funktion, der du eine Datenstruktur übergibst und die 
diese Datenstruktur vom File befüllt.
Es ist nicht Aufgabe dieser Funktion, dieses Datenelement dann auch noch 
in die Liste einzuhängen! Das geschieht an einer anderen Stelle!

Du schreibst da endlos lange Funktionen und dann wunderst du dich, wenn 
du den Überblick verlierst.
Ich hab dir doch beim letzten mal schon so ungefähr eine sinnvolle 
Struktur gegeben. Ich mach das doch nicht zum Spass und weil draussen 
das Wetter so schön ist.

Eines der 'Geheimnisse' der Programmierung besteht darin, dass man sich 
Struktur in den Code bringt. Struktur im Sinne von 'Aufteilung in 
Teilprobleme und jedes Teilproblem wird zu einer Funktion'. So kann man 
das Biest "Unübersichtlichkeit" bekämpfen und unter Kontrolle bringen. 
Aber doch nicht, indem man alles in möglichst eine einzige Funktion 
reinquetscht. Und dann auch noch mehrfach (wie zb das Einlesen eines 
Strings).

Gerade Neulinge glauben oft: Ja, aber wenn ich das jetzt erst mal in 
Teilfunktionen aufteile, dann brauch ich so lang bis ich fertig 
programmiert habe.
Das genaue Gegenteil ist der Fall! Du brauchst 10-fach länger, wenn du 
NICHT gleich organisiert an die Dinge ran gehst. Denn du wirst die 
Übersicht verlieren. Das ist 100% sicher! So ein Wunderwuzzi bist du 
nicht, dass bei dir alles ganz anders ist, wie bei den restlichen 
weltweit 20-tausend Programmierer, die jetzt im Moment genau das gleiche 
vorhaben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.