Elemente in einfache verkettete Liste speichern

Gast #2500355
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?
Gast #2500385
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!
Gast #2500398
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".
Gast #2500411
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.
Gast #2500442
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.
Gast #2500467
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
}
Gast #2500513
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.
#2500527
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
}
#2500867
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren