Dynamisches Array zur Laufzeit



  • Hallo ich hab ein Problem.
    Ich schreibe gerade ein Programm das alle Verzeichnisse von der Festplatte
    in einer Struktur speichert:

    #define PATH_MAX 512
    #define MAXHEAP 10000
    
    int counter = 0;
    int iDebug = 0, iRelease = 0;
    
    struct DIRECTORYBUFFER
    {
      char DirName[PATH_MAX];
      char AbsoluteName[PATH_MAX];
    };
    DIRECTORYBUFFER *buffer[MAXHEAP];
    

    Das Problem ist jetzt, das ich nicht genau weiß wieviel Verzeichnisse es entgültig gibt.

    Ich schaff also den Speicher so:

    for (int i = 0; i<MAXHEAP; i++)	
    	{
    		buffer[i] = new DIRECTORYBUFFER;
    		ZeroMemory(buffer[i],sizeof(DIRECTORYBUFFER));
    	}
    

    Also hier jetzt ganau fuer 10000 Ordner.

    Ich könnte ja erst die Directory Suchfunktion laufen lassen, einen Zähler mit laufen lassen, und danach den Speicher besorgen.
    Dann müsste ich aber nochmal die Suchfunktion laufen lassen um die Daten in die Struktur zu schreiben. Das kostet fast die doppelte Zeit.

    .
    .
    if (finder.IsDirectory())
    {
    	CString str = finder.GetFilePath();
          if (counter >= MAXHEAP-1) continue;   //Sicherung, damit Array nicht Überschritten wird
    	//cout << (LPCTSTR) str << endl;
    	strcpy(buffer[counter]->DirName,finder.GetFileName());
    	strcpy(buffer[counter]->AbsoluteName,finder.GetFilePath());
    	counter++;
    	Recurse(str);
    }
    .
    .
    

    Kann man irgendwie das Array "DIRECTORYBUFFER *buffer[MAXHEAP]" zur Laufzeit erweitern?
    und dann immer wenn ein Directory gefunden wird,mit new Speicher holen?



  • Wie wär's denn mit vector und string? Dann brauchst du dich gar nicht mehr ums Speichermanagement zu kümmern.



  • ich würd einfach std::list verwenden..





  • @Artchi: Dein Link funktioniert nicht.

    Ja string wäre eine möglichkeit aber ich wollte trotzdem gerne wissen ob sowas geht.
    ich meine von grund auf und keine vorgefertigten classen oder funktionen.



  • Probier es bitte noch einmal.



  • Ovaron123 schrieb:

    @Artchi: Dein Link funktioniert nicht.

    Funzt wieder.

    Ovaron123 schrieb:

    Ja string wäre eine möglichkeit aber ich wollte trotzdem gerne wissen ob sowas geht.
    ich meine von grund auf und keine vorgefertigten classen oder funktionen.

    natürlich geht das, aber wie Artchi schon auf seiner website sagt, haut man sich dadurch viele fehler und bufferoverflows ins programm rein. Man benutzt irgendwelche array-größen, die entweder zuviel leistung fressen, oder zuwenig platz bieten, aber mit den stl-containern hast du 100%ig funtionierende array-klassen, die sicher und schnell sind.
    du könntest std::vector nachprogrammieren, allerdings würde ich das nur als Übung empfehlen und danach sofort wieder std::vector benutzen. die sind nämlich überall verfügbar und ganz bestimmt bugfrei.

    mfg



  • Ah gut das hört sich nach einer Lösung an:

    vector<int> meinArray(10);
    
    int i = 100;
    //...
    meinArray.resize(i);
    

    Hab zwar noch keine Erfahrung mit STL oder Templates, (Bin im C++ Buch erst bei Copy-Konstruktoren) aber das ist gut erklärt.
    Danke



  • Ovaron123 schrieb:

    @Artchi: Dein Link funktioniert nicht.

    Ja string wäre eine möglichkeit aber ich wollte trotzdem gerne wissen ob sowas geht.
    ich meine von grund auf und keine vorgefertigten classen oder funktionen.

    Was heisst hier von Grund auf? std::vector, std::list und std::string sind Teil der Basis, auf der jedes C++ Programm aufbaut.

    Du kannst das gleiche mit dynamischen char Arrays erreichen, aber das ist dann auf dem selben Level wie wenn du die std:: Klassen benutzt, da es von der Sprache direkt gegeben ist.

    Dabei ist es unerheblich, dass die meisten Implementierungen dynamische Arrays für std::vector oder std::string benutzen. Das ist so nicht vorgeschrieben. Diese Funktionalität kann genauso LowLevel implementiert werden, wie man Arrays implementiert.



  • Ovaron123 schrieb:

    Ah gut das hört sich nach einer Lösung an:

    vector<int> meinArray(10);
    
    int i = 100;
    //...
    meinArray.resize(i);
    

    Muß noch anmerken, das du mit der Methode push_back() dir das resize() sogar in den meisten Fällen ersparen kannst. Sagen wir mal du gehst in einer Schleife deine Directories durch und willst deinen Vector füllen, hier mal pseudocode:

    // irgendwo:
    std::vector<CString*> directories;
    // ...
    
    void recurse()
    {
        if (finder.IsDirectory())
        {
           CString str = finder.GetFilePath();
           directories.push_back(&str); // vector wird autom. vergößert, wenn nötig!
           recurse();
        }
    
    }
    

    Du mußt also kein resize()-Aufrufen, wenn du nicht weißt, wie groß der Vector sein soll.



  • Ovaron123 schrieb:

    Ja string wäre eine möglichkeit aber ich wollte trotzdem gerne wissen ob sowas geht.
    ich meine von grund auf und keine vorgefertigten classen oder funktionen.

    Ja, sowas geht auch. (Diese Funktion vergrößert Int-Arrays, kannst du ja anpassen).
    Aber benutz lieber die STL für sowas (wie schon erwähnt).

    void resize(int*& buffer, unsigned int& len, const unsigned int& resizeTo)
    {        
            int* tmp = new int[((resizeTo < len) ? (resizeTo) : (len))];
            for(unsigned int i = 0; i < ((resizeTo < len) ? (resizeTo) : (len)); ++i)
                    tmp[i] = buffer[i];                
    
            delete[] buffer;
            buffer = new int[resizeTo];
    
            for(unsigned int i = 0; i < ((resizeTo < len) ? (resizeTo) : (len)); ++i)
                    buffer[i] = tmp[i];
    
            len = resizeTo;
            delete[] tmp;        
    }
    

    @all
    Mir ist gerade beim schreiben dieser Funktion aufgefallen, dass ich den ersten Parameter als Referenz auf Zeiger auf int schreiben muss. Ansonsten wird bei mir für buffer[0] und buffer[1] der Wert 10630024 ausgegeben? Warum ist das so? Ich dachte wenn man "nur" int* buffer schreibt, würde das reichen um die Adresse zu übergeben, damit man letzendlich das Array vergrößern kann?

    Kann mir das vielleicht jemand erklären?

    Caipi



  • Ah das heißt du kopierst die Daten immer hin und her.
    Ja das scheint auch eine gute Lösung zu sein. (Vielleicht macht es der Vector oder String genauso)
    Aber bei mir wäre das sehr Zeitintensiv glaube ich. Da ich immer am Schluß eins Anhängen muss.



  • Ovaron123 schrieb:

    Ah das heißt du kopierst die Daten immer hin und her.
    Ja das scheint auch eine gute Lösung zu sein. (Vielleicht macht es der Vector oder String genauso)

    Ehm, also vector ist da viel schlauer. Der reserviert sich sogar vorher mehr Speicher und merkt sich eigentlich zwei Variablen. Einmal für das reservierte Array und einmal den vom Benutzer tatsächlichen verbrauchten Array. Nur wenn die Reservierung tatsächlich verbraucht wird, vergrößert er die Reservervierung nochmal und das Spiel geht von vorne los. Wäre ziemlich uneffektiv, wenn bei jedem neuen Element, alles neu hin und her kopiert werden müsste.

    Es lohnt sich einfach nicht, besser als die STL zu sein. Die ist schon seit Jahren definiert und optimiert.

    Ovaron123 schrieb:

    Aber bei mir wäre das sehr Zeitintensiv glaube ich. Da ich immer am Schluß eins Anhängen muss.

    Ja, benutze einfach die push_back()-Methode, da diese ein neues Element ans Ende anfügt. Du mußt auch nicht wissen, wo das Ende ist. mit pop_back() kannst du Elemente vom Ende weg nehmene. Mit size() kannste die die Größe des Vectors abfragen.



  • vector kopiert auch jedesmal um, wenn du über seine kapazität gehst (darum auch reserve). Daher würde ich auch auch eher std::list benutzen, da das halt einfach ne (bidirectional) linked list ist und daher nicht immer alles rumkopiert werden muss, wenn was neues in die liste hinzukommt..



  • dafür ist eine liste aber speichertechnisch sehr teuer mit 2 zusätzlichen zeigern pro element...



  • hm wieviel verbrauchen denn 2 zeiger und wieviel verbrauchen 2 chararrays mit jeweils 512 elementen?


Anmelden zum Antworten