Hallo, ich versuche mir gerade ein Menü zu erstellen, davor will ich aber diesen Code verstehen lernen, ich komme besten willen nicht darauf für was der Pointer *menu_strings[MENU_ITEMS] gedacht ist ? Gruß #define MENU_ITEMS 4 char *menu_strings[MENU_ITEMS] = { "First Line", "Second Item", "3333333", "abcdefg" }; uint8_t menu_current = 0; uint8_t menu_redraw_required = 0; uint8_t last_key_code = KEY_NONE; void drawMenu(void) { uint8_t i, h; u8g_uint_t w, d; u8g.setFont(u8g_font_6x13); u8g.setFontRefHeightText(); u8g.setFontPosTop(); h = u8g.getFontAscent()-u8g.getFontDescent(); w = u8g.getWidth(); for( i = 0; i < MENU_ITEMS; i++ ) { d = (w-u8g.getStrWidth(menu_strings[i]))/2; u8g.setDefaultForegroundColor(); if ( i == menu_current ) { u8g.drawBox(0, i*h+1, w, h); u8g.setDefaultBackgroundColor(); } u8g.drawStr(d, i*h, menu_strings[i]); } } void updateMenu(void) { if ( uiKeyCode != KEY_NONE && last_key_code == uiKeyCode ) { return; } last_key_code = uiKeyCode; switch ( uiKeyCode ) { case KEY_NEXT: menu_current++; if ( menu_current >= MENU_ITEMS ) menu_current = 0; menu_redraw_required = 1; break; case KEY_PREV: if ( menu_current == 0 ) menu_current = MENU_ITEMS; menu_current--; menu_redraw_required = 1; break; } } void setup() { // rotate screen, if required // u8g.setRot180(); uiSetup(); // setup key detection and debounce algorithm menu_redraw_required = 1; // force initial redraw } void loop() { uiStep(); // check for key press if ( menu_redraw_required != 0 ) { u8g.firstPage(); do { drawMenu(); } while( u8g.nextPage() ); menu_redraw_required = 0; } updateMenu(); // update menu bar }
D. Chung schrieb: > ich komme besten willen nicht darauf > für was der Pointer *menu_strings[MENU_ITEMS] Das ist nicht ein Pointer, das ist ein Array aus Pointern.
Wie Rufus schon sagte ist menu_strings ein Array von Pointern. Genauer ein Array von char Pointer und ein char Pointer ist quasi ein string. In dem von dir gezeigten Code werden hier die verschiedenen Menüeinträge abgespeichert.
Ja wenn ich noch dabei bin hab ich mich falsch ausgedrückt, aber warum das ganze ?Wie Pointer funktionieren das versteh ich,...Vill könntest du mir das erklären wieso ? Gruß
Um das Ganze möglichst flexibel zu gestalten. Kein Mensch will die Menüeinträge wild verteilt in den Code werfen und Konstruktion wie
1 | for( i = 0; i < MENU_ITEMS; i++ ) |
2 | { |
3 | if(i == 0) |
4 | { |
5 | d = (w-u8g.getStrWidth("First Line"))/2; |
6 | u8g.drawStr(d, i*h, "First Line"); |
7 | } |
8 | if(i == 1) |
9 | { |
10 | d = (w-u8g.getStrWidth("Second Item"))/2; |
11 | u8g.drawStr(d, i*h, "Second Item"); |
12 | } |
13 | // usw... |
14 | } |
bauen. Bis aus den anzuzeigenden Text ist der Code zum Menüträge anzeigen offensichtlich identisch. Also packt man alle Einträge in ein Array und arbeitet dies ab.
Danke für die schnellen Antworten, ja das mit dem Array ist mir ja klar aber mich stört der Stern ... es würde doch auch ohne Pointer gehen. Ich erkenne den Sinn dahinter nicht in diesem Beispiel, das ist mein Problem würde jetzt menu_strings[MENU_ITEMS] = { "First Line", "Second Item",... dort stehen müsste es doch auch funktionieren ?
D. Chung schrieb: > Danke für die schnellen Antworten, ja das mit dem Array ist mir ja klar > aber mich stört der Stern ... es würde doch auch ohne Pointer gehen. Ich > erkenne den Sinn dahinter nicht in diesem Beispiel, das ist mein Problem > > würde jetzt > > menu_strings[MENU_ITEMS] = { "First Line", "Second Item",... > > dort stehen müsste es doch auch funktionieren ? Nein. Das würde der Compiler mit einer Fehlermeldung wegen eines fehlenden Datentyps quittieren. Schriebst Du jetzt, aber: char menu_strings[MENU_ITEMS] = { "First Line", "Second Item",... so erhälst Du damit ein Array, das nur aus einem MENU_ITEMS langem String besteht, versuchst aber das Array mit mehreren Strings zu initialisieren. Nimm's mir bitte nicht übel, aber das ist das Paradebeispiel für eine Gelegenheit, auf C-Bücher zu verweisen.
Erstmal geht menu_strings[MENU_ITEMS] alleine sowieso nicht. Da fehlt noch der Typ, also wenn dann char menu_strings[MENU_ITEMS]. Und nein so funktioniert das nicht. Wenn du das so machst hast du ein Array in dem du MENU_ITEMS chars also einzelne Zeichen speichern möchtest. Tatsächlich möchtest du aber MENU_ITEMS strings in dem Array Speichern. Hier noch einige Beispiele zu strings:
1 | // Array aus chars. Text kann verändert werden |
2 | char str[] = "Bla Blupp"; |
3 | |
4 | // Pointer zu char. Der Text kann in diesem Fall nicht verändert werden weil es von einem string Literal initialisiert wurde |
5 | char* str = "Bla Blupp"; |
6 | |
7 | // Array von char Pointern. Text kann auch nicht verändert werden, siehe oben |
8 | char* str[] = {"Bla", "Blupp"}; |
Ja der Datentyp muss natürlich dabei sein. @Bitflüsterer Ich glaub langsam komme ich dahinter bzw. hab wohl was übersehene char menu_strings[] = { "First Line", "Second Item"} würde doch ein Array aus 2 char s bilden. char menu_strings[1]-> First Line char menu_strings[2]-> Second Item Würde eine Zahl darin stehen wie char menu_strings[2] = { "First Line", "Second Item"} würde das heißen das in menu_strings[2] -> "First Line", "Second Item" drin stehen würde ? Und bei #define MENU_ITEMS 4 char *menu_strings[MENU_ITEMS] = { "First Line", "Second Item", "3333333", "abcdefg" }; Steht in char *menu_strings[1] -> First Line char *menu_strings[2] -> Second Item char *menu_strings[3] -> 3333333 char *menu_strings[4] -> abcdefg Ich hoffe ich bin auf dem richtigen Pferd ?
> Ich hoffe ich bin auf dem richtigen Pferd ?
Nein. Durchaus nicht. Bitte lies ein C-Buch. :-)
Ich glaube du brauchst tatsächlich ein gutes C Buch... Wenn du ein Array definierst besagt die Zahl in den eckigen Klammern wie viele Elemente dein Array haben soll. Man kann die Zahl auch weglassen dann kriegt das Array so viele Elemente wie du in den runden {} Klammern liefest. Wenn du später auf das Array zugreifst dann gibst du in den eckigen Klammern an auf welches Element zu zugreifen willst. Die Zählung beginnt auch bei 0 und nicht bei 1 wie in deinem Beispiel oben.
sebi707 schrieb: > Ich glaube du brauchst tatsächlich ein gutes C Buch... > > Wenn du ein Array definierst besagt die Zahl in den eckigen Klammern wie > viele Elemente dein Array haben soll. Man kann die Zahl auch weglassen > dann kriegt das Array so viele Elemente wie du in den runden {} Klammern > liefest. Wenn du später auf das Array zugreifst dann gibst du in den > eckigen Klammern an auf welches Element zu zugreifen willst. Die Zählung > beginnt auch bei 0 und nicht bei 1 wie in deinem Beispiel oben. Sebi707 @ Hä das selbe hab ich doch gerade gemeint ? Bis auf das mit der 0. Beispiel char a=menu_strings[1] in a steht dann Second Item?
Nein. In einem char kannst du keinen kompletten String speichern. Du brauchst entweder ein Array oder einen Pointern. So muss das aussehen: char* a=menu_strings[1]; Dann steht da drin "Second Item".
D. Chung schrieb: > char a=menu_strings[1] > > in a steht dann Second Item? Nein. Ein char ist ein einzelnes Zeichen.
sebi707 schrieb: > Nein. In einem char kannst du keinen kompletten String speichern. Du > brauchst entweder ein Array oder einen Pointern. So muss das aussehen: > char* a=menu_strings[1]; > > Dann steht da drin "Second Item". Weil ein char 8 bit lange ist... Sollte ich eigentlich wissen, bin schon zulange davon weg sry.
Das hier
1 | char *menu_strings[MENU_ITEMS] = { "First Line", "Second Item", "3333333", "abcdefg" } |
baut im Speicher diese Struktur auf
1 | menu_strings |
2 | +-------+ +-+-+-+-+-+-+-+-+-+-+--+ |
3 | | o---------------->|F|i|r|s|t| |L|i|n|e|\0| |
4 | +-------+ +-+-+-+-+-+-+-+-+-+-+--+ |
5 | | o-----------+ |
6 | +-------+ | +-+-+-+-+-+-+-+-+-+-+-+--+ |
7 | | o-------+ +------>|S|e|c|o|n|d| |I|t|e|m|\0| |
8 | +-------+ | +-+-+-+-+-+-+-+-+-+-+-+--+ |
9 | | o-----+ | |
10 | +-------+ | | +-+-+-+-+-+-+-+--+ |
11 | | +----->|3|3|3|3|3|3|3|\0| |
12 | | +-+-+-+-+-+-+-+--+ |
13 | | +-+-+-+-+-+-+-+--+ |
14 | +-->|a|b|c|d|e|f|g|\0| |
15 | +-+-+-+-+-+-+-+--+ |
Ein Array von Pointern unter dem Namen menu_strings, wobei jeder einzelne der Pointer auf einen Text zeigt. Man hätte natürlich auch ein 2D Array von chars machen können
1 | char menu_strings[4][12] = { "First Line", "Second Item", "3333333", "abcdefg" }; |
2 | |
3 | menu_strings |
4 | +-+-+-+-+-+-+-+-+-+-+-+-+ |
5 | |F|i|r|s|t| |L|i|n|e|\| | |
6 | +-+-+-+-+-+-+-+-+-+-+-+-+ |
7 | |S|e|c|o|n|d| |I|t|e|m|\| |
8 | +-+-+-+-+-+-+-+-+-+-+-+-+ |
9 | |3|3|3|3|3|3|3|\| | | | | |
10 | +-+-+-+-+-+-+-+-+-+-+-+-+ |
11 | |a|b|c|d|e|f|g|\| | | | | |
12 | +-+-+-+-+-+-+-+-+-+-+-+-+ |
das hat aber den 'Nachteil', das alle 'Zeilen' des 2D Arrays gleich lang sein müssen. Was wiederrum Speicherverschwendung bedeutet, wenn gleichzeitig relativ lange und relativ kurze Texte in diesem Array gespeichert werden sollen. Denn die Anzahl der Spalten ist ja über das komplette 2D Array in allen Zeilen gleich und muss sich logischerweise am längsten zu speichernden Text orientieren. In der Lösung mit dem Pointer Array brauch ich das nicht. Die Texte sind ja unabhängig vom Array. Das Array organisiert die nur insofern, dass es die Verweise enthält, wo die tatsächlichen Texte gespeichert sind. Und die können unabhängig voneinander beliebig lang sein.
:
Bearbeitet durch User
Okay danke, das leuchtet ein. Jetzt wenn ich dieses Thema weiter ausbauen will und noch Sub Menü s erzeugen will hätte ich anfangs das Array um eine Dimension erweitert, dann war mein Gedanke dazu das ich Plätze im Array verschwende, weil ich unterschiedliche Sub menues evtl habe... Meine zweite Lösung besteht aus mehreren Switch case bzw genau der Anzahl der main menues, damit wäre ich in der Anzahl der unter Menues variable. Das wird aber irgendwann unübersichtlich denk ich. Jetzt könnte ich mir das auch mit Pointer vorstellen, das wäre die elegantere Lösung oder ?Das wäre dann doch eine Pointer auf Pointer Struktur ? Gruß
:
Bearbeitet durch User
Der ganze Ansatz ist schon zweifelhaft. Denn ein Menü besteht ja nicht
nur aus Texten. Spätestens wenn du noch Submenüs haben willst und ev.
sogar direkt Funktionen an Menüpunkte hängen willst, solltest du mal ein
gutes C Buch konsultieren, welche Möglichkeiten zur Datenstrukturierung
du noch hast. Ein Array ist beileibe nicht alles, was dir an
Möglichkeiten zur Verfügung steht. Da gibt es zb noch die Struktur.
> Das wird aber irgendwann unübersichtlich denk ich.
Im Idealfall hast du EINEN Code, der ein Menü in all seinen Ausprägungen
behandeln kann. Die Daten steuern die Menüabaerbeitung. Der Code
interpretiert nur die Daten in der aufgebauten Datenstruktur. So ein
Design beginnt damit, dass man sich auf Papier mit Bleistift die
Datenstruktur anhand eines konkreten Beispiels aufmalt. Dann sieht man
schon, wie man das ganze strukturiert.
Aber wenn dir das Pointer Array schon kopfzerbrechen bereitet hat,
solltest du dir vielleicht erst mal die Latte nicht so hoch legen, bis
du deine Programmiersprache nicht nur rudimentär beherrscht sondern
tatsächlich mit den Sprachmitteln auch umgehen kannst.
@KHB Danke für die tolle Darstellung. Wie biegen sich die Zeiger, wenn ich keinen linearen Speicher, sondern RAM und ROM getrennt mit gleichem Adressbereich habe?
embedded schrieb: > @KHB > Danke für die tolle Darstellung. Wie biegen sich die Zeiger, wenn ich > keinen linearen Speicher, sondern RAM und ROM getrennt mit gleichem > Adressbereich habe? Im Prinzip genau gleich. Denn in der Darstellung ist das ja uninteressant. Du musst nur im Hinterkopf behalten was in welchem Speicher liegt (kann nicht schaden, wenn man sich das in der Zeichnung markiert) und je nach Compiler dann eben die entpsrechende Umsetzung in den C Code machen. Je nach Compiler ist das unterschiedlich. Bei manchen kommt dann eben zb ein 'const' in die Datenstruktur rein, bei anderen wieder gibt es spezielle Zugriffsfunktionen für zb den ROM Bereich. Aber grundsätzlich fürs Design ist das erst mal recht uninteressant. In der Zeichnung ist ein Pointer nichts anderes als ein Pfeil, der in einem Kästchen anfängt und dessen Spitze irgendwo anders hinzeigt.
Ich hab mir mal Gedanken dazu gemacht, ich denke der Ansatz wäre sehr einfach bezüglich weil ich in einem späteren Switch case die id abfragen kann sollte man zb. in dieser Menü Ebene was abfragen wollen. Strukturen kenne ich noch, das wird aber jetzt eine Struktur der sich wohl ein Array befinden muss struct menu{ const char* Menu_name; // Menue Name int id; // Menue ID,damit ich mich orientieren kann int Number; // Anzahl der Submenues { "Submenue 1, id" //Name des Submenues mit der ID "Submenue .... ...... } } } Das Array würde dann so aussehen menuEntry []={Submenue 1, id} Jetzt stellt sich mir aber die Frage wie mache ich die Anzahl der Array s variable ich habe ja unterschiedlich viele Sub menues menuSet []={SubSet_1, id} menueHome []={SubSet_2, id} .... Wäre der Ansatz okay ? Ich weiß nur gerade einfach nicht wie ich mit dem Array umgehen muss... Gruß
Zum Array wäre mir noch was eingefallen, ich verpacke die arrays wieder in eine Struktur , dann wäre die Anzahl doch variable ? struct menu{ const char* Menu_name; // Menue Name int id; // Menue ID,damit ich mich orientieren kann int Number; // Anzahl der Submenues struct Sub_menue[]; // } } Und dann habe ich eine Struct in dem sich die Arrays finden mit zb dem Namen und wieder der ID Damit hätte ich auch alle Parameter mitgeliefert die ich für ein Menü brauche -Anzahl Submenues damit ich Anfang und Ende kenne. -Id damit ich den Menue abschnitte kenne -Und den Namen zur ausgabe am Display.
:
Bearbeitet durch User
Ich hab das mal runter getippt. void Menues(void){ struct menu{ const char* Menu_name; // Menue Name int id; // Menue ID , damit ich mich orientieren kann int Number; // Anzahl der Submenues strukt Sub_menue []; } struct menue Main = { "Main", 10, 2, { {"Info", 100}, {"back", 90}, } }; struct menu Data_Log = { "Data Log", 20, 4, { {"Start", 200}, {"Stop", 201}, {"Settings", 202}, {"back", 203}, } }; Danke schon mals
Was soll "strukt Sub_menue [];" sein? Da fehlt irgendwie ein Variablenname oder der Typ (je nachdem was Sub_menue sein soll). Außerdem ist struct falsch geschrieben. Compilierst du deinen Code gar nicht zwischendurch? Hast du mitlerweile das C Buch von Anfang bis Ende gelesen und bist jetzt C-Meister und möchtest unbedingt flexible array member benutzen? Wenn nicht dann überleg dir bitte eine andere Speichermöglichkeit, die ohne unterschiedlich große Arays in structs auskommt. Z.B. irgendwas mit Pointern.
Danke nett für deine Antwort, besonders nett der Hinweis das ich mich bei einem pseudo Code vertippt habe. Es gibt auch noch Anfänger hier das sollte man nicht vergessen, zu dem sieht man bei mir das ich mir nicht die Arbeit machen lasse und selbst mit Ideen komme. C und C++ ist bei mir einfach auch schon mal wieder lange her!!! Man kann sich auch anständig unterhalten oder ? Und zum strukt Sub_menue []; alias struct Sub_menue []; ja zu diesem Datentyp bin ich mir nicht wirklich sicher , zumal ich mir die Frage stelle ob das möglich ist. Mit Stukturen zu arbeiten wäre mir auf anhieb einleuchtend, ich lass mich aber gern eines besseren belehren,.. Gruß
Der Grund warum hier mehrere zu einem C Buch raten ist, dass du offensichtlich Defizite bei wichtigen Themen wie z.B. Pointern hast. Viele deiner Antworten sind irgendwie hingeschriebener C Code oder wie du ja jetzt sagst Pseudo-Code. Ohne richtiges Verständnis welche Konstruktionen es in C gibt und welche nicht kommt man meistens nicht weit. In Pseudo-Code kann man theoretisch alles hinschreiben, aber ob das in C dann so umzusetzen ist, ist noch eine ganz andere Frage. Wenn ich mir ein Design überlege dann schreibe ich das direkt in der Programmiersprache hin, in der ich es auch umsetzen möchte und sehe dann spätestens beim Compilieren ob das so überhaupt funktioniert. Um auf dein eigentliches Problem zurückzukommen: Du möchtest eine Menüstruktur mit Funktionen für einzelne Menüpunkte, sowie Untermenüs darstellen. Das Ganze soll auf einem µC laufen? Hast du nirgendwo erwähnt scheinbar. Arrays mit variabler Länge in structs gibt es zwar in C, ist aber eher ein spezial Feature und sollte man nicht unbedingt verwenden, da es immer anders geht. Der ursprüngliche Ansatz mit einem Array von char* war gar nicht so schlecht. Wenn man statt char* ein struct für ein Menüeintrag erstellt kommt man schon weiter. Ich habe mir jetzt in ein paar Minuten mal diese Struktur überlegt:
1 | struct MenuItem |
2 | { |
3 | const char* name; |
4 | void (*func)(void); |
5 | MenuItem* submenu; |
6 | }; |
7 | |
8 | // Beispielmenü |
9 | MenuItem submenu[] = { |
10 | {"First submenu function", &sfunc1, NULL}, |
11 | {"Second submenu function", &sfunc2, NULL}, |
12 | {NULL, NULL, NULL} |
13 | }; |
14 | |
15 | MenuItem mainMenu[] = { |
16 | {"First function", &func1, NULL}, |
17 | {"Submenu", NULL, submenu}, |
18 | {"Second function", &func2, NULL}, |
19 | {NULL, NULL, NULL} |
20 | }; |
Ein Menüeintrag besteht aus einem Namen, einem Functionpointer (bitte Nachlesen wenn dir das nichts sagt), sowie einem Pointer auf ein Untermenü. Falls beim Auswählen eines Menüpunktes eine Funktion aufgerufen werden soll trägst du die Funktion in den Functionpointer ein. Versteckt sich hinter einem Menüeintrag ein Untermenü dann trägst du den submenu Pointer ein. Die einzelnen Menüs werden dann wieder in Arrays gespeichert, mit einem abschließenden Menüeintrag, der nur aus NULL Einträgen besteht. Der NULL Eintrag markiert das Ende eines Menüs. Dadurch kann man einfach auf ein Untermenü verweisen und muss nicht auch noch die Länge irgendwo mitgeben.
Bin gerade unterwegs und danke für deine Antwort, ich hab das ganze jetzt schnell überflogen. Ganz kurz aber noch--> MenuItem mainMenu[] = { {"First function", &func1, NULL}, {"Submenu", NULL, submenu}, {"Second function", &func2, NULL}, {NULL, NULL, NULL} }; Main Menue ist ja der oberste Menuepunkt, bei den Submenues was wäre für dich jetzt eine First function und eine Second funktion? Wenn ich die Hierarchie richtig verstanden habe dann würde das in meinem Fall so aussehen --> MenuItem mainMenu[] = { {""Main"",Submenue_menue, NULL}, {"Data Log",Submenue_Datalog, Null}, {"Diagnostic",Submenue Diagnistic, NULL}, {NULL, NULL, NULL} }; MenuItem Submenue_Datalog[] = { {""Sub1",Sub11,&func0 }, {" Sub2",Sub12,&func1}, {" Sub3",Sub13,&func2}, {NULL, NULL, NULL} } Ich versuch das jetzt mal umzusetzen, klingt alles noch logisch danke. Gruß
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.