Für was gehört der Pointer ?

OP #3771782
Lesenswert?

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

}
Gast #3771810
Lesenswert?

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.
Gast #3771821
Lesenswert?

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.
OP #3771829
Lesenswert?

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 ?
Gast #3771840
Lesenswert?

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.
Gast #3771843
Lesenswert?

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"};
OP #3771855
Lesenswert?

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 ?
Gast #3771860
Lesenswert?

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.
OP #3771864
Lesenswert?

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?
Gast #3771867
Lesenswert?

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".
#3771886
Lesenswert?

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.
OP #3771951
Lesenswert?

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ß
#3771963
Lesenswert?

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.
#3771975
Lesenswert?

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.
OP #3773248
Lesenswert?

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ß
OP #3773275
Lesenswert?

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.
OP #3773366
Lesenswert?

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
Gast #3773426
Lesenswert?

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.
OP #3774454
Lesenswert?

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ß
Gast #3774539
Lesenswert?

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.
OP #3775098
Lesenswert?

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ß

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren