Forum: PC-Programmierung Prob: Lineare Liste


von Michael L. (nemesisod)


Lesenswert?

Hallo zusammen,

ich habe ein Problem mit meiner Linearen Liste in ANSI-C.

Wenn ich die Liste erstelle, werden die richtigen Werte in sie 
reingeschrieben, aber beim Auslesen führt mein Code zu einem Programm 
absturz.

Ich vermute mal, das ich beim schreiben nur die Zeiger auf lokale 
Variablen setzte und nach der Routine diese nicht mehr gültig sind. Bin 
aber noch nicht so erfahren mit Zeigern, so das ich den Fehler nicht 
finden kann.

Hier mein Code:
1
typedef struct GC
2
{
3
    unsigned int G;               // G-Code
4
    unsigned int X;               // X-Koordinate (Optional)
5
    unsigned int Y;               // Y-Koordinate (Optional)
6
    unsigned int D;               // D-Code (Optional)
7
    struct DB *Block_Liste;       // Nur wenn dem G-Code ein Block folgt
8
} G_CODE;
9
10
typedef struct DB
11
{ 
12
    unsigned int X;               // X-Koordinate
13
    unsigned int Y;               // Y-Koordinate
14
    unsigned int PLOT_FUNCTION;   // D-Code
15
} DATA_BLOCK;
16
17
18
typedef struct Block
19
{
20
  char union_type;
21
  union 
22
  {
23
    G_CODE  g;                          //Falls das Element ein G-Code ist
24
    DATA_BLOCK data;                    //Falls das Element ein Data-Block ist        
25
  } body;
26
  struct Block *next;     
27
} DATA_LIST;
28
29
30
/*----------------------------------------------------------------------------*/
31
/*----------------------------------------------------------------------------*/
32
/*----------------------------------------------------------------------------*/
33
/* Einfuegen von wert an passender Stelle (aufsteigend sortiert) */
34
void Einfuegen_Block(DATA_LIST **pliste,G_CODE *g,DATA_BLOCK *data)
35
{
36
 if (*pliste==NULL)
37
 {
38
  *pliste = (DATA_LIST*)malloc(sizeof(DATA_LIST));
39
  
40
  if (*pliste == NULL)
41
  {
42
   fprintf(stderr,"\nmalloc()-Aufruf schlug fehl!\n");
43
//   exit(0);
44
  } /* end if malloc() schlug fehl */
45
  
46
  if( g != NULL)
47
  {
48
      (*pliste)->union_type = 1;
49
      (*pliste)->body.g = *g; 
50
      printf("\n\t%d\n",(*pliste)->union_type);
51
  }          
52
  else if ( data != NULL )
53
  {
54
      (*pliste)->union_type = 2;
55
      (*pliste)->body.data = *data; 
56
      printf("\n\t%d\n",(*pliste)->union_type);
57
  }
58
       
59
  (*pliste)->next = NULL;
60
61
 } /* end if *pliste==NULL */
62
 else 
63
 {
64
65
  Einfuegen_Block(&((*pliste)->next),g,data);
66
 } /* rekursiver Zweig - weiter hinten anhängen oder einfügen*/
67
} /* end Einfuegen */
68
69
/*----------------------------------------------------------------------------*/
70
/*----------------------------------------------------------------------------*/
71
/*----------------------------------------------------------------------------*/
72
/* Einfache Ausgabe der linearen Liste */
73
void Ausgeben_Block(DATA_LIST *liste)
74
{
75
DATA_BLOCK data;
76
int i,x;
77
 if (liste==NULL)
78
    printf("\n(Ende der Liste)\n");
79
 else
80
 {
81
  printf("\n(Test %d)\n",(*liste).union_type);
82
  if( ((*liste).union_type) == 1 )
83
  {
84
   printf("G%02d",liste->body.g.G);    
85
  }
86
  else if( ((*liste).union_type) == 2 )
87
  {
88
       
89
  }
90
  Ausgeben_Block(liste->next);   
91
 }
92
} /* end Ausgeben */
93
94
/*----------------------------------------------------------------------------*/
95
/*----------------------------------------------------------------------------*/
96
/*----------------------------------------------------------------------------*/
97
98
DATA_LIST *scan_line(char *s,DATA_LIST *pointer)
99
{
100
DATA_BLOCK data_block;
101
G_CODE g_block;
102
103
104
if( DATA_BLOCK_FILTER(s,&data_block) != NULL)
105
{
106
107
Einfuegen_Block(pointer,NULL,&data_block);
108
109
 #if DEBUG == 1
110
     printf("\n\tX = %d\n\tY = %d\n\tD = %d\n",data_block.X,data_block.Y,data_block.PLOT_FUNCTION);
111
 #endif
112
}
113
else if ( G_CODE_FILTER(s,&g_block) != NULL)
114
{
115
Einfuegen_Block(pointer,&g_block,NULL);
116
 #if DEBUG == 1
117
     printf("\n\tG = %d\n\tX = %d\n\tY = %d\n\tD = %d\n",g_block.G,g_block.X,g_block.Y,g_block.D);
118
 #endif     
119
}
120
       
121
}
122
123
int main(void)
124
{
125
....
126
scan_line("G54D10*",&liste);
127
128
scan_line("X1000Y4356D01*",&liste);
129
130
Ausgeben_Block(&liste);
131
....
132
}

Wenn die Zeile Ausgeben_Block(&liste); auskommentiert ist, stürzt mein 
Programm nicht ab.

Ich würde mich freuen wenn mir jemand helfen kann.

Gruß
NemesisoD

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Crash sofort ohne jede fprintf/printf-Ausgabe?

von Michael L. (nemesisod)


Lesenswert?

Also,
das "Test %d" gibt er aus, und zwar 3 mal, aber in %d steht nicht das 
was ich erwaret habe.

Auch das "G%02d" wird ausgegeben, aber auch hier steht nicht der 
richtige wert drin.

Danke

von yalu (Gast)


Lesenswert?

Wie ist liste in main definiert? Ich schätze, so:
1
  DATA_LIST *liste;

Dann muss die Argumentliste von scan_line aber nicht so
1
DATA_LIST *scan_line(char *s,DATA_LIST *pointer)

sondern wahrscheinlich so aussehen:
1
DATA_LIST *scan_line(char *s,DATA_LIST **pointer)

und der Aufruf von Ausgeben_Block nicht so
1
  Ausgeben_Block(&liste);

sondern so:
1
  Ausgeben_Block(liste);

Gibt der Compiler bei der Übergabe nichtkompatibler Pointer keine
Warnung aus? Wenn nicht, musst du den Warning-Level erhöhen. Wenn doch,
musst du diese auch beachten ;-)

von yalu (Gast)


Lesenswert?

Noch etwas: Hast du, bevor du C gelernt hast, LISP programmiert? Das
würde deinen Hang zur rekursiven Programmierung erklären ;-)

Die Rekursionstiefe in Einfuegen_Block und Ausgeben_Block ist gleich
der Anzahl der Elemente in der Liste. Bei sehr langen Listen kommt es
dann irgendwann zum Stacküberlauf. Da es sich in beiden Fällen um eine
Endrekursion handelt, wird sie ein intelligenter Compiler (z.B. GCC bei
Optimierungsstufe -O2, -O3 oder -Os) zwar in eine Schleife umwandeln, es
ist aber gefährlich, sich auf solche Features zu verlassen.

In C vermeidet man Rekursionen, wo dies so leicht möglich ist, wie in
diesem Fall.

Anders in LISP: Dort ist es sogar guter Stil, Endrekursionen
(funktionales Konstrukt, hui) statt Schleifen (prozedurales Konstrukt,
pfui) zu verwenden. Im Gegensatz zu C gehört in LISP die Auflösung von
Endrekursionen durch den Compiler aber zur Sprachspezifikation, weswegen
man sich auf sie verlassen kann.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich schliesse mich Yalu an und ergänze noch was formales:

In Einfuegen_Block() reicht diese Anweisung (*pliste)->body.g = *g; 
nicht aus, um aus der Quelle (Zeiger g) in das Ziel (Element g vom Typ 
G_CODE in der Union body) zu kopieren. Hier muss eine Blockkopieraktion 
wie z.B. memcpy() ran. Gleiches gilt für data.

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.