array durch array in array ersetzen :))))

Hallo,
ich bin gerade dabei ein kleines Menu für ein 16X2 LCD zu basteln.
Im Hauptmenu kann ich mich schon problemlos bewegen mit hoch und runter.
Jetzt möchte ich eine Menuebene tiefer, da ich das ganze sehr allgemein halten will und nicht für jeden Menupunkt alles neu schreiben will habe ich mir folgendes Überlegt.

char* Hauptmenu[]={"HMenu1", "HMenu2", "HMenu3"};
char* HMenu1[]={"Punkt1", "Punkt2", "Punkt3"};
char* HMenu2[]={"Punkt1", "Punkt2", "Punkt3"};
int Position = 1;  // Derzeit angewähltes Menu durch druck auf Taster auf oder ab wird der nächste Eintrag im Array angewählt
int Menulaenge = 0;
char* Menu[10];  // Aus dieser Variable wird später durch Indexzugriff der jeweilige Wert gelesen der auf dem LCD angezeigt wird.
char* altesMenu[10];  // Menu wird hierher kopiert um das letzte Menu wieder mit der Zurücktaste aufrufen zu können.
char* *nextMenu;  // Zeiger 



void setup(){
...

// Das Array Menu bekommt die Werte von Hauptmenu, weil ich beim Starten ja im Hauptmenu starten will.
for (int i=0;i<sizeof(Hauptmenu)/sizeof(Hauptmenu[0]);i++){
   Menulaenge += 1;
   Menu[i] = Hauptmenu[i];

...
 }



void loop(){

...
for (int i=0;i<sizeof(Menu)/sizeof(Menu[0]);i++){    //aktuelles Menu in das Array altesMenu kopieren
      altesMenu[i] = Menu[i];  
}

//////////////// Mein Problem liegt hier//////////////////////
nextMenu = &Menu[Position-1];     
    for (int i=0;i<sizeof(nextMenu)/sizeof(nextMenu[0]);i++){
      Menu[i] = *nextMenu[i];
    }

}

//Menu wird an die Funktion übergeben die für die Ausgabe auf dem LCD verantwortlich ist

So und hier ist mein Problem, angenommen ich befinde mich im Hauptmenu und habe gerade den Punkt
HMenu2 angewählt, (Variable Position=2)
Mit dem nächsten Befehlt bekommt die Variabel naechstesMenu den Wert "HMenu2" so wie es sein soll.
Aber Wenn ich jetzt mit der selben for-Schleife wie oben das Array Menu mit den Werten vom Array HMenu2 füllen möchte klappt das nicht.
Wahrscheinlich weil der Zeiger nextMenu auf das Wort HMenu2 und nicht auf das Array HMenu2 zeigt.
Wie kann ich beide gleichsetzen?

Ich möchte das ganze ohne großen Schreibaufwand beliebig erweitern können deshalb schreibe ich nicht für jedes Untermenu extra die Ausgaben.

Librarys möchte ich nicht verwenden da ich momentan beim lernen bin, ich will wissen wie es funktioniert.

Warum das Rad neu erfinden?
Schau doch mal hier: Projektvorstellung: Library für das Erstellen von Menus für LCD Displays - Deutsch - Arduino Forum
und hier: Projekt: LCDMenuLib / LCDMenuLib2 ( LCDML ) - Menü mit mehreren Ebenen - Deutsch - Arduino Forum

Sorry, dass Du keine Libs benutzen willst hab ich zu spät gesehen :blush:

Menu[i] = *nextMenu[i];

Das geht natürlich nicht. Wenn du einen char* dereferenzierst hast du einen char. Und das kannst du keinem Array aus char* zuweisen

Ein Array komplett in ein anderes zu kopieren (wenn es das ist was das willst) geht mit memcpy():
http://www.cplusplus.com/reference/cstring/memcpy/

nextMenu = &Menu[Position-1];     //nextMenu ist ein Zeiger
    for (int i=0;i<sizeof(nextMenu)/sizeof(nextMenu[0]);i++){
      Menu[i] = *nextMenu[i];
    }

nextMenu zeigt jetzt auf sagen wir mal Index [1] von Menu
Menu[1] ist ja HMenu2
HMenu2 ist aber jetzt nicht das Array sondern nur ein Char
mit der for Schleife kopiere ich ja ein Array in ein anderes Array,
Nur wie bekomme ich es hin das anstatt nextMenu HMenu2 dort steht ohne das ich es selber hinschreibe?

mit der for Schleife kopiere ich ja ein Array in ein anderes Array

Du hast vielleicht nicht genau verstanden wie du deine Arrays deklariert hast. In C sind Arrays erst mal nur Zeiger auf das erste Element.
Hauptmenu ist lediglich ein Array aus 3 Zeigern mit je 2 Bytes. Die eigentlichen Strings stehen wo anders im Speicher. Wenn du also den Zeigern neuen Werten zuweist werden da keine Arrays kopiert. Es wird nur die Information kopiert wo der String steht.

Das ist prinzipiell völlig in Ordnung und es besteht hier kein Grund die Strings an sich zu kopieren. Du darfst das aber nicht mit zwei-dimensionalen Arrays verwechseln (mit [][] ), oder denken, dass man mit einer einzelnen Zuweisung komplette Arrays kopieren kann.

EDIT:
Genaugenommen kopierst du das Array aus Zeigern. Aber nicht die Strings selbst (welche ja auch nur Arrays aus char) sind.

EDIT 2:
Sehe gerade das hier:

char* *nextMenu;

Ich hatte den zweiten Stern übersehen

Ist dir klar, dass das ein Zeiger auf einen Zeiger ist? Was man besser so schreibt:

char** nextMenu;

Das gilt aber das gleiche was ich schon gesagt habe. Nur eine Ebene tiefer. Einem char** muss die Adresse eines char* zugewiesen werden.

Serenifly:
Ist dir klar, dass das ein Zeiger auf einen Zeiger ist? Was man besser so schreibt:

char** nextMenu;

Das gilt aber das gleiche was ich schon gesagt habe. Nur eine Ebene tiefer. Einem char** muss die Adresse eines char* zugewiesen werden.

Ok wie bekomme ich es denn hin das der Wert HMenu1 im Array Hauptmenu die selbe Adresse hat wie das Array HMenu1 selber?

Wozu soll das gut sein? Wenn du die Zeiger in Hauptmenu überschreibst, dann sind die Verbindung zu den drei Strings mit denen du das Array initialisierst hast weg.

Ich dachte du wolltest immer Zeiger auf das aktuelle Array in Menu[] halten. Aber die Arrays mit den Strings sollte man eigentlich nicht ändern.

Oder hast du eher sowas gemeint?

char* HMenu1[]={"Punkt1", "Punkt2", "Punkt3"};
char* HMenu2[]={"Punkt1", "Punkt2", "Punkt3"};
char** Hauptmenu[]={ HMenu1, HMenu2 };

Serenifly:

char* HMenu1[]={"Punkt1", "Punkt2", "Punkt3"};

char* HMenu2[]={"Punkt1", "Punkt2", "Punkt3"};
char** Hauptmenu[]={ HMenu1, HMenu2 };

Das funktioniert nicht.
"note: no known conversion for argument 1 from ‘char**’ to ‘long unsigned int’"

Ich versuchs nochmal zu erklären. Ist echt schwer ohne was mit dem Finger zu zeigen :slight_smile:
Je nach dem in welcher Menuebene ich mich befinde, hat das Array Menu unterschiedliche Werte.
Mit der folgenden for-Schleife schreibe ich ja die Werte vom Array HMenu1 in das Array Menu.

for (int i=0;i<sizeof(HMenu1)/sizeof(HMenu1[0]);i++){
   Menulaenge += 1;
   Menu[i] = HMenu1[i];
}

Ich möchte nun aber nicht HMenu1 schreiben sondern dafür eine Variable einsetzen die folgendermaßen gebildet wird.
AchtungBeispiel:
HMenu1 = Menu[0] Menu hätte in diesem Fall die Werte vom Array Hauptmenu.

Puh das war jetzt ganz schön kniffelig die richtigen Worte zu finden.

Verabschiede dich wie gesagt am besten von den for-Schleifen. Das ist zwar nicht falsch, aber memcpy() ist übersichtlicher und sicherer.

Mal sehen ob ich es jetzt richtig verstanden habe:

char* hauptmenu[]={"HMenu1", "HMenu2", "HMenu3"};
char* hMenu1[]={"Punkt1", "Punkt2", "Punkt3", "Punkt4"};
char* hMenu2[]={"Punkt1", "Punkt2", "Punkt3"};

char* menu[10];

void copyArray(char** source, size_t size)
{
  memset(menu, 0, sizeof(menu));
  memcpy(menu, source, size);
}

void printMenu()
{
  int i = 0;
  size_t size = sizeof(menu) / sizeof(char*);

  while(i < size && menu[i] != NULL)
	Serial.println(menu[i++]);
  Serial.println();
}

void loop()
{
  copyArray(hauptmenu, sizeof(hauptmenu));
  printMenu();

  copyArray(hMenu1, sizeof(hMenu1));
  printMenu();

  copyArray(hMenu2, sizeof(hMenu2));
  printMenu();

  delay(2000);
}

Ausgabe:

HMenu1
HMenu2
HMenu3

Punkt1
Punkt2
Punkt3
Punkt4

Punkt1
Punkt2
Punkt3

Du übergibst ja in der loop Funktion jedesmal manuel das jeweilige Menu an die Funktion copyArray
Ich möchte das aber durch eine Variable lösen. Ich glaube ich kann einfach nicht richtig beschreiben was mein Problem ist.

Serial.print(hauptmenu[0]); gibt mir folgendes aus
HMenu1

Ich möchte die Ausgabe von hauptmenu[0] gleich als das nächste array benutzen.
anstatt von Hand sowie du das machst das jeweilige Array an die Funktion copyArray zu übergeben.

Aber das geht nicht weil hauptmenu[0] mir einen String wieder gibt (heißt das string? bei Python heißt es so)
Und dieser String nicht das selbe ist wie char* HMenu1.

Da wird nicht das ganze Array übergeben. Arrays sind nicht viel mehr als Zeiger. Eine Array-Variable ist nur ein Zeiger auf das erste Element.
Das ist nicht wie in Python/Java/C# oder anderen Sprachen wo Arrays Objekte sind! Das ist ja der Grund weshalb man die Größe extra verwalten muss.

Ich übergebe da schon eine Variable :slight_smile: Nur nicht die die du wolltest.

Serial.print(hauptmenu[0]); gibt mir folgendes aus
HMenu1

Natürlich! Weil das ein Array aus Strings ist! Das macht genau was du programmiert hast

Deshalb der Gedanke, dass du eher ein Array aus Arrays auf String wolltest:

char* hMenu1[]= {"Punkt1", "Punkt2", "Punkt3", "Punkt4"};
char* hMenu2[]= {"Punkt1", "Punkt2", "Punkt3"};
char** hauptmenu[]= { hMenu1, hMenu2 };

char* menu[10];

void copyArray(char** source, unsigned int elements)
{
	memset(menu, 0, sizeof(menu));
	memcpy(menu, source, elements * sizeof(char*));
}

void loop()
{
	copyArray(hauptmenu[0], 4);
	printMenu();

	copyArray(hauptmenu[1], 3);
	printMenu();
}

Ausgabe:

Punkt1
Punkt2
Punkt3
Punkt4

Punkt1
Punkt2
Punkt3

Das Problem dabei ist, dass man nicht sizeof(hauptMenu[0]) machen kann. Das ist immer 2 weil Zeiger 2 Byte breit sind. Ein zusätzliches Array um die Größe der anderen Arrays zu speichern ist hier eine Option. Das kann man dann über den gleichen Index wie hauptMenu ansprechen.

Alles klar,
Danke :slight_smile:

Wobei du dir die ganze Geschichte mit dem Umkopieren wahrscheinlich auch sparen kannst.

Da Arrays eben Zeiger sind kann man auch einfach sowas machen:

char** currentMenu = hauptmenu[0];

Da wird nichts kopiert oder geändert. Man kann einfach das Array hMenu1 über eine andere Variable ansprechen.

Die Länge der String Arrays könnte man auch bestimmen indem hinten einen NULL-Zeiger einfügt. Dann kann man darüber iterieren bis dieser kommt. Ähnlich einem C String selbst, welcher auch nur ein Null-terminierte char Arrays sind. Sowas:

char* hMenu1[]= {"Punkt1", "Punkt2", "Punkt3", "Punkt4", NULL};

Dann kann man das machen:

unsigned int getLength(char** source)
{
	if(source == NULL)
		return 0;
	
	unsigned int i = 0;
	while(source[i] != NULL)
		i++;

	return i;
}

Und das liefert die Anzahl der Strings im Array:

getLength(currentMenu);