Zeiger auf Text-Array



  • Hi,
    nach Stunden der vergeblichen Versuche gebe ich auf und wende mich an Euch:
    Ich will den nachfolgenden Code mit Zeigern versehen:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    //Definition der Struktur "Actions"
    	struct Actions {
    		long Action;		// Durchzuführende Funktion bei Druck auf "Select"
    		const char *Ptr_Text;		// Zeiger auf Array mit den Texten
    	};
    //Definition und Deklaration des Textarrays
    	char a_Texte[][14] = {
    		"Manuell",
    		"Auto",
    		"Seriell"
    	};
    	int lng_txt = sizeof (a_Texte[0]); // Länge eines einzelnen Textes (muss 14 sein)
    // Deklaration der Struktur "Actions"
    	struct Actions Action[] = {
    		{  10, (const char*) &a_Texte},
    		{  11, (const char*) &a_Texte},
    	};
    
    int main(int argc, char** argv) {
    	char text0[14];				//string0 mit 13 Zeichen + \0
    	int len_t0 = sizeof(text0);	//Länge von txt0
    	char text1[20];				//string1 mit 19 Zeichen + \0
    	int len_t1 = sizeof(text1);	//Länge von txt1
    	char text2[15];				//string2 mit 14 Zeichen + \0
    	int len_t2 = sizeof(text2);	//Länge von txt2
    	int i_action_line = 0;		//Laufvariable für Array Actions (hier immer 0)
    	int i;						//soll jeweils auf den i-ten Text des Arrays a_Texte verweisen
    // Texte aus Array in text0 bis text3 schreiben	
    	i = 0;
    	strncpy(text0, (Action[i_action_line].Ptr_Text+(i * lng_txt)), len_t0);
    	i = 1;
    	strncpy(text1, (Action[i_action_line].Ptr_Text+(i * lng_txt)), len_t1);
    	i = 2;
    	strncpy(text2, (Action[i_action_line].Ptr_Text+(i * lng_txt)), len_t2);
    
    	return 0;
    }
    

    Das funktioniert schon mal so weit.

    Was ich machen will: Ändern der Deklaration und Definition des Textarrays (in Zeile 10) auf:

    //Definition und Deklaration des Textarrays
    	const char *a_Texte[14] = {
    		"Manuell",
    		"Auto",
    		"Seriell"
    	};
    

    Dann sollte eine der obigen strncpy-Zeilen (z.B. Zeile 34) doch so aussehen:

    strncpy(text0, (Action[i_action_line].Ptr_Text+i), len_t0);
    

    Was mir nicht gelingt ist die Abänderung der Definition (Zeile 5) und der Deklaration (Zeile 19) der Struktur "Actions".

    Ist hier jemand bereit, mir bei der Lösung des Problems zu helfen?

    Schon einmal Danke vorweg...

    Grüße
    hefter



  • Hi, jetzt antworte ich mir selbst:
    Ich bin doch auf eine Lösung gekommen, die jetzt so aussieht:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    //Definition der Struktur "Actions"
    	struct Actions {
    		long Action;		// Durchzuführende Funktion bei Druck auf "Select"
    		const char **Ptr_Text;		// Zeiger auf Array mit den Texten
    	};
    //Definition und Deklaration des Textarrays
    	const char *a_Texte[] = {
    		"Manuell",
    		"Auto",
    		"Seriell"
    	};
    	# define ANZ_TEXTE sizeof(a_Texte)/sizeof(*a_Texte) // Anzahl der Texte für Vergleich mit i
    //	int lng_txt = sizeof (a_Texte[0]); // Länge eines einzelnen Textes (muss 14 sein) !!! nicht benötigt!!
    // Deklaration der Struktur "Actions"
    	struct Actions Action[] = {
    		{  10, a_Texte},
    		{  11, a_Texte},
    	};
    
    int main(int argc, char** argv) {
    	char text0[14];				//string0 mit 13 Zeichen + \0
    	int len_t0 = sizeof(text0);	//Länge von txt0
    	char text1[20];				//string1 mit 19 Zeichen + \0
    	int len_t1 = sizeof(text1);	//Länge von txt1^2!
    	char text2[15];				//string2 mit 14 Zeichen + \0
    	int len_t2 = sizeof(text2);	//Länge von txt2
    	int i_action_line = 0;		//Laufvariable für Array Actions (hier immer 0)
    	int i;						//soll jeweils auf den i-ten Text des Arrays a_Texte verweisen
    	int lng_txt0 = strlen(*(Action[i_action_line].Ptr_Text +0 )); // für Vergleich mit Länge des Zielstrings
    	int lng_txt1 = strlen(*(Action[i_action_line].Ptr_Text +1 )); // für Vergleich mit Länge des Zielstrings
    	int lng_txt2 = strlen(*(Action[i_action_line].Ptr_Text +2 )); // für Vergleich mit Länge des Zielstrings
    // Texte aus Array in text0 bis text3 schreiben	
    	i = 0;
    	strncpy(text0, *(Action[i_action_line].Ptr_Text + i), len_t0);
    	i++;
    	strncpy(text1, *(Action[i_action_line].Ptr_Text + i), len_t1);
    	i++;
    	strncpy(text2, *(Action[i_action_line].Ptr_Text + i), len_t2);
    
    	return 0;
    }
    

    Zusätzliche Ergänzung zum ursprünglichen Beispiel:
    Die Anzahl der Texte im Text-Array ist in ANZ_TEXTE zu finden, die einzelnen Textlängen werden in lng_txt0 bis lng_txt2 abgelegt.

    Ich möchte fragen, ob das "stilistisch" einigermaßen in Ordnung ist, oder ich da schwere "Schnitzer" (also Fehler) drinnen habe, die sich nur in diesem speziellen Beispiel nicht auswirken.
    Dass text0 bis text3 besser in einem 2-dimensionalen Array aufgehoben sind und i letztlich die Laufvariable in einer for-Schleife wird ist schon klar, das ist im Code nur zur besseren Sichtbarmachung meines ursprünglichen Problems.

    Danke für jegliche Anmerkungen, ich bin wie man unschwer sieht noch stark am Lernen...



  • Nur kurz:

    Der Kommentar in Zeile 17 stimmt so nicht mehr.

    strncopy schließt nicht mit einer '\0' ab, wenn len erreicht wurde.
    Du hast dann keinen gültigen C-String mehr.



  • Ich kann kein Design erkennen.
    Es ist alles Schrott, was du präsentierst.

    Das fängt mit dem Daten"design" (Z. 19-21) an, wo du Daten und Funktionen (bei dir Aktionen) miteinander vermischst.
    Zeile 25/26, 27/28, 29/30 zeigt auch, dass du unsinnig zur Compilezeit vorhandene statische Arraygrößen für Nutzdaten verwendest, die aber üblichweise zur Laufzeit dynamische Größen besitzen.
    strncpy wurde schon gesagt, dass das Schrott ist (du handelst dir nur unnötige Laufzeit-Abhängigkeiten ein, die du durch gescheites Daten/Funktionsdesign zur Compilezeit durch den Compiler prüfen lassen kannst).

    Bei neuen Programmen verwendet man üblicherweise Top-Down mit vorigem Daten-Design, d.h. zuerst musst du dir mal klar werden, was deine Daten sind, meist verwendet man dann ein oder mehrere struct, davon dann eine Liste (keine verkettete), instanziiert davon dann in main ein Objekt, was man jeweils (gesteuert in main) an Funktionen übergibt, die die eigentliche Arbeit machen (und das Objekt auch ändern können müssen).



  • DirkB schrieb:

    Der Kommentar in Zeile 17 stimmt so nicht mehr.

    ja, weil sizeof auf ein Array von Zeigern immer die Zeigerlänge (bei meinem Compiler = 😎 liefern würde. Ich habe die Zeile deshalb auch auskommentiert.

    DirkB schrieb:

    strncopy schließt nicht mit einer '\0' ab, wenn len erreicht wurde.
    Du hast dann keinen gültigen C-String mehr.

    Ah, danke für den Hinweis, hätte ich glatt übersehen!
    Wenn ich beim strncpy die Längenangabe auf len_t0 - 1 ändere, sollte das dann aber funktionieren.
    Im realen Programm werden die 3 Texte in 3 definierte Bereiche eines 3*32 Zeichen großen LCD-Displays geschrieben. Die Bereiche sind 13,19 und 14 Zeichen groß. Die fixen Definitionen (z.B. die Zahl 14 in char text0[14] ist natürlich in einer *.h-Datei per #define geregelt und auch das len_t0 (bzw. len_t0-1 ) gibt es nicht, dafür wird bei strncpy als Länge die entsprechende, mit #define definierte Definition genommen. Da ich das "-1" aber auch im realen Programm nicht berücksichtigt habe ist Dein Hinweis auf die Nicht-Null-Terminierung für mich Gold wert, danke nochmals dafür!

    Ich habe versucht mein Problem im Posting des C-Codes so einfach wie möglich darzustellen, um den Fokus auf das Wesentliche zu lenken. Das Programm erstreckt sich über mehrere C-Files, die den Rahmen hier bei Weitem sprengen würden....
    Mir ging es hauptsächlich wie geschrieben um die Definition/Deklaration der Struktur, da ich auf die einfach Lösung const char **Ptr_Text; einfach nicht gekommen bin, sondern stundenlang wie vernagelt mit irgendwelchen Kombinationen aus * und & "herumprobiert" habe.

    Danke nochmals für Deine Hilfe!

    Nachtrag, habe gerade gesehen dass Wutz eine Antwort gegeben hat:

    Wutz schrieb:

    Das fängt mit dem Daten"design" (Z. 19-21) an, wo du Daten und Funktionen (bei dir Aktionen) miteinander vermischst.

    Die Struktur Actions ist im realen Programm wesentlich umfangreicher und enthält neben den beiden für mein Problem wichtigen Einträgen noch weitere 24 Einträge. Es werden hier für die "Action" (= 1. Wert) Wertgrenzen (Min, Max, Standard, Ersatzwert u.s.w für Zählwerte, die Anzeigetexte, sowie Vorgaben für die weitere Verarbeitung definiert.
    Die Deklaration von struct Actions Action[] { hat über 90 Zeilen, die aber für die Problembeschreibung (meinem Empfinden nach) nicht maßgeblich sind.
    Ich war der Meinung, dass dies eigentlich ein einigermaßen vernünftiges Design ist.

    Dein Kommentar zu den Zeilen 25 bis 30 ist nachvollziehbar. Vielleicht wird meine Erklärung oben das relativieren?

    Wutz schrieb:

    ....ein oder mehrere struct, davon dann eine Liste (keine verkettete), instanziiert davon dann in main ein Objekt,

    Hm, ist das ist mir jetzt nicht ganz klar, wie Du das meinst.
    - Definition der Struct ab Zeile 6 (habe ich im realen Programm in einer xxxx.h) ... das scheint ja zu passen
    wie sähe die erwähnte Liste aus? Darunter kann ich mir nichts vorstellen. (Ich dachte bis eben, meine Deklaration ab Zeile 19 wäre genau das?)
    Deklaration ab Zeile 19... Diese gehört in main?

    Es wäre für mich sehr hilfreich, wenn Du mir da ein paar Tipps (oder einen kurzen Code-Schnipsel) geben könntest, da meine (aus diversen Büchern und Foren zusammengesuchte) bisherige Programm- und Datenstruktur bzw. mein "Design" anscheinend absolut falsch ist.



  • hefter schrieb:

    Wenn ich beim strncpy die Längenangabe auf len_t0 - 1 ändere, sollte das dann aber funktionieren.

    Nein.
    Es sei denn, du setzt selber die '\0' ans Ende. Aber dann kannst du auch die -1 weg lassen.



  • Hi Dirk,

    DirkB schrieb:

    Es sei denn, du setzt selber die '\0' ans Ende. Aber dann kannst du auch die -1 weg lassen.

    Ja, das war mir soweit klar, habe ich vergessen dazu zu schreiben.
    Ich bin aber am Überlegen, ob nicht ein strcpy mit vorangestellter Prüfung, ob der zu kopierende String (inkl. \0) ins Ziel passt, die vernüftigere Lösung ist.

    Danke für Deine Hilfe und den Hinweis.. das hat mir geholfen.


Anmelden zum Antworten