www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Probleme mit Pointern und Strings


Autor: Flo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,
Ich habe auf einem ATmega 64 ein Menüsystem implementiert, bestehend aus 
structs, die einen Pointer auf ihre unter-structs haben.
Das ganze wird auf einem LCD dargestellt und man kann in den Menüs 
navigieren.

Mittlerweile ist das Menü ziemlich umfangreich und ich bekomme Probleme 
mit den strings. Wenn ich in manche Untermenüs gehe, zeigt das LCD nur 
wilde Zeichen. Es liegt nicht am ATmega64, ich habe schon andere 
probiert.
Ich denke, dass es ein Problem mit den Speicherbereichen gibt, da ich 
die Größe der einzelnen structs mit ihren Pointern nicht definiere. 
Jedes struct enthält ja wieder Pointer und ich fürchte, dass der 
Speicherbereich dafür nicht explizit deklariert wird und dadurch von 
anderem Code überschrieben.

Vielleicht liege ich auch total falsch. Auf jeden Fall brauche ich eine 
Lösung :)

Ich habe ein bisschen Code extrahiert, damit man sieht, wie ichs mache:

struct Menu {
  char *Name;
  struct Menu *Menus[8];
  struct Menu *ParentMenu;
  uint8_t MenuCount;
  Function function;
} Menu;

typedef enum {
  An,
  Aus,
  Rot,
  Blau,
} Function;

// Allgemeine Untermenüs (mehrfach verwendet)
struct Menu Switch[2];
Switch[0].Name = "An";
Switch[0].MenuCount = 0;
Switch[0].function = An;
Switch[1].Name = "Aus";
Switch[1].MenuCount = 0;
Switch[1].function = Aus;

struct Menu Color[2];
Color[0].Name = "Rot";
Color[0].MenuCount = 0;
Color[0].function = Rot;
Color[1].Name = "Blau";
Color[1].MenuCount = 0;
Color[1].function = Blau;

// Ebene 1 Menüs
struct Menu Haus;

// Ebene 2 Menüs
struct Menu Haus_Tuer;
struct Menu Haus_Fenster;

// Ebene 2 zu Ebene 1 zuweisen
Haus.Menus[0] = &Haus_Tuer;
Haus.Menus[1] = &Haus_Fenster;
Haus.MenuCount = 2;


Haus_Tuer.Name = "Haustuer";
Haus_Tuer.MenuCount = 2;

// Ebene 3 zu Ebene 2 zuweisen
Haus_Tuer.Menus[0] = &Switch;
Haus_Tuer.Menus[0]->Name = "Schalter";
Haus_Tuer.Menus[0]->MenuCount = 2;
Haus_Tuer.Menus[0]->Menus[0] = &Switch[0];
Haus_Tuer.Menus[0]->Menus[1] = &Switch[1];

// Ebene 3 zu Ebene 2 zuweisen
Haus_Tuer.Menus[1] = &Color;
Haus_Tuer.Menus[1]->Name = "Farbe";
Haus_Tuer.Menus[1]->MenuCount = 2;
Haus_Tuer.Menus[1]->Menus[0] = &Color[0];
Haus_Tuer.Menus[1]->Menus[1] = &Color[1];


Haus_Fenster.Name = "Haustuer";
Haus_Fenster.MenuCount = 2;

// Ebene 3 zu Ebene 2 zuweisen
Haus_Fenster.Menus[0] = &Switch;
Haus_Fenster.Menus[0]->Name = "Switch";
Haus_Fenster.Menus[0]->MenuCount = 2;
Haus_Fenster.Menus[0]->Menus[0] = &Switch[0];
Haus_Fenster.Menus[0]->Menus[1] = &Switch[1];

// Ebene 3 zu Ebene 2 zuweisen
Haus_Fenster.Menus[1] = &Color;
Haus_Fenster.Menus[1]->Name = "Farbe";
Haus_Fenster.Menus[1]->MenuCount = 2;
Haus_Fenster.Menus[1]->Menus[0] = &Color[0];
Haus_Fenster.Menus[1]->Menus[1] = &Color[1];


// Ebene 0 Menüs
struct Menu MainMenu;
MainMenu.MenuCount = 1;
MainMenu.Name = "MAIN";

// Ebene 1 zu Ebene 0 zuweisen
MainMenu.Menus[0] = &Haus;


Vielen Dank schon einmal!
Grüße
Flo

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Ansatz sieht gut aus. Erste Zeile, die mir komisch vorkommt:
Haus_Tuer.Menus[0] = &Switch;

Hier würd ich nochmal drüber nachdenken...

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, jetzt habe ich verstanden, was du damit anstellen wolltest:
// Allgemeine Untermenüs (mehrfach verwendet)

und genau das mit dem Mehrfachverwenden geht nicht, außer

(a) du kopierst an der entsprechenden Stelle die Sachen um, oder
(b) du verwendest die Vorlage wirklich nur in der untersten Ebene.

Letzteres hast du offensichtlich vorgehabt, allerdings kann das schon 
durch den Zeiger ParentMenu nicht mehr funktionieren. Wie du vermutet 
hast, wird das erste um die fehlenden Daten ergänzte Untermenü 
überschrieben, sobald du das zweite versorgst. Auch sonst stecken noch 
ein paar Ungereimtheiten drin.

Eins steht aber fest:

du wirst dich aber entweder vom Schablonenkonzept verabschieden müssen, 
oder deine Datenstrukturen so umbauen, daß die Untermenüs in letzter 
Ebene wirklich identisch bleiben können (dann muß dein Code ohne 
ParentMenu-Zeiger auskommen), oder aber bei der Initialisierung ein paar 
memcpys einbauen müssen.

Autor: Flo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Danke für die Antwort, aber ich stimme Dir nicht ganz zu.

Ich weise einem Menü ein Untermenü zu und speichere gleichzeitig im 
Untermenü den Zeiger auf das Menü, damit ich wieder zurück komme.
Aus meinem Verständnis sollte das mehrfache zuweisen problemlos gehen, 
da ich  nur den Pointer übergebe.
Bisher ging es auch einwandfrei, nur je umfangreicher das Menü wird, 
umso öfter tritt der Fehler auf.
Durch ein paar Tricks konnte ich das bisher lösen, aber jetzt kam ich 
nicht weiter.
Ich denke, es liegt daran, dass der Compiler nicht weiss, wie lang der 
Text wird und wieviele Untermenüs ich in einem Menü speichern will.
Die Anzahl der Untermenüs habe ich dann auf 8 begrenzt.
Gerade eben haben ich aus dem
char *Name;
folgendes gemacht:
char Name[9];
und kopiere nun die strings mit strcpy rein. Damit läuft das Menü wieder 
sauber.
Der Compiler sollte jetzt keine Variable mit unbekannter Länge mehr 
haben und kann so den Platz allokieren.
Ich hoffe, dass es ab nun funktioniert, sonst melde ich mich wieder :)

Grüße
Flo

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Flo wrote:
#> Ich denke, es liegt daran, dass der Compiler nicht weiss, wie lang 
der
> Text wird

Ooch. Character Zählen ist für den Compiler eine der leichtesten
Übungen.

> Gerade eben haben ich aus dem
> char *Name;
> folgendes gemacht:
> char Name[9];
> und kopiere nun die strings mit strcpy rein.

Damit hast du aber die Speicherauslastung nur noch verschlimmert.
Deine ursprüngliche Lösung war schon ok. Wenns noch weniger
Speicherverbrauch sein soll, dann muss man die Texte in den
Flash auslagern.

> Der Compiler sollte jetzt keine Variable mit unbekannter Länge mehr
> haben und kann so den Platz allokieren.

Die hatte er auch so nicht.
Die Texte sind sog. String Literale (also Konstante), die der Compiler
im SRAM unterbringt. In den Strukturen hast du nur noch Pointer darauf.
Ist doch in Ordnung so.

PS: durch die Änderung hast du die Texte nicht aus dem SRAM verbannt,
die sind immer noch dort (irgendwo müssen sie ja sein). Allerdings
werden sie beim Hochfahren des Programmes im Speicher einmal
umkopiert, nämlich in die Arrays. Daher residieren die Texte jetzt
2 mal im Speicher :-) Einmal als String-Literal und einmal als
Kopie in den Arrays.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich denke, dass es ein Problem mit den Speicherbereichen gibt, da ich
> die Größe der einzelnen structs mit ihren Pointern nicht definiere.
> Jedes struct enthält ja wieder Pointer und ich fürchte, dass der
> Speicherbereich dafür nicht explizit deklariert wird und dadurch von
> anderem Code überschrieben.

Da brauchst du keine Angst haben.
So wie du das gemacht hast, ist das schon in Ordnung.

Das einzige: Schmeiss den Parent Pointer raus. So wie du
deine Strukturen benutzt, ist der sinnlos. Der Parent-Pointer
ergibt sich sowieso dynamisch, durch die Aufrufabfolge der
Menüs. Die brauchst du nicht in den Strukturen speichern.

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.