Forum: Mikrocontroller und Digitale Elektronik eventqueue in c schreiben


von Sonke A. (soeni)


Lesenswert?

Hallo, ich wollte ienen fifo also eine Queue in c schreiben, damit ich 
eintreffende Events in der eingetroffenen reihenfolge bearbeiten kann, 
wenn ich dazu zeit habe. hierbei bekomme ich die queue einfach nicht 
hin. irgendwas stimmt da nicht mit den Pointern. meine getEvent und 
meine initialisierung funktionieren nicht richtig. der compiler meldet 
folgende fehler:
1
../EventQueue/evenQueue.c:48: error: expected expression before 'mainEventQueue'
2
../EventQueue/evenQueue.c: In function 'getEvent':
3
../EventQueue/evenQueue.c:65: error: 'event' undeclared (first use in this function)
4
../EventQueue/evenQueue.c:65: error: (Each undeclared identifier is reported only once
5
../EventQueue/evenQueue.c:65: error: for each function it appears in.)
6
../EventQueue/evenQueue.c:65: error: expected ';' before 'ret'
7
../EventQueue/evenQueue.c:66: error: 'eventQueue' undeclared (first use in this function)
8
../EventQueue/evenQueue.c:66: error: expected ';' before 'tmp'
9
../EventQueue/evenQueue.c:67: error: expected identifier or '(' before '=' token
10
../EventQueue/evenQueue.c:68: error: 'tmp' undeclared (first use in this function)
11
../EventQueue/evenQueue.c:69: error: 'ret' undeclared (first use in this function)

der code:
1
/**
2
 *
3
 *          Project:    Automatic WIFI Network
4
 *          Package:    EventQueue
5
 *
6
 *
7
 * File:          Test.c
8
 * Author:        Soenke Paschko
9
 * Maintainer:   Soenke Paschko
10
 *
11
 * Created on:   08. August 2009, 11:35
12
 *
13
 * Content:
14
 *
15
 *
16
 * Revision history:
17
 * 08.08.09 1. revision Paschko  -  First version
18
 */
19
20
21
  #include "../main.h"
22
  #include "events.h"
23
  #include "eventQueue.h"
24
25
   /**
26
   * Event struct
27
   */
28
  typedef struct event{
29
    char eventClass;
30
    char eventSource;
31
  };
32
  
33
  typedef struct eventQueue{
34
    struct event data;
35
    struct eventQueue *next;
36
  }mainEventQueue;
37
38
  int length;
39
40
  struct eventQueue * endOfQueue;
41
42
43
  /**
44
   * This function initializes the event queue
45
   */
46
  void initEventQueue(){
47
    length  = 0;
48
    endOfQueue = &mainEventQueue;
49
  }
50
51
  /**
52
   * This function adds an event to the event queue
53
   */
54
  void addEvent(struct event evt){
55
    length=length + 1;
56
    struct eventQueue  newElement = {evt, NULL};
57
    endOfQueue->next = &newElement;
58
  }
59
60
  /**
61
   * This function gets the event from the event queue
62
   */
63
  struct event getEvent(){
64
    length = length - 1;
65
    event ret = mainEventQueue->data;
66
    eventQueue tmp = mainEventQueue;
67
    mainEventQueue = mainEventQueue->next;
68
    free(tmp);  // free allocated memory
69
    return ret;
70
  }

von Sven P. (Gast)


Lesenswert?

Mach dir klar, dass mit
1
typedef struct eventQueue{
2
    struct event data;
3
    struct eventQueue *next;
4
  }mainEventQueue;
keine Variable vereinbart wird.

von Naja (Gast)


Lesenswert?

Welcher Typname wird hiermit
1
  typedef struct event{
2
    char eventClass;
3
    char eventSource;
4
  };

definiert?

von Sonke A. (soeni)


Lesenswert?

Sven P. schrieb:
> Mach dir klar, dass mit
>
1
> typedef struct eventQueue{
2
>     struct event data;
3
>     struct eventQueue *next;
4
>   }mainEventQueue;
5
>
> keine Variable vereinbart wird.

hm warum nicht? steht doch mainEventQueue dahinter. Iwe macht man das 
sonst?



Naja schrieb:
> Welcher Typname wird hiermit
>
>
1
>   typedef struct event{
2
>     char eventClass;
3
>     char eventSource;
4
>   };
5
>
>
> definiert?

naja der typname ist event oder?

von Sven P. (Gast)


Lesenswert?

Nein, eben nicht.

Mit
1
typedef struct eventQueue{
2
     struct event data;
3
     struct eventQueue *next;
4
}mainEventQueue;
definierst du:
1. ein Token: struct eventQueue und
2. einen Typen: mainEventQueue.

Du kannst damit dann Variablen deklarieren, etwa so:
1. struct eventQueue var1, var2, bla, blubb;
2. mainEventQueue varA, varB, x, y, z;

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Statt
1
 typedef struct event{
2
    char eventClass;
3
    char eventSource;
4
  };
5
  
6
  typedef struct eventQueue{
7
    struct event data;
8
    struct eventQueue *next;
9
  }mainEventQueue;

dies benutzen:
1
  struct event{
2
    char eventClass;
3
    char eventSource;
4
  };
5
  
6
  struct eventQueue{
7
    struct event data;
8
    struct eventQueue *next;
9
  };
10
11
  struct eventQueue mainEventQueue;

Dies
1
  void addEvent(struct event evt){
2
    length=length + 1;
3
    struct eventQueue  newElement = {evt, NULL};
4
    endOfQueue->next = &newElement;
5
  }

geht in die Hose. Nach Verlassen von addEvent ist newElement ungültig. 
Das einsame free() ohne passendes malloc() macht mich auch stutzig.

von Sonke A. (soeni)


Lesenswert?

warum? ich verknüpfe es doch in meine liste??

das free gibt den speicherplatz wieder frei. alloziert wird der, wenn er 
der Funktion übergeben wird. aber du hast recht ich übergebe keinen 
pointer, nur eine kopie, deshalb geht das verlohren.

hier die neue Version:
1
/**
2
 *
3
 *          Project:    Automatic WIFI Network
4
 *          Package:    EventQueue
5
 *
6
 *
7
 * File:          Test.c
8
 * Author:        Soenke Paschko
9
 * Maintainer:   Soenke Paschko
10
 *
11
 * Created on:   08. August 2009, 11:35
12
 *
13
 * Content:
14
 *
15
 *
16
 * Revision history:
17
 * 08.08.09 1. revision Paschko  -  First version
18
 */
19
20
#ifndef EVENTQUEUE_H_
21
#define EVENTQUEUE_H_
22
23
   /**
24
   * Event structs
25
   */
26
  typedef struct{
27
    char eventClass;
28
    char eventSource;
29
  }event;
30
31
  typedef struct queue{
32
    event data;
33
    struct queue *next;
34
  }eventQueue;
35
36
37
  void initEventQueue();
38
  void addEvent(event * evt);
39
  event getEvent();
40
41
#endif /* EVENTQUEUE_H_ */

und der code:
1
/**
2
 *
3
 *          Project:    Automatic WIFI Network
4
 *          Package:    EventQueue
5
 *
6
 *
7
 * File:          Test.c
8
 * Author:        Soenke Paschko
9
 * Maintainer:   Soenke Paschko
10
 *
11
 * Created on:   08. August 2009, 11:35
12
 *
13
 * Content:
14
 *
15
 *
16
 * Revision history:
17
 * 08.08.09 1. revision Paschko  -  First version
18
 */
19
20
21
  #include "../main.h"
22
  #include "events.h"
23
  #include "eventQueue.h"
24
25
26
27
28
  int length;
29
30
  eventQueue * endOfQueue;     // Pointer to the end of the queue
31
  eventQueue * mainEventQueue;  // Pointer to the first Element of the queue
32
33
34
  /**
35
   * This function initializes the event queue
36
   */
37
  void initEventQueue(){
38
    length  = 0;
39
    endOfQueue = &mainEventQueue;
40
  }
41
42
  /**
43
   * This function adds an event to the event queue
44
   */
45
  void addEvent(event * evt){
46
    length=length + 1;
47
    eventQueue  newElement = {evt, NULL};
48
    endOfQueue->next = &newElement;
49
  }
50
51
  /**
52
   * This function gets the event from the event queue
53
   */
54
   event getEvent(){
55
    length = length - 1;
56
    event ret = mainEventQueue->data;
57
    eventQueue * tmp = mainEventQueue;
58
    mainEventQueue = mainEventQueue->next;
59
    free(tmp);  // free allocated memory
60
    return ret;
61
  }

von Mark .. (mork)


Lesenswert?

Das Problem mit der ungültigen Variable besteht immer noch. In 'void 
addEvent' wird eine lokale Varible 'newElement' angelegt. Sobald die 
Funktion verlassen wird, existiert 'newElement' nicht mehr und der 
gespeicherte Pointer zeigt auf einen Speicherbereich mit zufälligem 
Inhalt. Damit die Variable auch dann gültig ist, wenn die Funktion 
verlassen wurde, muss sie auf dem Heap abgelegt werden. Und das macht 
macht man eben mit malloc. Siehe 
http://home.fhtw-berlin.de/~junghans/cref/FUNCTIONS/malloc.html

Und noch was: 'endOfQueue = &mainEventQueue;' in 'void initEventQueue' 
ist sowohl semantisch als auch syntaktisch totaler Unsinn. 'endOfQueue' 
ist ebenso wie 'mainEventQueue' vom Typ 'eventQueue*' und deshalb kann 
man ihr auch keine Adresse von mainEventQueue zuweisen. Was Du machen 
willst, ist beide Zeiger auf NULL zu setzen, damit sie nicht auf einen 
zufälligen Bereich zeigen.

MfG Mark

Nachtrag: 'addEvent' hat noch einen kleinen Fehler, nämlich dass 
'endOfQueue' am Ende der Funktion nicht auf die Adresse des neuen 
Elements gesetzt wird. Zudem darf 'endOfQueue->next = &newElement;' so 
nicht stehen bleiben, sondern es muss zuerst geprüft werden, ob 
überhaupt ein letztes Element exisitiert (mit if(endOfQueue)). Erst dann 
kann man endOfQueue dereferenzieren.

von Sonke A. (soeni)


Lesenswert?

also muss ich das so machen?
1
  /**
2
   * This function adds an event to the event queue
3
   */
4
  void addEvent(event * evt){
5
    length=length + 1;
6
    eventQueue * newElement = (*char) malloc(3*8); 
7
    if(newElement != NULL){
8
      newElement = {evt, NULL};
9
      endOfQueue->next = &newElement;
10
    }
11
  }

nur da werden mir syntaxfehler gemeldet.

und das müsste dann so heisen?
1
  /**
2
   * This function initializes the event queue
3
   */
4
  void initEventQueue(){
5
    length  = 0;
6
    mainEventQueue = {NULL,NULL};
7
    endOfQueue = mainEventQueue;
8
  }


auch hier ist dann aber ein syntaxfehler bei mainEventQueue = 
{NULL,NULL};

was ist da falsch?

von Karl H. (kbuchegg)


Lesenswert?

Sönke Paschko schrieb:
> also muss ich das so machen?
>
>
1
>   /**
2
>    * This function adds an event to the event queue
3
>    */
4
>   void addEvent(event * evt){
5
>     length=length + 1;
6
>     eventQueue * newElement = (*char) malloc(3*8);
7
>     if(newElement != NULL){
8
>       newElement = {evt, NULL};
9
>       endOfQueue->next = &newElement;
10
>     }
11
>   }
12
>
>
> nur da werden mir syntaxfehler gemeldet.

Welche?
Syntaxfehler haben einen Text. Manchmal ist der Text wenig hilfreich 
aber meistens führt er einen auf die Spur.

* benutze KEINEN cast in C um das Ergebnis von malloc zurechtzucasten!
  Wenn der C-Compiler einen Datentypfehler ankreidet, dann ist hier ein
  cast ausnahmsweise nicht das Mittel der Wahl.

* (*char) ist Kein Cast, sondern ein banaler Syntaxfehler. Es müsste
  (char*) heissen. Aber der Cast ist wie gesagt in C nicht notwendig
  und auch nicht gut.

* malloc(3*8)
  Benutze kein Wissen darüber, wie gross Datentypen sind, wenn du es
  nicht unbedingt musst. Lass den Compiler sich um die Details der
  Datentypgrößen kümmern! Auf anderen Maschinen als auf einem AVR
  wirst du nämlich dein blaues Wunder erleben, wenn du eine derartige
  struct so allokierst. Da kann es dann durchaus sein, dass ein
  Strukturelement 4 Bytes gross ist, obowhl du rechnerisch nur auf
  3 kommst -> der Compiler hat padding Bytes eingefügt.
  Lass den Compiler rechnen, der kann das besser und kennt die Details.

*   newElement = {evt, NULL};
  in welcher Sprache du hier auch immer programmierst, C ist es auf
  keinen Fall.


> was ist da falsch?

Grob gesagt: Falsch ist, dass du kein C-Buch benutzt um die Sprache zu 
lernen (und da spreche ich noch gar nicht über das halbe Dutzend 
logischer Fehler, die du in den 5 Zeilen Code eingebaut hast)

1
/**
2
  * This function adds an event to the event queue
3
  */
4
eventQueue * addEvent( event * evt )
5
{
6
  eventQueue * newElement = malloc( sizeof( eventQueue ) );
7
 
8
  if( newElement != NULL ) {
9
     newElement->data = evt;
10
     newElement->next = NULL;
11
12
     if( mainEventQueue == NULL )
13
       mainEventQueue = newElement;
14
     else
15
       endOfQueue->next = newElement;
16
17
     endOfQueue = newElement;
18
19
     length = length + 1;
20
  }
21
22
  return newElement;
23
}

von Sonke A. (soeni)


Lesenswert?

also laut einem onlinebuch kann man ein struct so initialisieren

struckttyp hallo = {1.eintrag,2.eintrag};

wie machst du das denn?

so?
1
  /**
2
   * This function initializes the event queue
3
   */
4
  void initEventQueue(){
5
    length  = 0;
6
    mainEventQueue->data = NULL;
7
    mainEventQueue->next = NULL;
8
    endOfQueue = mainEventQueue;
9
  }

gehts nämlich auch nicht.

von Karl H. (kbuchegg)


Lesenswert?

Sönke Paschko schrieb:
> also laut einem onlinebuch kann man ein struct so initialisieren
>
> struckttyp hallo = {1.eintrag,2.eintrag};
>

Eine Initialisierung ist keine Zuweisung (auch wenn sie so aussieht)
Initialisierung: Ein neues Objekt kommt zur Welt und bekommt Werte.
Aber die Zuweisung von Werten an ein bereits bestehendes Objekt ist 
keine Initialisierung!

Für Initialisierungen kann man in C Syntaxelemente benutzen, die für 
Zuweisungen nicht zur Verfügung stehen.

WIe ich schon sagte: Du brauchst ein Buch. Und zwar ein vernünftiges 
Buch (zb den K&R) und nicht irgendein windiges Online-Tutorial, in dem 
die Hälfte nicht drinnen steht.

von Karl H. (kbuchegg)


Lesenswert?

Sönke Paschko schrieb:

>
>
1
>   /**
2
>    * This function initializes the event queue
3
>    */
4
>   void initEventQueue(){
5
>     length  = 0;
6
>     mainEventQueue->data = NULL;
7
>     mainEventQueue->next = NULL;
8
>     endOfQueue = mainEventQueue;
9
>   }
10
> 
11
>
>
> gehts nämlich auch nicht.

Logo geht das nicht (logisch gesehen). mainEventQueue ist ein Pointer! 
Worauf zeigt denn dieser Pointer ganz am Anfang?
Antwort: Irgendwo ins Nichts!
1
  /**
2
    * This function initializes the event queue
3
    */
4
  void initEventQueue(){
5
    length  = 0;
6
    mainEventQueue = NULL;
7
    endOfQueue = NULL;
8
 }

Zusammen mit der add Funktion, die ich dir oben geschrieben habe, 
funktioniert das dann perfekt. Bei ersten add wird das erste eventQueue 
Objekt erzeugt und mainEventQueue und endOfQueue darauf gesetzt.

von Naja (Gast)


Lesenswert?

Poste mal den Quelltext wie er jetzt aussieht.

"geht nicht" ist leider als Information nicht ausreichend. Woran siehst 
Du das es nicht geht?

Wenn man davon ausgeht das der Quellcode sich nicht wesentlich verändert 
hat, also immer noch
1
eventQueue * mainEventQueue;  // Pointer to the first Element of the queue

da steht, dann "geht" der Code deswegen nicht, weil noch kein Speicher 
für das worauf mainEventQueue zeigt, alloziiert ist. Ergo gibt es die 
Elemente data und next nicht.

von Karl H. (kbuchegg)


Lesenswert?

Und noch ein Tip:
starte deinen ersten Ausflug in die Welt der dynamischen Datenstrukturen 
NICHT auf einem AVR sondern auf einem PC. Du hast dort wesentlich 
bessere Debug-Möglichkeiten. Alleine die Tatsache, dass du dir deine 
Queue mittels
1
void print()
2
{
3
  eventQueue * pLoop = mainEventQueue;
4
5
  while( pLoop ) {
6
    printf( ....  was auch immer du für einen Event ausgeben kannst ... );
7
    pLoop = pLoop->next;
8
  }
9
}

eine simple View-Funktion machen kannst, die ziemlich zuverlässig Amok 
läuft, sobald auch nur der kleinste Hund in deiner Datenstruktur 
enthalten ist, ist die Vorarbeit auf einem PC wert. Nach jedem add 
oder delete die print Funktion aufrufen und nachsehen, ob das erwartete 
Ergebnis vorliegt.
Du wirst nämlich schnell merken, dass bei dynamischen Datenstrukturen 
jede Anweisung 100% korrekt sein muss, ansonsten geht etwas schief. Das 
gilt auch für die Reihenfolge von Anweisungen.
Das sieht zwar alles auf den ersten Blick korrekt aus, aber Fehler 
finden sich in dynamischen Strukturen immer erst >20 Schritte später. 
Das alte Prinzip, wonach ein Fehler im Debugger dort zu suchen ist, wo 
auch der Absturz passiert, gilt hier nicht mehr.

Wenn du deine Eventqueue auf dem PC korrekt laufen hast, lässt sich das 
alles 100% 1:1 auf den AVR übernehmen.

Und leg dir Papier und BLeistift bereit und zeichne die Operationen mit!
Für jeden Pointer malst du ein kleines Rechteck und wenn es sich dabei 
um eine benannte Variable handelt, dann schreibst du den Variablennamen 
darüber. Machst du einen malloc, dann malst du ein größeres Rechteck 
aufs Papier. Bei der Zuweisung des Pointers von malloc in eine Variable, 
malst du einen Pfeil von der 'Variablen' zum Rechteck. Genauso bei jeder 
anderen Zuweisung von Adressen an Pointer: Ein Pfeil wird eingezeichnet 
(Ausnahme: NULL wird einfach hineingeschrieben)


Das ist die Ausgangssituation:
Du hast 2 Variablen, beides Pointer
1
  mainEventQueue 
2
  +------------------+
3
  |                  |
4
  +------------------+
5
6
  endOfQueue
7
  +------------------+
8
  |                  |
9
  +------------------+

Jetzt gehen wir mal die add Funktion durch und zeichnen bei jedem 
Statement mit. Und zwar nur das, was auch tatsächlich im Quelltext 
steht!

Wir fangen bei der initFunktion an, die einfach nur die beiden Pointer 
Variablen auf NULL setzt
1
  mainEventQueue 
2
  +------------------+
3
  |   NULL           |
4
  +------------------+
5
6
  endOfQueue
7
  +------------------+
8
  |   NULL           |
9
  +------------------+

Die add-Funktion beginnt und bekommt einen Pointer auf einen Event in 
evt
1
  mainEventQueue 
2
  +------------------+
3
  |   NULL           |
4
  +------------------+
5
6
  endOfQueue
7
  +------------------+
8
  |   NULL           |
9
  +------------------+
10
11
12
  evt
13
  +-------------+        +-------------+
14
  |    o---------------->|             |
15
  +-------------+        |  Event      |
16
                         |             |
17
                         +-------------+
Die Funktion beginnt
1
  eventQueue * newElement = malloc( sizeof( eventQueue ) );

auf dem Papier bedeutet das, das ein neues Rechteck geboren wird, und es 
eine weitere Pointer Variable namens newElement gibt, die auf dieses 
Rechteck zeigt
1
  mainEventQueue 
2
  +------------------+
3
  |   NULL           |
4
  +------------------+
5
6
  endOfQueue
7
  +------------------+
8
  |   NULL           |
9
  +------------------+
10
11
  newElement
12
  +---------------+                   +------------+
13
  |       o-------------------------->| data:      |
14
  +---------------+                   | next:      |
15
                                      +------------+
16
17
  evt
18
  +-------------+        +-------------+
19
  |    o---------------->|             |
20
  +-------------+        |  Event      |
21
                         |             |
22
                         +-------------+
Beachte: Bei data bzw. next habe ich nichts eingetragen. Keinen Pfeil 
und auch nicht NULL. Denn genau das macht auch malloc, nämlich nichts. 
Was auch immer dort steht ist zufällig. Und zur Erinnerung: Du darfst 
auf dem Papier nur das machen, was auch dein Programm macht!

Weiter im Text
1
  if( newElement != NULL ) {

Such dir die Variable newElement in deiner Zeichnung. Steht da NULL 
drinnen oder nicht? Da geht ein Pfeil raus, newElement ist also nicht 
NULL. Also wird der then Teil vom if genommen
1
     newElement->data = evt;

rechte Seite der Zuweisung: evt. Von evt soll also der Wert genommen 
werden. Das läuft in der Zeichnung darauf hinaus, dass ein 2-ter Pfeil 
konstruiert wird, der dorthin zeigt, wo auch evt hinzeigt. Und wo soll 
dieser Pfeil beginnen? In newElement->data. Also: newElement aufsuchen. 
Dort muss ein Pfeil beginnen (daher im Quelltext auch ->). Dieser Pfeil 
endet in einem Rechteck und in diesem Rechteck muss es ein data Feld 
geben. Dort soll der neue Pfeil beginnen.
1
  mainEventQueue 
2
  +------------------+
3
  |   NULL           |
4
  +------------------+
5
6
  endOfQueue
7
  +------------------+
8
  |   NULL           |
9
  +------------------+
10
11
  newElement
12
  +---------------+                   +------------+
13
  |       o-------------------------->| data:  o--------+
14
  +---------------+                   | next:      |    |
15
                                      +------------+    |
16
                                                        |
17
                          +-----------------------------+
18
  evt                     v
19
  +-------------+        +-------------+
20
  |    o---------------->|             |
21
  +-------------+        |  Event      |
22
                         |             |
23
                         +-------------+
Überzeuge dich davon, dass der neu eingezeichnete Pfeil exakt dem 
entspricht, was durch
1
 newElement->data = evt;
gefordert war!

Weiter im Text
1
     newElement->next = NULL;
Das ist wieder einfach. newElement aufsuchen, dem Pfeil einmal folgen 
und im Rechteck bei next einen NULL Pointer eintragen
1
  mainEventQueue 
2
  +------------------+
3
  |   NULL           |
4
  +------------------+
5
6
  endOfQueue
7
  +------------------+
8
  |   NULL           |
9
  +------------------+
10
11
  newElement
12
  +---------------+                   +------------+
13
  |       o-------------------------->| data:  o--------+
14
  +---------------+                   | next: NULL |    |
15
                                      +------------+    |
16
                                                        |
17
                          +-----------------------------+
18
  evt                     v
19
  +-------------+        +-------------+
20
  |    o---------------->|             |
21
  +-------------+        |  Event      |
22
                         |             |
23
                         +-------------+
weiter
1
     if( mainEventQueue == NULL )
sieh dir meinEventQueue an. Steht da NULL drinnen?
Ja das tut es, also wird der then-Zweig genommen
1
   mainEventQueue = newElement;
Aha. Kennen wir schon. In mainEventQueue einen Pfeil installieren, der 
dorthin zeigt, wo auch newElement hinzeigt
1
  mainEventQueue 
2
  +------------------+
3
  |   o--------------------------------+
4
  +------------------+                 |
5
                                       |
6
  endOfQueue                           |
7
  +------------------+                 |
8
  |   NULL           |                 |
9
  +------------------+                 |
10
                                       |
11
  newElement                           v
12
  +---------------+                   +------------+
13
  |       o-------------------------->| data:  o--------+
14
  +---------------+                   | next: NULL |    |
15
                                      +------------+    |
16
                                                        |
17
                          +-----------------------------+
18
  evt                     v
19
  +-------------+        +-------------+
20
  |    o---------------->|             |
21
  +-------------+        |  Event      |
22
                         |             |
23
                         +-------------+
1
  endOfQueue = newElement;
Auch das ist wieder einfach
1
  mainEventQueue 
2
  +------------------+
3
  |   o--------------------------------+
4
  +------------------+                 |
5
                                       |
6
  endOfQueue                           |
7
  +------------------+                 |
8
  |   o-------------------------------+|
9
  +------------------+                ||
10
                                      ||
11
  newElement                          vv
12
  +---------------+                   +------------+
13
  |       o-------------------------->| data:  o--------+
14
  +---------------+                   | next: NULL |    |
15
                                      +------------+    |
16
                                                        |
17
                          +-----------------------------+
18
  evt                     v
19
  +-------------+        +-------------+
20
  |    o---------------->|             |
21
  +-------------+        |  Event      |
22
                         |             |
23
                         +-------------+
1
   length = length + 1;

OK. length habe ich bis jetzt ignoriert. Die Variable würde ich sowieso 
rauswerfen.

Damit ist die Funktion zu Ende und die Variablen evt und newElement als 
lokale Varibablen werden aufgelöst:
1
  mainEventQueue 
2
  +------------------+
3
  |   o--------------------------------+
4
  +------------------+                 |
5
                                       |
6
  endOfQueue                           |
7
  +------------------+                 |
8
  |   o-------------------------------+|
9
  +------------------+                ||
10
                                      ||
11
                                      vv
12
                                      +------------+
13
                                      | data:  o--------+
14
                                      | next: NULL |    |
15
                                      +------------+    |
16
                                                        |
17
                          +-----------------------------+
18
                          v
19
                         +-------------+
20
                         |             |
21
                         |  Event      |
22
                         |             |
23
                         +-------------+
Und? Das Ergebnis sieht richtig aus. Alle Pointer Variablen zeigen 
irgendwo hin oder sind NULL. Kein Pointer zeigt ins Nichts (Pfeil der an 
keinem Rechteck endet)

(Fortsetzung folgt)

von Karl H. (kbuchegg)


Lesenswert?

Jetzt machen wir einen weiteren Aufruf von add.

Wieder bekommt die Funktion einen Event in Form eines POinters in evt
1
  mainEventQueue
2
  +------------------+
3
  |   o--------------------------------+
4
  +------------------+                 |
5
                                       |
6
  endOfQueue                           |
7
  +------------------+                 |
8
  |   o-------------------------------+|
9
  +------------------+                ||
10
                                      ||
11
                                      vv
12
                                      +------------+
13
                                      | data:  o--------+
14
                                      | next: NULL |    |
15
                                      +------------+    |
16
                                                        |
17
                          +-----------------------------+
18
                          v
19
                         +-------------+
20
                         |             |
21
                         |  Event      |
22
                         |             |
23
                         +-------------+
24
25
  evt
26
  +-----------+                          +-----------+
27
  |   o--------------------------------->|           |
28
  +-----------+                          |  Event    |
29
                                         |           |
30
                                         +-----------+
Die Funktion beginnt
1
  eventQueue * newElement = malloc( sizeof( eventQueue )
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o--------------------------+|
9
  +------------------+           ||
10
                                 ||
11
                                 vv
12
                                 +------------+            +-----------+
13
                                 | data:  o--------+    +->| data:     |
14
                                 | next: NULL |    |    |  | next:     |
15
                                 +------------+    |    |  +-----------+
16
                                                   |    |
17
                          +------------------------+    |
18
                          v                             |
19
                         +-------------+                |
20
                         |             |                |
21
                         |  Event      |                |
22
                         |             |                |
23
                         +-------------+                |
24
                                                        |
25
                                                        |
26
  newElement                                            |
27
  +-------------+                                       |
28
  |   o-------------------------------------------------+
29
  +-------------+
30
31
  evt
32
  +-----------+                          +-----------+
33
  |   o--------------------------------->|           |
34
  +-----------+                          |  Event    |
35
                                         |           |
36
                                         +-----------+
1
  if( newElement != NULL ) {

newElement ist offensichtlich nut NULL (da geht ein Pfeil heraus)
1
    newElement->data = evt;
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o--------------------------+|
9
  +------------------+           ||
10
                                 ||
11
                                 vv
12
                                 +------------+            +-----------+
13
                                 | data:  o--------+    +->| data:  o----+
14
                                 | next: NULL |    |    |  | next:     | |
15
                                 +------------+    |    |  +-----------+ |
16
                                                   |    |                |
17
                          +------------------------+    |                |
18
                          v                             |                |
19
                         +-------------+                |                |
20
                         |             |                |                |
21
                         |  Event      |                |                |
22
                         |             |                |                |
23
                         +-------------+                |                |
24
                                                        |                |
25
                                                        |                |
26
  newElement                                            |                |
27
  +-------------+                                       |                |
28
  |   o-------------------------------------------------+                |
29
  +-------------+                                                        |
30
                                          +------------------------------+
31
  evt                                     v                              
32
  +-----------+                          +-----------+
33
  |   o--------------------------------->|           |
34
  +-----------+                          |  Event    |
35
                                         |           |
36
                                         +-----------+
1
  newElement->next = NULL;
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o--------------------------+|
9
  +------------------+           ||
10
                                 ||
11
                                 vv
12
                                 +------------+            +------------+
13
                                 | data:  o--------+    +->| data:  o----+
14
                                 | next: NULL |    |    |  | next: NULL ||
15
                                 +------------+    |    |  +------------+|
16
                                                   |    |                |
17
                          +------------------------+    |                |
18
                          v                             |                |
19
                         +-------------+                |                |
20
                         |             |                |                |
21
                         |  Event      |                |                |
22
                         |             |                |                |
23
                         +-------------+                |                |
24
                                                        |                |
25
                                                        |                |
26
  newElement                                            |                |
27
  +-------------+                                       |                |
28
  |   o-------------------------------------------------+                |
29
  +-------------+                                                        |
30
                                          +------------------------------+
31
  evt                                     v                              
32
  +-----------+                          +-----------+
33
  |   o--------------------------------->|           |
34
  +-----------+                          |  Event    |
35
                                         |           |
36
                                         +-----------+
1
   if( mainEventQueue == NULL )
Sieh dir die Variable mainEventQueue an. Ist sie NULL? Nein, da kommt 
ein Pfeil heraus. Also wird der else Zweig genommen
1
  endOfQueue->next = newElement;

Die Variable endOfQueue aufsuchen, dem Pfeil folgen (wegen dem -> im 
Quelltext) und im Rechteck an dem du landest bei next einen Pfeil 
eintragen, der dort endet, wo auch newElement endet:
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o--------------------------+|
9
  +------------------+           ||
10
                                 ||
11
                                 vv
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  | +->| data:  o----+
14
                                 | next:  o-----------+ |  | next: NULL ||
15
                                 +------------+    |    |  +------------+|
16
                                                   |    |                |
17
                          +------------------------+    |                |
18
                          v                             |                |
19
                         +-------------+                |                |
20
                         |             |                |                |
21
                         |  Event      |                |                |
22
                         |             |                |                |
23
                         +-------------+                |                |
24
                                                        |                |
25
                                                        |                |
26
  newElement                                            |                |
27
  +-------------+                                       |                |
28
  |   o-------------------------------------------------+                |
29
  +-------------+                                                        |
30
                                          +------------------------------+
31
  evt                                     v                              
32
  +-----------+                          +-----------+
33
  |   o--------------------------------->|           |
34
  +-----------+                          |  Event    |
35
                                         |           |
36
                                         +-----------+

Soweit so gut. Weiter:
1
   endOfQueue = newElement;

Das ist wieder einfach. Ein Pfeil der von endOfQueue ausgeht und dort 
endet wo auch der Pfeil in newElement endet:
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o---------------------------|------------------------+
9
  +------------------+            |                        |
10
                                  |                        |
11
                                  v                        v
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  | +->| data:  o----+
14
                                 | next:  o-----------+ |  | next: NULL ||
15
                                 +------------+    |    |  +------------+|
16
                                                   |    |                |
17
                          +------------------------+    |                |
18
                          v                             |                |
19
                         +-------------+                |                |
20
                         |             |                |                |
21
                         |  Event      |                |                |
22
                         |             |                |                |
23
                         +-------------+                |                |
24
                                                        |                |
25
                                                        |                |
26
  newElement                                            |                |
27
  +-------------+                                       |                |
28
  |   o-------------------------------------------------+                |
29
  +-------------+                                                        |
30
                                          +------------------------------+
31
  evt                                     v                              
32
  +-----------+                          +-----------+
33
  |   o--------------------------------->|           |
34
  +-----------+                          |  Event    |
35
                                         |           |
36
                                         +-----------+

Damit ist die Funktion wieder durch, die Argumente und lokalen Variablen 
werden eliminiert:
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o---------------------------|------------------------+
9
  +------------------+            |                        |
10
                                  |                        |
11
                                  v                        v
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  |    | data:  o----+
14
                                 | next:  o-----------+    | next: NULL ||
15
                                 +------------+    |       +------------+|
16
                                                   |                     |
17
                          +------------------------+                     |
18
                          v                                              |
19
                         +-------------+                                 |
20
                         |             |                                 |
21
                         |  Event      |                                 |
22
                         |             |                                 |
23
                         +-------------+                                 |
24
                                                                         |
25
                                                                         |
26
                                          +------------------------------+
27
                                          v                              
28
                                         +-----------+
29
                                         |           |
30
                                         |  Event    |
31
                                         |           |
32
                                         +-----------+

Zurücklehnen und die Datenstruktur studieren.
Sieht gut aus. Beginnend mit mainEventQueue startet eine Kette von 
EventQueue Objekten, die über den next-Pointer sauber miteinander 
verknüpft sind. Das letzte EventQueue Objekt hat ein NULL im next 
Pointer. Jedes EventQueue Objekt zeigt auch auf einen Event in seinem 
data Feld und endOfQueue zeigt auch tatsächlich auf das letzte 
EventQueue Objekt in der Kette.

von Karl H. (kbuchegg)


Lesenswert?

Bleibt nur noch darüber zu sprechen, was bei der Umkehrung (free) am 
Papier passieren soll.
Wenn dein Programm einen free ausführt, dann radierst du das Rechteck 
aus auf das der angegebene Pfeil zeigt, inklusive aller Pfeile die aus 
dem Rechteck herausführen. Und das wars dann schon. Insbesondere 
radierst du keinen Pfeil weg, der zu diesem Rechteck geführt hat! Nur 
weil man eine struct mittels free löscht, wird deswegen noch lange kein 
Pointer der dorthin zeigt umgesetzt. Der Pointer zeigt nach wie vor auf 
die gleiche Stelle im Speicher und die Tatsache, dass du dann am Papier 
einen Pfeil hast, der im Nichts endet, soll dich darauf aufmerksam 
machen, dass dann eine Operation wie Pointer->next einfach nicht mehr 
machbar ist. Der Pfeil zeigt ins Leere, dort gibt es kein next Feld!

Gehen wir als Beispiel deine etwas umgewandelte get Funktion durch
1
  struct event * getEvent(){
2
    length = length - 1;
3
    event * ret = mainEventQueue->data;
4
    eventQueue * tmp = mainEventQueue;
5
    mainEventQueue = mainEventQueue->next;
6
    free(tmp);  // free allocated memory
7
    return ret;
8
  }

Die Funktion beginnt mit dieser Datenstruktur
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o---------------------------|------------------------+
9
  +------------------+            |                        |
10
                                  |                        |
11
                                  v                        v
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  |    | data:  o----+
14
                                 | next:  o-----------+    | next: NULL ||
15
                                 +------------+    |       +------------+|
16
                                                   |                     |
17
                          +------------------------+                     |
18
                          v                                              |
19
                         +-------------+                                 |
20
                         |             |                                 |
21
                         |  Event      |                                 |
22
                         |             |                                 |
23
                         +-------------+                                 |
24
                                                                         |
25
                                                                         |
26
                                          +------------------------------+
27
                                          v                              
28
                                         +-----------+
29
                                         |           |
30
                                         |  Event    |
31
                                         |           |
32
                                         +-----------+

Erste Anweisung
1
      event * ret = mainEventQueue->data;

Also: neue Variable erzeugen und auf meinEventQueue->data zeigen lassen
(mainEventQueue aufsuchen, dem -> folgen, data Feld im Rechteck 
aufsuchen)
1
  mainEventQueue
2
  +------------------+
3
  |   o---------------------------+
4
  +------------------+            |
5
                                  |
6
  endOfQueue                      |
7
  +------------------+            |
8
  |   o---------------------------|------------------------+
9
  +------------------+            |                        |
10
                                  |                        |
11
                                  v                        v
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  |    | data:  o----+
14
                                 | next:  o-----------+    | next: NULL ||
15
                                 +------------+    |       +------------+|
16
                                                   |                     |
17
                          +------------------------+                     |
18
                          v                                              |
19
                         +-------------+                                 |
20
                         |             |                                 |
21
                         |  Event      |                                 |
22
                         |             |                                 |
23
                        >+-------------+                                 |
24
                        |                                                |
25
                        |                                                |
26
                        |                 +------------------------------+
27
                        |                 v                              
28
                        |                +-----------+
29
                        |                |           |
30
                        |                |  Event    |
31
                        |                |           |
32
                        |                +-----------+
33
                        |
34
   ret                  |
35
   +------+             |
36
   |  o-----------------+
37
   +------+
1
      eventQueue * tmp = mainEventQueue;
1
  mainEventQueue                        tmp
2
  +------------------+                  +----------+
3
  |   o---------------------------+ +--------o     |
4
  +------------------+            | |   +----------+
5
                                  | |
6
  endOfQueue                      | |
7
  +------------------+            | |
8
  |   o---------------------------|-|----------------------+
9
  +------------------+            | |                      |
10
                                  | |                      |
11
                                  v v                      v
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  |    | data:  o----+
14
                                 | next:  o-----------+    | next: NULL ||
15
                                 +------------+    |       +------------+|
16
                                                   |                     |
17
                          +------------------------+                     |
18
                          v                                              |
19
                         +-------------+                                 |
20
                         |             |                                 |
21
                         |  Event      |                                 |
22
                         |             |                                 |
23
                        >+-------------+                                 |
24
                        |                                                |
25
                        |                                                |
26
                        |                 +------------------------------+
27
                        |                 v                              
28
                        |                +-----------+
29
                        |                |           |
30
                        |                |  Event    |
31
                        |                |           |
32
                        |                +-----------+
33
                        |
34
   ret                  |
35
   +------+             |
36
   |  o-----------------+
37
   +------+
1
   mainEventQueue = mainEventQueue->next;
mainEventQueue soll dorthin zeigen, wo mainEventQueue->next bisher 
hingezeigt hat
1
  mainEventQueue                        tmp
2
  +------------------+                  +----------+
3
  |   o---------------------------+ +--------o     |
4
  +------------------+            | |   +----------+
5
                                  | |
6
  endOfQueue                      +-------------------------+
7
  +------------------+              |                       |
8
  |   o-----------------------------|----------------------+|
9
  +------------------+              |                      ||
10
                                    |                      ||
11
                                    v                      vv
12
                                 +------------+       +--->+------------+
13
                                 | data:  o--------+  |    | data:  o----+
14
                                 | next:  o-----------+    | next: NULL ||
15
                                 +------------+    |       +------------+|
16
                                                   |                     |
17
                          +------------------------+                     |
18
                          v                                              |
19
                         +-------------+                                 |
20
                         |             |                                 |
21
                         |  Event      |                                 |
22
                         |             |                                 |
23
                        >+-------------+                                 |
24
                        |                                                |
25
                        |                                                |
26
                        |                 +------------------------------+
27
                        |                 v                              
28
                        |                +-----------+
29
                        |                |           |
30
                        |                |  Event    |
31
                        |                |           |
32
                        |                +-----------+
33
                        |
34
   ret                  |
35
   +------+             |
36
   |  o-----------------+
37
   +------+
1
  free(tmp);  // free allocated memory
Das Rechteck, auf das tmp zeigt, wird ausradiert
1
  mainEventQueue                        tmp
2
  +------------------+                  +----------+
3
  |   o---------------------------+ +--------o     |
4
  +------------------+            | |   +----------+
5
                                  | |
6
  endOfQueue                      +-------------------------+
7
  +------------------+              |                       |
8
  |   o-----------------------------|----------------------+|
9
  +------------------+              |                      ||
10
                                    |                      ||
11
                                    v                      vv
12
                                                           +------------+
13
                                                           | data:  o----+
14
                                                           | next: NULL ||
15
                                                           +------------+|
16
                                                                         |
17
                         +-------------+                                 |
18
                         |             |                                 |
19
                         |  Event      |                                 |
20
                         |             |                                 |
21
                        >+-------------+                                 |
22
                        |                                                |
23
                        |                                                |
24
                        |                 +------------------------------+
25
                        |                 v                              
26
                        |                +-----------+
27
                        |                |           |
28
                        |                |  Event    |
29
                        |                |           |
30
                        |                +-----------+
31
                        |
32
   ret                  |
33
   +------+             |
34
   |  o-----------------+
35
   +------+
1
  return ret;
Der Aufrufer kriegt also einen Pointer zurück. ret zeigt tatsächlich 
noch auf etwas und dieses Etwas ist sogar sinnvoll, nämlich die 
Event-Beschreibung des ersten Events.

Damit ist die Funktion wieder zu Ende und die lokalen Variablen werden 
aufgelöst
1
  mainEventQueue                        
2
  +------------------+                   
3
  |   o---------------------------+  
4
  +------------------+            | 
5
                                  | 
6
  endOfQueue                      +-------------------------+
7
  +------------------+                                      |
8
  |   o----------------------------------------------------+|
9
  +------------------+                                     ||
10
                                                           ||
11
                                                           vv
12
                                                           +------------+
13
                                                           | data:  o----+
14
                                                           | next: NULL ||
15
                                                           +------------+|
16
                                                                         |
17
                         +-------------+                                 |
18
                         |             |                                 |
19
                         |  Event      |                                 |
20
                         |             |                                 |
21
                         +-------------+                                 |
22
                                                                         |
23
                                                                         |
24
                                          +------------------------------+
25
                                          v                              
26
                                         +-----------+
27
                                         |           |
28
                                         |  Event    |
29
                                         |           |
30
                                         +-----------+

Sieht nach wie vor gut aus. Der main Pointer zeigt auf den Anfang der 
verbleibenden EventQueue Objekte, auch endOfQueue ist noch gültig. Das 
einsame Event Objekt da mitten drinn, ist auch kein Problem, ein Pointer 
darauf wurde ja dem Aufrufer zurückgegeben, er ist auch dafür zuständig, 
dass es zerstört wird. Genauso wie er dafür zuständig war, dass es beim 
Aufruf von add schon erzeugt war.

von Sonke A. (soeni)


Lesenswert?

vielen dank für die lange erklährung, das war wirklich gut. ich hoffe 
ich hab alles verstanden. werde mich morgen mal an die Umsetzung machen.

von Aahh (Gast)


Lesenswert?

Debugger - nie gehoert ?
Simulation - Nie gehoert ?

So wird das eh nichts.

von soeni- (Gast)


Lesenswert?

Was meinst du damit?

ich habe kein Emulator (VIEL ZU VIEL GELD)
Mit nem Simulator lassen sich nur sehr schwehr interrupts erzeugen, das 
ist zu kompliziert und warum?

Debugger (JTAG ICE) hab ich auch nicht.

Wozu auch, man kann doch über LEDs debuggen. oder man nimmt halt rs232 
und hat nen printfdebugging

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.