- Akku Tests und Balkonkraftwerk Speicher         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 23

Thema: class mit übergebenen array Größen erstellen

  1. #1
    HaWe
    Gast

    class mit übergebenen array Größen erstellen

    Anzeige

    Powerstation Test
    hi,
    ich möchte eine class tMenu erstellen, die per tMenu::init(a,b) zur Laufzeit einen array tMenu::array[a][b] erzeugen kann.

    In der Art:

    Code:
    class tMenu {
      
      protected:    
      
      public:      
        
        tMenu () : 
           {  }
    
           char CAPTLEN;
           char MENULEN;
        
           void init(char captlen,  char menulen) { 
             CAPTLEN = captlen;
             MENULEN = menulen;            
           }
    
           char list[MENULEN][CAPTLEN];
    };
    
    //
    klar geht das so nicht, wegen const für array-Dimensionen -
    aber wie kriegt man es dennoch hin?

    - - - Aktualisiert - - -

    ich bin jetzt 1 Schritt weiter, über assert -
    leider kann ich damit nur einen 1-dim array erstellen, keinen 2-dim.

    wie geht das denn nun wohl...?

    Code:
    #include <cassert>
     
    class tMenu {
      
      protected:         
            char * list;
            char MENULEN, CAPTLEN;      
      
      public:      
        
         tMenu (char menulen, char captlen) // constructor
         {
            assert(menulen > 0); 
            assert(captlen > 0); 
            list = new char[menulen]; 
        //  list = new char[menulen][captlen];   // alternat. >> error!
            MENULEN = menulen;
            CAPTLEN = captlen;
         }      
    
     
         ~tMenu() // destructor
         {
           // Dynamically delete the array we allocated earlier
           delete[] list ;
         }
    
    };
    Geändert von HaWe (04.12.2018 um 07:57 Uhr)

  2. #2
    shedepe
    Gast
    Du bist schon ganz gut in der richtigen Richtung unterwegs.

    Ein multidimensional array in C++ ist eigentlich eine Liste von Pointer. D.h. list[0] z.B. liefert einen Pointer zurück, und auf diesem wird mit list[0][1] z.B. auf das 2. Element des Pointer zugegriffen.
    Deshalb kann man wie in Variante 1 das mit einer Schleife initialisieren.

    Variante 1
    Code:
    char * list;
    list = new char[menulen * captlen]
    Alternativ kann man auch einen außreichend großen Block Speicher allokieren.

    Variante 2
    Code:
    char ** list;
    list = new char*[menulen];
    for(int i = 0; i < captlen; i++)
    {
       list[i] = new char[captlen];
    }
    //Zugriff auf stelle x, y
    char val = list[x * captlen + y)
    Nachzulesen gibt es das z.B. hier: https://stackoverflow.com/questions/...in-c-using-new

    Ein Tipp außerdem: Solltest du das auf einem Mikrocontroller machen wollen solltest du auf new verzichten. Am PC würde ich auch auf die Arrays verzichten und stattdessen einen std::vector<std::vector<char>> list verwenden. Dann muss man nämlich den Speicher nicht von Hand aufräumen und hat dynamische Größen geschenkt bekommen.

  3. #3
    HaWe
    Gast
    Zitat Zitat von shedepe Beitrag anzeigen
    Du bist schon ganz gut in der richtigen Richtung unterwegs.

    Ein multidimensional array in C++ ist eigentlich eine Liste von Pointer. D.h. list[0] z.B. liefert einen Pointer zurück, und auf diesem wird mit list[0][1] z.B. auf das 2. Element des Pointer zugegriffen.
    Deshalb kann man wie in Variante 1 das mit einer Schleife initialisieren.

    Variante 1
    Code:
    char * list;
    list = new char[menulen * captlen]
    Alternativ kann man auch einen außreichend großen Block Speicher allokieren.

    Variante 2
    Code:
    char ** list;
    list = new char*[menulen];
    for(int i = 0; i < captlen; i++)
    {
       list[i] = new char[captlen];
    }
    //Zugriff auf stelle x, y
    char val = list[x * captlen + y)
    Nachzulesen gibt es das z.B. hier: https://stackoverflow.com/questions/...in-c-using-new

    Ein Tipp außerdem: Solltest du das auf einem Mikrocontroller machen wollen solltest du auf new verzichten. Am PC würde ich auch auf die Arrays verzichten und stattdessen einen std::vector<std::vector<char>> list verwenden. Dann muss man nämlich den Speicher nicht von Hand aufräumen und hat dynamische Größen geschenkt bekommen.
    danke,
    ich wollte es tatsächlich auf einem ESP oder ARM machen, evtl. aber auch kompatibel zu einem Raspi.
    (schön ntl, wenn es später auch auf AVRs läuft.)
    vector kenne ich noch nicht, aber für später ist es wichtig, dass ich prinzipiell auf diese Weise den Zugriff habe auf 2-dim arrays, sowohl intern als auch dann von der aufrufenden Funktion:

    this->char list[10][20]={"line0", "line1", "line2", "line3",..., "line9"};
    Serial.println(this->list[k]);

    tMenu mymenu(10,20);
    strcpy(mymenu.list[5], "5 new testline", sizeof(testline));
    mymenu.list[5][0]='>';

    also Zugriff direkt auf die 2-dim Struktur, ohne immer rechnen zu müssen
    x * captlen + y

    Wie macht man es also am besten, cross-over-Plattform-kompatibel?
    Geändert von HaWe (04.12.2018 um 09:46 Uhr)

  4. #4
    shedepe
    Gast
    Für den ESP32 kann ich leider nichts sagen.
    Deshalb erläutere ich kurz die Überlegung dahinter warum man auf einem Mikrocontroller in der Regel keinen Speicher dynamisch allokieren möchte.
    Das Problem dabei ist: Wenn man Speicher mit malloc oder new allokiert, wird dieser intern von der libc verwaltet. Diese schaut prinzipiell wo ist noch Speicher übrig bzw. wo ist genügend speicher am Stück übrig. Wenn man jetzt aber z.B. auf einem Atmega sehr wenig Speicher hat, wird dieser sehr schnell durchlöchtert wenn man häufiger Speicher reserviert bzw. wieder frei gibt. Die libc implementiert zwar Algorithmen um diesen Speicher möglichst intelligent zu verwalten, das funktioniert nur mit sowenig Speicher nicht so super bzw. kann sehr viel Performance klauen. Zudem kann man nicht zur compilezeit sagen ob der Speicher überhaupt reicht.

    Bei größeren Controllern wie dem ESP32 kann es durchaus möglich sein, dass effizient mit dynamisch allokiertem Speicher umgegangen werden kann.

    Ob es Sinn macht die Container aus der C++ Standardlib zu verwenden auf dem ESP32, müsstest du auch noch mal recherieren. Diese machen einem das Leben wesentlich leichter, kosten aber natürlich auch etwas mehr Speicher und CPU Leistung.

  5. #5
    HaWe
    Gast
    neinnein, ich habe "nur" einen esp8266, alternativ M0, M3, M4, aber es wäre ntl schön auch auf dem Raspi und auch AVR Mega oder gar Nano: grundsätzlich eben Plattform-unabhängig.
    Das mit den Löchern verstehe ich, aber es wird vorraussichtlich nicht so häufig passieren mit dem destructor, viel häufiger werden constructors nacheinander aufgerufen werden.

    Was würdest du also vorschlagen für die Erzeugung von 2-dim arrays
    - wichtig, wie gesagt, ist der direkte Zugriff auf alle einzelnen Speicherzellen beider Dimensionen, ohne so etwas wie
    x * captlen + y
    rechnen zu müssen,
    so z.B. wie bereits oben erwähnt

    tMenu mymenu(10,20);
    strcpy(mymenu.list[5], "5 new testline", sizeof(testline));
    mymenu.list[5][0]='>';

  6. #6
    shedepe
    Gast
    Mein Vorschlag wäre: Mache eine Klasse, wie du sie jetzt schon hast. Lege aber die Instanzen des Klassen auf dem Stack an.
    Also statt tMenu * mymenu = new tMenu(); lieber tMenu myMenuy;

    Dann solltest du die Größen statt über den Konstruktor lieber als C++ Template übergeben. Dann können die zur Compilezeit ersetzt werden.
    Dann kannst du dein array auch mit: char mylist[x][y] anlegen.

    Beispiel
    Code:
    template <int x_size,int y_size>
    class Menu{
         private:
             char list[x_size][y_size];
         
    
    
    };
    
    Verwendung:
    Menu<10,20> myMenu;
    Noch ein Hinweis zum Rechnen (Falls das mal relevant für dich werden sollte):
    Einfach den Zugriff in einer Methode Kapseln die das Rechnen macht und dann ist das auch gar nicht so schlimm

  7. #7
    HaWe
    Gast
    hmm, vielen lieben Dank, das klingt alles wirklich gut. Ich muss jetzt nur noch alles ineinander kriegen, tatsächlich ist dieses hier erst mein zweites C++ OOP Projekt überhaupt.

    Erstmal, ist private besser als protected? Oder geht beides? Ist protected evtl flexibler für Zugriffe von "außen" und "innen"?

    dann zu
    Also statt tMenu * mymenu = new tMenu(); lieber tMenu myMenu;
    ja: so hatte ich es ja auch vor als Instanz: tMenu myMenu;


    Das wäre jetzt, was ich aus deinen Vorschlägen verstanden habe, mit int16_t als Kompromiss zw. char und int für die sizes,
    allerdings völlig unklar wie der constructor jetzt aussehen muss , also wie genau ich den array samt seines Speicherbedarfs dynamisch erzeugen soll:

    Code:
    class tMenu{
       private :
    
           int16_t  MENULEN, CAPTLEN;      
           char list[MENULEN][CAPTLEN];
    
       public:      
        
         tMenu (int16_t menulen, int16_t captlen) // constructor
         {       
            MENULEN = menulen;
            CAPTLEN = captlen;
    
            // .... und wie weiter hier?
         }      
    
     
         ~tMenu() // destructor
         {
           // Dynamically delete the array we allocated earlier
           delete[] list ;
         }
    
    };
    Edit:
    zusätzlich rechnen möchte ich ja nicht, weder innerhalb der Klasse noch außerhalb bei Verwendung von Instanzen.
    Instanziierung würde ich auch am liebsten ohne template machen, wenn möglich, einfach per

    tMenu mymenu(10,20);

    für solche Manipulationen in main oder loop:

    strcpy(mymenu.list[5], "5 new testline", sizeof(testline));
    mymenu.list[5][0]='>';
    Geändert von HaWe (04.12.2018 um 12:43 Uhr)

  8. #8
    HaWe
    Gast
    wie muss denn also dafür der construcor für den "echten" dynamischen 2-dim array aussehen?

    denn diese beiden Methoden

    Code:
    char * list;
    list = new char[menulen * captlen]
    
    char ** list;
    list = new char*[menulen];
    for(int i = 0; i < captlen; i++)
    {
       list[i] = new char[captlen];
    }
    
    //Zugriff auf stelle x, y
    char val = list[x * captlen + y)
    scheinen ja nur jew. einen 1-dim array zu erzeugen....?

  9. #9
    HaWe
    Gast
    also dies funktioniert nicht

    Code:
    class tMenu {
      
      protected:    
            int16_t  MENULEN, CAPTLEN;     
            char    list[MENULEN][CAPTLEN];      
                  
      
      public:      
        
         tMenu (int16_t menulen, int16_t captlen) // constructor
         {
            MENULEN = menulen;
            CAPTLEN = captlen;
           
            list = new char*[menulen];
            for(int i = 0; i < captlen; i++)
            {
              list[i] = new char[captlen];
            }
            
         }      
    
    };
    exit status 1
    invalid use of non-static data member 'tMenu::MENULEN'

    so auch nicht:
    Code:
    class tMenu {
      
      protected:    
            int16_t  MENULEN, CAPTLEN;                  
            char    **list;      
      
      public:      
          
         tMenu (int16_t menulen, int16_t captlen) // constructor
         {
            MENULEN = menulen;
            CAPTLEN = captlen;
           
            list = new char*[menulen];
            for(int i = 0; i < captlen; i++)
            {
              list[i] = new char[captlen];
            }
            
         }      
    }; 
    
    tMenu mymenu(20,10);
    //...
      char test[15]="5 newline_";
      strcpy(mymenu.list[5], test);
    exit status 1
    'char** tMenu::list' is protected

    dies funktioniert offenbar, von außen aufgerufen

    Code:
    class tMenu {
      
      protected:    
            int16_t  MENULEN, CAPTLEN;                  
              
      
      public:      
         char    **list;     
         tMenu (int16_t menulen, int16_t captlen) // constructor
         {
            MENULEN = menulen;
            CAPTLEN = captlen;
           
            list = new char*[menulen];
            for(int i = 0; i < captlen; i++)
            {
               list[i] = new char[captlen];
            }
            
         }      
    
     
         ~tMenu() // destructor
         {
           // Dynamically delete the array we allocated earlier
           delete[] list ;
         }
    
    };
     
    
    tMenu mymenu(20,10);
    
    void setup(void)
    {
      // Start Serial
      
      Serial.begin(115200);
      delay(2000); // wait for Serial()
      Serial.println("Serial started");
      
      char test[15]="5 newline_";
      strcpy(mymenu.list[5], test);
      Serial.println(mymenu.list[5]);
      mymenu.list[5][0]='>';
      Serial.println(mymenu.list[5]);
      //
    }
    - - - Aktualisiert - - -

    was allerdings nicht funktioniert, ist die Benutzung der array Zellen intern,
    z.B. per init cstrings reinkopieren:


    Code:
    class tMenu {
      
      protected:    
            int16_t  MENULEN, CAPTLEN; 
            char buf[20];                 
              
      
      public:      
         char    **list;     
         tMenu (int16_t menulen, int16_t captlen) // constructor
         {
            MENULEN = menulen;
            CAPTLEN = captlen;
           
            list = new char*[MENULEN];
            for(int i = 0; i < CAPTLEN; i++)
            {
              list[i] = new char[CAPTLEN];
            }        
         }      
         
         void init() {
            for(int i=0; i<MENULEN; i++) {
               sprintf(buf,"%d line %d", i);
               strcpy(list[i], buf);
            }
         }
    
     
         ~tMenu() // destructor
         {
           // Dynamically delete the array we allocated earlier
           delete[] list ;
         }
    
    };
    
    //
      tMenu mymenu;
      mymenu.init();
    Exception (29):
    epc1=0x40205d7b epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

    ctx: cont
    sp: 3fff0250 end: 3fff0550 offset: 01a0

    >>>stack>>>
    3fff03f0: 00000022 3ffef4fc 00000028 402025a3
    3fff0400: 3ffe9d80 4010560e feefeffe feefeffe
    3fff0410: feefeffe feefeffe 00000000 4000050c
    3fff0420: 3fffc278 40105464 3fffc200 00000022
    3fff0430: 3fff0440 feefeffe feefeffe feefeffe
    3fff0440: 402040f9 00000030 0000001e ffffffff
    (usw...)
    <<<stack<<<
    - - - Aktualisiert - - -

    auch so geht es nicht:
    Code:
       void init() {
            for(int i=0; i<MENULEN; i++) {
               sprintf(buf,"%d line %d", i);
               strcpy(list[i*CAPTLEN], buf);
            }
         }
    wie muss man jetzt stattdessen this->init() richtig codieren?
    Geändert von HaWe (05.12.2018 um 09:00 Uhr)

  10. #10
    HaWe
    Gast
    also noch mal 1 Schritt zurück:
    offenbar lässt sich list[MENULEN][CAPTLEN] intern noch nicht richtig ansprechen, indem man Werte für die Zellen , z.B. cstrings, in die Zellen reinkopiert, genau wie man es von außen per Aufruf einer Instanz können soll:

    Code:
      strcpy(mymenu.list[5], test);  
      Serial.println(mymenu.list[5]);
      mymenu.list[5][0]='>';
      Serial.println(mymenu.list[5]);
    wie muss man intern in der class einen 2-dim array
    list[MENULEN][CAPTLEN]
    erzeugen, damit man auch intern mit Objekt-Methoden seine Zellen einzeln ansprechen und manipulieren kann?
    Noch nicht einmal mit "rechnen"
    list[i*CAPTLEN]...
    geht es ja bisher...?



    Code:
    class tMenu{
       private :
    
           int16_t  MENULEN, CAPTLEN;      
          
    
       public:      
        
         tMenu (int16_t menulen, int16_t captlen) // constructor
         {       
            MENULEN = menulen;
            CAPTLEN = captlen;
    
            // .... wie ist public list[MENULEN][CAPTLEN] zu erzeuen?     }      
    
    
    };
    Geändert von HaWe (05.12.2018 um 16:42 Uhr) Grund: typo

Seite 1 von 3 123 LetzteLetzte

Ähnliche Themen

  1. Change member of a class from another class
    Von iciwi im Forum Arduino -Plattform
    Antworten: 1
    Letzter Beitrag: 27.08.2016, 09:45
  2. neues Byte aus Byte-Array erstellen
    Von BoondockDuck im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 4
    Letzter Beitrag: 06.09.2008, 07:53
  3. Bits in sämtlichen Größen :)
    Von squelver im Forum Allgemeines zum Thema Roboter / Modellbau
    Antworten: 0
    Letzter Beitrag: 22.11.2007, 12:02
  4. SMD-Größen für SMD-Anfänger
    Von jeybo im Forum Elektronik
    Antworten: 22
    Letzter Beitrag: 29.08.2006, 07:04
  5. Eagle - Größen
    Von BlackDevil im Forum Konstruktion/CAD/3D-Druck/Sketchup und Platinenlayout Eagle & Fritzing u.a.
    Antworten: 9
    Letzter Beitrag: 27.03.2006, 22:58

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests