String-Array innerhalb eines struc's nutzen;



  • nabend Programmierer;
    Es ist zwar kein C-Quellcode, aber das Problem ist ein rein C-spezifisch. Ich will ein String Array bzw. ein **stringArray, das in einem struct "eingebettet" ist mit Werten auffüllen. Wie genau funktioniert das mit der Allokierung? Muss ich schon im Voraus wissen, wieviele Strings ich auffüllen will und wie lang jedes einzelne String ist? Folgenden Code hab ich bis jetzt:

    #include <iostream>
    using namespace std;
    
    struct struktur fuelleArray();
    
    struct struktur 
    {
    	char **stringArray;
    };
    
    int main()
    {
    	struct struktur schablone = fuelleArray();
    	cout<< schablone.stringArray[0]<<endl;
    }
    
    struct struktur fuelleArray()
    {
    	char buffer[256];
    	cin.getline(buffer,256);	
    	struct struktur schablone;
    	schablone.stringArray[0] = buffer;
    	return schablone;
    }
    

    er gibt mir ein Segmentation fault aus... 😞



  • wenn du sowiso c++ machst, warum quälst dich du mit so was rum?

    Da du ein Array nimmst, musst du spätestens beim anfordern des Speicher wissen, wie groß das ganze werden könnte, da du sonnst natürlich später ein größeres erstellen müsstest und das bestehende umkopieren musst.

    Für sowas gibts die Templateklasse vector<T>, die macht das selbstständig.

    Das selbe Problem hast du mit den strings ja aber auch nochmal.

    in deinem Code sind übrigens zwei essentieller Fehler :
    Zeile 22: du dereferenzierst einen Pointer der nirgens initialisert wurde.
    Zeile 19/22: du erzeugst eine lokales Objekt auf den Stack (dein array) und gibst den Pointer in deine rückgabewert-struktur.
    Sobald die Funktione verlassen wird, wird der stack abgeräumt und von anderen Funktionen woeder überschrieben, so dass undefineirt ist, wo dein array hinzeigt. --> segmentation fault

    wozu brauchst du überhaupt ein char**?
    du benutz doch nur das erste element.

    struct struktur
    {
        char **stringArray;   // brauchst du wirklich ** (array von strings)
    };
    
    struct struktur fuelleArray()  // tatsächlich wird hier nur der erste platz des arrays gefüllt. 
    {
        char buffer[256];                    // <- speicher auf stack (struktur enthält uninitialisiertn pointer
        cin.getline(buffer,256);             
        struct struktur schablone;           // <-- struktur auf stack
        schablone.stringArray[0] = buffer;   // derefernzierung unintialiserter Pointer und zuweisung einer Stackadresse
        return schablone;                    // 
    }
    

    Aber wie gesagt:

    in cpp wurde das ganze so aussehen:

    #include <vector>
    #include <string>
    using namespace std;
    
    struct StringTable   // ich spar mir mal jetzt ein umfangreiches klassendesign 
    {
      vector<string> strings;
    }
    
    int main()
    {
        StringTable stringtable;
        fuelleArray(stringtable);
        cout<< stringtable.strings <<endl;
    }
    
    void fuelleArray( StringTable& io_stringtable)  // ich bau das mal um,  da fülle impliziert, dass ein objekt, was schon da ist gefüllt wird
    {
        string str;
        cin >> str;
        io_stringtable.strings.push_back(string);
    }
    


  • wenn du bei deiner ursprünglichen variante bleiben willst müsstest du folgendes machen:

    struct StringTable
    {
      char **strings;
      int  size;
      int  maxsize;
    };
    
    BOOL StringTable_init(StringTable* o_self, int size)
    {
      int i;
      o_self->strings = malloc(size* sizeof(char*));
    
      if(o_self->strings)
      {
        o_self->size = 0;
        o_self->maxsize = size;
        memset(o_self->strings, 0, size* sizeof(char*)); // hier bin ich mir grad nicht sicher, ob der 2. parameter der wert oder die länge ist
        return TRUE;
      }else
        return FALSE;  
    }
    
    BOOL StringTable_enlarge(StringTable* io_self, int newsize)
    {
      // TODO: verkleinerungen handeln -> entweder abfangen und verbieten, oder code anpassen (und funktione umbenennen)
    
      char** newbuff = malloc(newsize* sizeof(char*));
      if(newBuff)
      {
        io_self->maxsize = newsize;
        memcpy(newbuff, io_self->strings, io_self->size*sizeof(char*));                // TODO: check ob anzehlen stimmen
        memset(io_self->strings + io_self->size, 0, io_self->maxsize - io_self->size): // TODO: check ob anzehlen stimmen
        return TRUE;
      }else
        return FALSE;
    }
    
    void StringTable_delete( StringTable* io_self, BOOL deleteStrings)
    {
      if(deleteStrings)
      {
        int i;
        for(i=0; i<io_self->size)
        {
          free(io_self->strings[i]);
        }
      }
      free(io_self->strings);
      io_self->strings = NULL;
      io_self->size    = 0;
      io_self->maxsize = 0;
    
    }
    


  • sorry für die möglicherweise blöden Fragen (ich bin noch Anfänger)...

    in deinem Code sind übrigens zwei essentieller Fehler :
    Zeile 22: du dereferenzierst einen Pointer der nirgens initialisert wurde.

    Wieso wurde der buffer-Pointer nicht initialisiert? Habe ich das nicht mit Zeile 20 getan?

    Zeile 19/22: du erzeugst eine lokales Objekt auf den Stack (dein array) und gibst den Pointer in deine rückgabewert-struktur.
    Sobald die Funktione verlassen wird, wird der stack abgeräumt und von anderen Funktionen woeder überschrieben, so dass undefineirt ist, wo dein array hinzeigt. --> segmentation fault

    Das stimmt.Da meine Muttersprache Java ist hab ich zu oft noch Schwierigkeiten mit Pointer-Geschichten.... Ich habe den Buffer und den struct in meiner neuen Version jetzt zu globalen Variablen gemacht...er gibt trotzdem ein Segmentation fault aus....(siehe unten)

    das char** brauche ich... (später sollen noch mehr Strings dazukommen)...
    Sorry aber das ähnelt in keinster Weise meiner ursprünglichen Vision 🙂 ... Mein Ziel ist es, den struct nicht zu verändern und die Gesamt-Struktur, also mit main, struct und einer Funktion, die ein struct wiedergibt, auszukommen.

    (Ich habe nicht den ganzen Code gepostet)... mir ist jeweils die Länge aller Strings bekannt... mir ist nur nicht die Anzahl der Strings bekannt...

    #include <iostream>
    struct struktur fuelleArray();
    using namespace std;
    
    struct struktur 
    {
    	char **stringArray;
    }schablone;
    
    char *buffer;
    int main()
    {
    	struct struktur schablone = fuelleArray();
    	cout<< schablone.stringArray[0]<<endl;
    }
    
    struct struktur fuelleArray()
    {
    	buffer = (char *) malloc(256);
    	cin.getline(buffer,256);	
    	//schablone.stringArray[0] = malloc(strlen(buffer));
    	schablone.stringArray[0] = buffer;
    	return schablone;
    }
    


  • sharp schrieb:

    Wieso wurde der buffer-Pointer nicht initialisiert? Habe ich das nicht mit Zeile 20 getan?

    ich rede nicht vom puffer, ich rede von dem array, in dem die Pointer drinstehen, die auf die strings zeigen sollen, also von schablone.stringArray

    (Ich habe nicht den ganzen Code gepostet)... mir ist jeweils die Länge aller Strings bekannt... mir ist nur nicht die Anzahl der Strings bekannt...

    Auf die länbge der strings bin ich doch gar nicht eingegangen.
    Alles was ich gepostet habe bezieht sich nur auf das management der Varianbel langen Liste mit strings.

    Den speicher für die strings musst du natürclich noch zusätzlichallozieren (nicht vom Stk holen) und dann den Pointern zuweisen.

    Ich glaub, du hast das mit den Array von Pointern noch nicht richtig vertanden.

    deine struktur ist genau so groß, wie ein Pointer.

    struktor s;
    // s enthält einen Pointer, der später auf den Anfang des Array zeigen soll
    //
    // s.stringArray     
    //    |
    //    v
    //  x#.*+, // zeigt iregndwo hin
    //
    // -> speicher allozieren und initialisieren.
    
    s.stringArray = malloc(4* sizeof(char*))
    //
    // jetzt zeigt s.stringArray auf einen speicherbereich mit zeigern
    //
    // s.stringarray
    //    |
    //    v
    //   [0] --> x#.*+,  // zeigt iregndwo hin
    //   [1] --> x#.*+,  // zeigt iregndwo hin
    //   [2] --> x#.*+,  // zeigt iregndwo hin
    //   [3] --> x#.*+,  // zeigt iregndwo hin
    //
    // s.stringarray hat jetzt also platz für maximal 4 pointer auf chararrays (nix anderes ist ein c-string nämlich)
    //
    
    for(i=0;i<4;++i)
       s.stringarray[i] = 0; //damit man sieht, dass die poitner ungültig sind;
    
    // 
    // wenn ich jetzt ein string in die liste soll, brauche ich erst mal ein char-array:
    // wo ich wieder vorher wissen muss, wie lang mein string wird, deswegen erst mal ein auzsreichend großes stackarray
    char buf[1000];
    // irgendwas einlesen in buf;
    int len = strlen(buf); //länge ermitteln
    s.stringarray[0] c = malloc(len + 1); // speicher anfordern. plus 1 ist wichtig wegen 0 am schluss.
    strcpy(s.stringarray[0], buf);
    

    Ich hoffe du verstehst jetzt, warum ich dir rate, lieber die cpp-bibliothek zu nutzen, wenn du sowiso c++-Programme erzeugst.

    Mein Ziel ist es, den struct nicht zu verändern und die Gesamt-Struktur, also mit main, struct und einer Funktion, die ein struct wiedergibt, auszukommen.

    Das wird nicht funktionieren, da du so keine möglichkeit hast, dem Array anzusehen, wie lang oder voll es gerade ist.



  • vielen Dank.. jetzt hab ichs verstanden. Nur Zeile 35 bereitet mir noch Schwierigkeiten (s.stringarray[0] c)...ein Tippfehler? Ansonsten ist mir deine Erklärung eine große Hilfe. Werde ich gleich ausprobieren...



  • das c ist natrlcih quatisch, das liegt an der späten stunde.
    ich hatte da vorher char* stehn, aber es dann doch direkt dem Array-feld zugewiesen.



  • perfekt. danke nochmal für die Erklärung und den Code.. das hat mich ein ganzes Stück weiter gebracht...

    #include <iostream>
    struct struktur fuelleArray();
    using namespace std;
    
    struct struktur 
    {
    	char **stringArray;
    };	
    
    char *buffer;
    
    int main()
    {
    	struct struktur schablone = fuelleArray();
    	cout<<"1. String: " <<schablone.stringArray[0]<<endl;
    	cout<<"2. String: " <<schablone.stringArray[1]<<endl;
    }
    
    struct struktur fuelleArray()
    {
    	struct struktur schablone;
    	schablone.stringArray;
    	schablone.stringArray = (char**) malloc (2* sizeof(char*));
    
    	char buffer1[256];
    	cin.getline(buffer1,256);
    
    	char buffer2[256];
    	cin.getline(buffer2,256);
    
    	int len1 = strlen(buffer1);
    	int len2 = strlen(buffer2);
    
    	schablone.stringArray[0]  = (char*) malloc(len1 + 1);
    	schablone.stringArray[1]  = (char*) malloc(len2 + 1);
    
    	strcpy(schablone.stringArray[0], buffer1); 
    	strcpy(schablone.stringArray[1], buffer2); 
    	return schablone;
    }
    

Anmelden zum Antworten