Forum: Mikrocontroller und Digitale Elektronik Zeiger auf nichtinitialisierte Struktur, aber wie?


von Ste N. (steno)


Lesenswert?

Hallo C-Gemeinde, ich weiss einfach nicht wonach ich noch suchen soll. 
Was mir einfiel, brachte mich nicht wirklich weiter...

Bin gerade dabei eine Menüstruktur für einen µC zu schreiben. Dabei 
möchte ich gern das Prinzip der verketteten Liste nutzen. Nun habe ich 
aber das Problem, das ich auf Strukturen zeigen muß die noch nicht 
Initialisiert sind. Gibt es dafür in C eine Lösung? Ich könnte natürlich 
alle Menüeinträge in eine Struktur schreiben, das Ganze wird aber bei 
größeren Menütiefen extrem unübersichtlich. Außerdem muß man zum 
Einfügen eines neuen Menüpunktes alle nachfolgenden Menü-Zeiger ändern, 
was die Sache nicht unbedingt Fehlerunanfälliger macht.
1
#define ANZAHL_TASTEN 4
2
3
/*grundlegender datentyp */
4
typedef struct m{ struct m  *upmen;            /* Menü eine Ebene höher, falls vorhanden */
5
                  struct m  *prev;            /* Das vorhergehende Menü dieser Ebene */
6
                  struct m  *next;            /* Das nächste Menü dieser Ebene */
7
                  struct m  *submen;          /* Untermenü, falls vorhanden */
8
                  char      *mtxt;            /* Menütext */
9
                  void      (*mfun)(struct m**);    /* Menüfunktion, falls vorhanden */
10
                  char      *mdat;            /* Menüdaten */
11
                                              /* Die diesem Menüpunkt zugeordneten Tastenfunktionen */
12
                  void      (*tastfun[ANZAHL_TASTEN])(struct m**);  
13
                }MENU;
14
15
// Submenü 1            
16
MENU sm1[]={  {&omu[0], &sm1[0], &sm1[1], NULL, "Menu 1.1", dumfun, NULL, {curup, curdwn, upmen, dumfun}},
17
              {&omu[0], &sm1[0], &sm1[2], NULL, "Menu 1.2", dumfun, NULL, {curup, curdwn, upmen, dumfun}},
18
              {&omu[0], &sm1[1], &sm1[3], NULL, "Menu 1.3", dumfun, NULL, {curup, curdwn, upmen, dumfun}},
19
              {&omu[0], &sm1[2], &sm1[3], NULL, "Menu 1.4", dumfun, NULL, {curup, curdwn, upmen, dumfun}}};
20
21
// Oberste Menüebene
22
MENU omu[]={  {NULL, &omu[0], &omu[1],  sm1, "Menu 1  ", dumfun, NULL, {curup, curdwn, dumfun, submen}},
23
              {NULL, &omu[0], &omu[2], NULL, "Menu 2  ", dumfun, NULL, {curup, curdwn, dumfun, dumfun}},
24
              {NULL, &omu[1], &omu[3], NULL, "Menu 3  ", dumfun, NULL, {curup, curdwn, dumfun, dumfun}},
25
              {NULL, &omu[2], &omu[3], NULL, "Menu 4  ", dumfun, NULL, {curup, curdwn, dumfun, dumfun}}};
26
27
28
/* Das vorhergehende Menü dieser Ebene */
29
void curup(MENU **men)
30
{
31
  MENU *m;
32
  m = (*men)->prev;
33
  if (m)
34
    *men = m;
35
}
36
37
/* Das nächste Menü dieser Ebene */
38
void curdwn(MENU **men)
39
{
40
  MENU *m;
41
  m = (*men)->next;
42
  if (m)
43
    *men = m;
44
}
45
46
/* Untermenü */
47
void submen(MENU **men)
48
{
49
  MENU *m;
50
  m = (*men)->submen;
51
  if (m)
52
    *men = m;
53
}
54
55
/* Menü eine Ebene höher */
56
void upmen(MENU **men)
57
{
58
  MENU *m;
59
  m = (*men)->upmen;
60
  if (m)
61
    *men = m;
62
}
63
64
/* Displaytext anzeigen */
65
void display (MENU **men)
66
{
67
  sendStringSPI((*men)->mtxt);
68
}
69
70
71
MENU *zeile;
72
73
int main(void)
74
{
75
  zeile = omu;
76
77
  while (1)
78
  {
79
    taste = get_key();
80
    if(taste)
81
    {
82
      zeile->tastfun[taste-1](&zeile);
83
      zeile->mfun(&zeile);
84
      display(&zeile);
85
    }
86
  }
87
  return 0;
88
}

Mein Problem ist nun konkret, das ich im Array sm1[] auf om[] verweisen 
möchte, welches aber zu diesem Zeitpunkt noch gar nicht existiert.
1
MENU sm1[]={  {&omu[0],...
Weiß jemand Rat?

Ach ja, das Programm hier muß jetzt nicht 100%ig lauffähig sein. Habe 
ich nur schnell aus meiner Anwendung zusammenkopiert. Es soll nur den 
Sachverhalt verdeutlichen

Viele Grüße,
Steffen

von Hc Z. (mizch)


Lesenswert?

Es sollte gehen, wenn Du ein
1
extern MENU omu[];
voranstellst.  Eine Extern-Deklaration und eine Definition im selben 
File beißen sich nicht.

von G. O. (aminox86)


Lesenswert?

Das Problem mit dem Hauptmenü habe ich in meinem Wettbewerbsbeitrag von 
2008, Tinykon, dadurch gelöst, dass es kein Hauptmenü gibt, auf das zur 
Compilierzeit verwiesen wird.
Die Datenstruktur von Tinykon ist der hier vorgestellten Menüstruktur 
ähnlich (Menüpunkte in doppelt verketteter Liste, Tastatur im 
Zeigerarray, usw), allerdings sind die Menüebenen streng hierarchisch 
dem jeweils aufrufenden Menü untergeordnet, es gibt keinen Rückzeiger, 
der aus dem Untermenü auf das aufrufende Menü zurückzeigt.
Da alle Menüeinträge vom gleichen Datentyp sind, gelangt man zum 
gewünschten Untermenü durch rekusiven Aufrauf der (Menü)Startfunktion, 
der der Zeiger auf das gewählte Untermenü übergeben wird. Zur 
übergeordneten Menüebene gelangt man zurück, in dem man die 
Startfunktion einfach verlässt. Der Compiler sorgt für den richtigen 
Ablauf.
Natürlich funktioniert diese Methode nur, wenn der Zeiger auf das 
übergeordnete Menü auf dem Stapel abgelegt wird, pro Menüebene ein 
Zeiger.

mfg

von Ste N. (steno)


Lesenswert?

> Hc Zimmerer
1
extern MENU omu[];

Danke für den Tipp, das ist des Rätsels Lösung! Funktioniert perfekt, 
jetzt kann's ans Eingemachte gehen.

> G. O.
Tatsächlich entstammen 90% der Funktionalität des Menüs deinem Tinykon. 
Dafür ein großes Dankeschön! Vor allem die Funktionszeiger sind genial 
gelöst. Wenn man es erst mal begriffen hat, extrem Übersichtlich und 
Wartungsfreundlich :-) Allerdings möchte ich in der Main() mehrere 
Prozesse abarbeiten, also habe ich es an meine Bedürfnisse angepasst. Es 
ist ja im Prinzip nur ein Zeiger mehr! Dadurch spart man sich aber die 
Rekusivität. Die Menüfunktion wird nur bei Bedarf aufgerufen und kehrt 
in die Main() zurück.

MfG

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.