mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik struct / pointer => Verständnisproblem


Autor: Christoph Borowski (cborowski)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hall zusammen,

ich baue mir gerade in C ein LCD-Menü auf Basis von struct zusammen. An 
einer Stelle habe ich Probleme, die ich auch mit Hilfe der Suche & 
Google nicht lösen kann. Offensichtlich habe ich noch nicht das richtige 
Verständnis von struct/pointern :(

Mein struct sieht wie folgt aus und deklariert gleichzeitig ein Menü (in 
dem Fall ist der Funktinspointer NULL und subMenueCount/subMenues 
gefüllt) oder ein Menüpunkt (Funktinspointer verweist auf eine Funktion, 
subMenueCount/subMenues sind nicht gesetzt):
typedef void (*fp)(void);

typedef struct menue {
  char* menueName;
  fp pFunction;
  uint8_t subMenueCount;
        // 1 Frage: Wie deklariere ich ein Array von 
        // MENUE-Pointern der Größe 3?
  struct menue* subMenues[3];
  struct menue* parentMenu;
} MENUE;

Nun versuche ich mein Menü zu initialisieren und verwende hierzu zwei 
Funktionen:
void init_menu(void) {
  MENUE* m1 = createMenue("GPS", &operateInGPSMode, 0, NULL);
  
  MENUE* m21 = createMenue("Create waypoint route", 
                                 &createWaypointRoute, 0, NULL);
  MENUE* m22= createMenue("Load waypoint route", 
                                 &loadWaypointRoute, 0, NULL);
  MENUE* m23 = createMenue("Edit waypoint route", 
                                 &editWaypointRoute, 0, NULL);

  MENUE g2[3] = {m21, m22, m23};
        // 2 Frage: Wie übergebe ich ein Pointer auf mein 
        // MENUE-Pointer-Array?
  MENUE* m2 = createMenue("Waypoint menu", NULL, 3, g2);
  
  MENUE g1[2] = {m1, m2};
  MENUE* m0 = createMenue("Main menu", NULL, 2, g1);

  (*m2).parentMenu = m0;
}

// 3 Frage: Wie deklariere ich den Parameter für meinen übergebenen
// Pointer auf mein MENUE-Pointer-Array (letzter Parameter)?
MENUE* createMenue(char* menueName, fp pFunction, 
        uint8_t subMenueCount, MENUE* subMenues) {
  MENUE* newMenue = (MENUE*) malloc(sizeof(MENUE));
  (*newMenue).menueName = menueName;
  (*newMenue).pFunction = pFunction;
  (*newMenue).subMenueCount = subMenueCount;
        // 4 Frage: Wie weise ich das ganze hier zu?
  (*newMenue).subMenues = subMenues;
}

Innerhalb des Sourcecodes habe ich Fragen eingefügt, die mein Problem an 
den diversen Stellen beschreiben. Im Grunde habe ich Probleme mit einem 
Array von MENUE-Pointern, d. h. wie deklariere ich das ganze, wie 
übergebe ich sowas an besten an eine Funktion, wie weise ich sowas zu 
etc. Habe vieles ausprobiert, aber der Compiler hat immer gemeckert.

Kann mir jemand hierzu Links, Ratschläge, Anregungen o. Tipps geben?

Im voraus schon mal Danke...
Christoph

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Christoph,
die 1. Frage hast Du wohl selbst richtig beantwortet! Hier dreht es 
sich im Wesentlichen um Dinge wie Vorwärts-Deklaration u.ä.

Die 2. Frage bezieht sich anscheinend auf das g2[3]. Das stimmt wohl 
auch, wie Du es gelöst hast.

Die 3. Frage: Ebenfalls Volltreffer!

Die 4. Frage genauso!

Die 5. Frage sollte jetzt kommen, statt des "der Compiler hat immer 
gemeckert"! Sie lautet: "Was bedeuten die folgenden Fehlermeldungen des 
Compilers?".

Ich lese jetzt mal Kaffeesatz: Der Compiler beschwert sich, daß hier 
lokalen Variablen zwar Werte zugewiesen werden, aber diese Werte nicht 
benutzt werden.

Damit komme ich zu Deinem vermutlichen Problem:
Der unterschiedliche Geltungsbereich der verschiedenen Klassen von 
Variablen ist Dir wohl unbekannt. Diese Kenntnis gehört allerdings bei 
jeder Programmiersprache zum absoluten Basiswissen.

Ein Tip:
Nimm ein gutes C-Lehrbuch und lerne C! Programmiersprachen lernt man 
am besten (meine persönliche Erfahrung) von der Theorie her zur Praxis 
hin und nicht durch "Ausprobieren". Das ist der Unterschied zu 
natürlichen Sprachen, die man genau andersherum lernt.

Grüße
Bernhard

P.S. Deine Frage schreckt allein durch ihren Umfang viele vom Antworten 
ab.

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß allerdings auch nicht, wie Du diese Anfrage hättest kürzer 
"bringen" können.

Grüße
Bernhard

Autor: Christoph Borowski (cborowski)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

erst einmal Danke für die Antwort(en).

Der Compiler meldet für die folgende Zeile (mit << markiert) in
MENUE* createMenue(char* menueName, fp pFunction, 
        uint8_t subMenueCount, MENUE* subMenues) {
  MENUE* newMenue = (MENUE*) malloc(sizeof(MENUE));
  (*newMenue).menueName = menueName;
  (*newMenue).pFunction = pFunction;
  (*newMenue).subMenueCount = subMenueCount;
  (*newMenue).subMenues = subMenues; // << error laut compiler
}

die folgende Meldung:

main.c:126: error: incompatible types in assignment

Hier noch mal der zugehörige struct:
typedef struct menue {
  char* menueName;
  fp pFunction;
  uint8_t subMenueCount;
  struct menue* subMenues[3];
  struct menue* parentMenu;
} MENUE;

Es gibt also keine Probleme bzgl. der Gültigkeitsbereiche von Variablen. 
Das Thema Gültigkeitsbereiche ist mir auch klar. Zur Info... ich 
entwickle beruflich seit ca. 9 Jahren in Java. Aus diesem Grund fällt 
mir die Arbeit mit Pointern momentan schwer bzw. ist noch ziemlich 
ungewohnt.

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Christoph,
jetzt lichtet sich der Nebel!

Das   (*newMenue).subMenues = subMenues; // << error laut compiler

sollte werden:
   (*newMenue).subMenues[0] = subMenues[0];
   (*newMenue).subMenues[1] = subMenues[1];
   (*newMenue).subMenues[2] = subMenues[2];

U.U. ginge das Ganze auch dann, wenn Du folgendes tust:

statt MENUE* createMenue(char* menueName, fp pFunction,
        uint8_t subMenueCount, MENUE* subMenues) {

mache mal MENUE* createMenue(char* menueName, fp pFunction,
        uint8_t subMenueCount, MENUE subMenues[3]) {

Der generierte Aufruf-Code wäre identisch, aber der Fehler müßte 
verschwinden.

Da liegt - denke ich - einer der Unterschiede zwischen Java und C(++).

Es zahlt sich wirklich aus, an eine neue Programmiersprache von der 
Theorie her heranzugehen, anstatt zu glauben "X ist etwa wie Y, also 
übertrage ich meine Erfahrungen von Y nach X".

Ich habe den Übergang C ---> C++ bzw. C(++) ---> Java als durchaus mit 
Fallen gespickt empfunden - nicht den OO-Teil, sondern die kleinen 
Feinheiten, wie z.B. die compiler-interne Umsetzung von "unsigned char" 
nach "signed integer" und zurück. Da liegen zwischen C und C++ u.U. 
Welten!

Viel Erfolg mit C!
Bernhard

Autor: Christoph Borowski (cborowski)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, das ganze funktioniert jetzt und ich wollte an dieser Stelle den 
Code zeigen, falls es jemanden interessiert. Danke an Bernhard, dessen 
letzter Tipp zur Lösung geführt hat. Ehrlich gesagt verstehe ich wie die 
Lösung funktioniert, aber nicht, wieso der vorherige Ansatz nicht 
funktioniert hat. Da werde ich mir also noch ein gutes C-Buch anschaffen 
:)

Wie auch immer, weiter unten der funktionierende Code.

Gruß
Christoph
typedef void (*fp)(void);

typedef struct menue {
  char* menueName;
  fp pFunction;
  uint8_t subMenueCount;
  struct menue* parentMenu;
  struct menue* subMenues[3];
} MENUE;

// currentMenue ist der Pointer auf das aktuell anzuzeigende Menü
MENUE* currentMenue = NULL;

/**
 *
 */
void init_menu(void) {
  MENUE* m1 = createMenue("GPS", &operateInGPSMode, 0, NULL);
  
  MENUE* m21 = createMenue("Create waypoint route", &createWaypointRoute, 0, NULL);
  MENUE* m22= createMenue("Load waypoint route", &loadWaypointRoute, 0, NULL);
  MENUE* m23 = createMenue("Edit waypoint route", &editWaypointRoute, 0, NULL);
  MENUE* g2[3] = {m21, m22, m23};
  MENUE* m2 = createMenue("Waypoint menu", NULL, 3, g2);
  
  MENUE* g1[2] = {m1, m2};
  MENUE* m0 = createMenue("Main menu", NULL, 2, g1);
  
  (*m0).parentMenu = m0;
  (*m2).parentMenu = m0;
  
  currentMenue = m0;
}

/**
 *
 */
MENUE* createMenue(char* menueName, fp pFunction, 
  uint8_t subMenueCount, MENUE* subMenues[]) {
  MENUE* newMenue = (MENUE*) malloc(sizeof(MENUE));
  (*newMenue).menueName = menueName;
  (*newMenue).pFunction = pFunction;
  (*newMenue).subMenueCount = subMenueCount;
  // Einhängen von Untermenüpunkten in einer Schleife,
  // weil ein Menü zwischen einem und drei Untermenüpunkte
  // haben kann (angegeben durch subMenueCount).
  for (int i=0; i<subMenueCount; i++) {
    (*newMenue).subMenues[i] = subMenues[i];
  }
  return newMenue;
}

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christoph Borowski wrote:
> Ehrlich gesagt verstehe ich wie die
> Lösung funktioniert, aber nicht, wieso der vorherige Ansatz nicht
> funktioniert hat.
Weil man in C ein Array nicht als Ganzes zuweisen kann. Es gibt in C 
keinen Datentyp "Array" oder "String", weshalb man die einzelnen 
Elemente immer einzeln behandeln muss.

> Da werde ich mir also noch ein gutes C-Buch anschaffen
> :)
Das ist sicher von Vorteil... Nicht gleich entmutigen lassen.

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.