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


von Christoph B. (cborowski)


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):
1
typedef void (*fp)(void);
2
3
typedef struct menue {
4
  char* menueName;
5
  fp pFunction;
6
  uint8_t subMenueCount;
7
        // 1 Frage: Wie deklariere ich ein Array von 
8
        // MENUE-Pointern der Größe 3?
9
  struct menue* subMenues[3];
10
  struct menue* parentMenu;
11
} MENUE;

Nun versuche ich mein Menü zu initialisieren und verwende hierzu zwei 
Funktionen:
1
void init_menu(void) {
2
  MENUE* m1 = createMenue("GPS", &operateInGPSMode, 0, NULL);
3
  
4
  MENUE* m21 = createMenue("Create waypoint route", 
5
                                 &createWaypointRoute, 0, NULL);
6
  MENUE* m22= createMenue("Load waypoint route", 
7
                                 &loadWaypointRoute, 0, NULL);
8
  MENUE* m23 = createMenue("Edit waypoint route", 
9
                                 &editWaypointRoute, 0, NULL);
10
11
  MENUE g2[3] = {m21, m22, m23};
12
        // 2 Frage: Wie übergebe ich ein Pointer auf mein 
13
        // MENUE-Pointer-Array?
14
  MENUE* m2 = createMenue("Waypoint menu", NULL, 3, g2);
15
  
16
  MENUE g1[2] = {m1, m2};
17
  MENUE* m0 = createMenue("Main menu", NULL, 2, g1);
18
19
  (*m2).parentMenu = m0;
20
}
21
22
// 3 Frage: Wie deklariere ich den Parameter für meinen übergebenen
23
// Pointer auf mein MENUE-Pointer-Array (letzter Parameter)?
24
MENUE* createMenue(char* menueName, fp pFunction, 
25
        uint8_t subMenueCount, MENUE* subMenues) {
26
  MENUE* newMenue = (MENUE*) malloc(sizeof(MENUE));
27
  (*newMenue).menueName = menueName;
28
  (*newMenue).pFunction = pFunction;
29
  (*newMenue).subMenueCount = subMenueCount;
30
        // 4 Frage: Wie weise ich das ganze hier zu?
31
  (*newMenue).subMenues = subMenues;
32
}

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

von Bernhard R. (barnyhh)


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.

von Bernhard R. (barnyhh)


Lesenswert?

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

Grüße
Bernhard

von Christoph B. (cborowski)


Lesenswert?

Hallo,

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

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

die folgende Meldung:

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

Hier noch mal der zugehörige struct:
1
typedef struct menue {
2
  char* menueName;
3
  fp pFunction;
4
  uint8_t subMenueCount;
5
  struct menue* subMenues[3];
6
  struct menue* parentMenu;
7
} 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.

von Bernhard R. (barnyhh)


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

von Christoph B. (cborowski)


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
1
typedef void (*fp)(void);
2
3
typedef struct menue {
4
  char* menueName;
5
  fp pFunction;
6
  uint8_t subMenueCount;
7
  struct menue* parentMenu;
8
  struct menue* subMenues[3];
9
} MENUE;
10
11
// currentMenue ist der Pointer auf das aktuell anzuzeigende Menü
12
MENUE* currentMenue = NULL;
13
14
/**
15
 *
16
 */
17
void init_menu(void) {
18
  MENUE* m1 = createMenue("GPS", &operateInGPSMode, 0, NULL);
19
  
20
  MENUE* m21 = createMenue("Create waypoint route", &createWaypointRoute, 0, NULL);
21
  MENUE* m22= createMenue("Load waypoint route", &loadWaypointRoute, 0, NULL);
22
  MENUE* m23 = createMenue("Edit waypoint route", &editWaypointRoute, 0, NULL);
23
  MENUE* g2[3] = {m21, m22, m23};
24
  MENUE* m2 = createMenue("Waypoint menu", NULL, 3, g2);
25
  
26
  MENUE* g1[2] = {m1, m2};
27
  MENUE* m0 = createMenue("Main menu", NULL, 2, g1);
28
  
29
  (*m0).parentMenu = m0;
30
  (*m2).parentMenu = m0;
31
  
32
  currentMenue = m0;
33
}
34
35
/**
36
 *
37
 */
38
MENUE* createMenue(char* menueName, fp pFunction, 
39
  uint8_t subMenueCount, MENUE* subMenues[]) {
40
  MENUE* newMenue = (MENUE*) malloc(sizeof(MENUE));
41
  (*newMenue).menueName = menueName;
42
  (*newMenue).pFunction = pFunction;
43
  (*newMenue).subMenueCount = subMenueCount;
44
  // Einhängen von Untermenüpunkten in einer Schleife,
45
  // weil ein Menü zwischen einem und drei Untermenüpunkte
46
  // haben kann (angegeben durch subMenueCount).
47
  for (int i=0; i<subMenueCount; i++) {
48
    (*newMenue).subMenues[i] = subMenues[i];
49
  }
50
  return newMenue;
51
}

von Johannes M. (johnny-m)


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.

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.