mikrocontroller.net

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


Autor: Steffen N. (steno)
Datum:

Bewertung
0 lesenswert
nicht 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.

#define ANZAHL_TASTEN 4

/*grundlegender datentyp */
typedef struct m{ struct m  *upmen;            /* Menü eine Ebene höher, falls vorhanden */
                  struct m  *prev;            /* Das vorhergehende Menü dieser Ebene */
                  struct m  *next;            /* Das nächste Menü dieser Ebene */
                  struct m  *submen;          /* Untermenü, falls vorhanden */
                  char      *mtxt;            /* Menütext */
                  void      (*mfun)(struct m**);    /* Menüfunktion, falls vorhanden */
                  char      *mdat;            /* Menüdaten */
                                              /* Die diesem Menüpunkt zugeordneten Tastenfunktionen */
                  void      (*tastfun[ANZAHL_TASTEN])(struct m**);  
                }MENU;

// Submenü 1            
MENU sm1[]={  {&omu[0], &sm1[0], &sm1[1], NULL, "Menu 1.1", dumfun, NULL, {curup, curdwn, upmen, dumfun}},
              {&omu[0], &sm1[0], &sm1[2], NULL, "Menu 1.2", dumfun, NULL, {curup, curdwn, upmen, dumfun}},
              {&omu[0], &sm1[1], &sm1[3], NULL, "Menu 1.3", dumfun, NULL, {curup, curdwn, upmen, dumfun}},
              {&omu[0], &sm1[2], &sm1[3], NULL, "Menu 1.4", dumfun, NULL, {curup, curdwn, upmen, dumfun}}};

// Oberste Menüebene
MENU omu[]={  {NULL, &omu[0], &omu[1],  sm1, "Menu 1  ", dumfun, NULL, {curup, curdwn, dumfun, submen}},
              {NULL, &omu[0], &omu[2], NULL, "Menu 2  ", dumfun, NULL, {curup, curdwn, dumfun, dumfun}},
              {NULL, &omu[1], &omu[3], NULL, "Menu 3  ", dumfun, NULL, {curup, curdwn, dumfun, dumfun}},
              {NULL, &omu[2], &omu[3], NULL, "Menu 4  ", dumfun, NULL, {curup, curdwn, dumfun, dumfun}}};


/* Das vorhergehende Menü dieser Ebene */
void curup(MENU **men)
{
  MENU *m;
  m = (*men)->prev;
  if (m)
    *men = m;
}

/* Das nächste Menü dieser Ebene */
void curdwn(MENU **men)
{
  MENU *m;
  m = (*men)->next;
  if (m)
    *men = m;
}

/* Untermenü */
void submen(MENU **men)
{
  MENU *m;
  m = (*men)->submen;
  if (m)
    *men = m;
}

/* Menü eine Ebene höher */
void upmen(MENU **men)
{
  MENU *m;
  m = (*men)->upmen;
  if (m)
    *men = m;
}

/* Displaytext anzeigen */
void display (MENU **men)
{
  sendStringSPI((*men)->mtxt);
}


MENU *zeile;

int main(void)
{
  zeile = omu;

  while (1)
  {
    taste = get_key();
    if(taste)
    {
      zeile->tastfun[taste-1](&zeile);
      zeile->mfun(&zeile);
      display(&zeile);
    }
  }
  return 0;
}


Mein Problem ist nun konkret, das ich im Array sm1[] auf om[] verweisen 
möchte, welches aber zu diesem Zeitpunkt noch gar nicht existiert.
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

Autor: Hc Zimmerer (mizch)
Datum:

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

Autor: G. O. (aminox86)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Steffen N. (steno)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hc Zimmerer
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.