Arraygröße aus Dateiangabe initialisieren



  • NDEBUG schrieb:

    tt ... nein. Sag mal ~fricky probierst du auch den Code den du hier postest vorher?!

    // ...
    int static_array[256][256];
    *(static_array + 3 * 256 + 2) = 5;  // geht nicht
    

    weil der typ nicht stimmt. du müsstest es so schreiben:

    *((int*)static_array + 3 * 256 + 2) = 5;
    

    es ändert aber nichts an der berechnung der adresse eines elements. bei mehrdimensionalen arrays hängt alles hintereinander im speicher, also kein pointer auf pointer auf pointer usw...

    NDEBUG schrieb:

    Gibt es dafür auch eine Lösung, wenn Zeilen und Spalten dynamisch eingelesen werden? Im Moment muß zumindest "spalten" zur Compilierzeit ja bekannt sein.

    nee, zur compile-zeit muss eine dimension (bei 2d-arrays) bekannt sein, weil der compiler damit den effektiven offset berechnen muss (siehe oben).
    🙂



  • Tim schrieb:

    Ja, man nimmt einfach einen T** und alloziert einmal Spalte und dann die Zeilen, also die klassische Variante die du schon vorgeschlagen hast 😉

    Ich stell mir vor, dass ein int-Array mit 100444 Zeilen und 5 Spalten dynamisch erzeugt werden soll. Zeilen- und Spaltenanzahl sind zur Compilezeit nicht bekannt.
    Bei der "klassischen Methode" 100445 Aufrufe von malloc() um das Array zu erzeugen und 100445 Aufrufe von free(), um den Speicher wieder freizugeben.

    Folgendes Beispiel in C++ erledigt diese Aufgabe mit einem Aufruf von new()und delete[].

    template<typename T>
    T** const new_2d(const int z, const int s) 
    {
    	T** const a = new T*[z+(z*s*sizeof(T))/sizeof(T*)+1];
    
    	for (size_t i = 0; i < z; i++)
    		a[i] = ((T*)&a[z])+i*s;
    
    	return a;							
    }
    
    template<typename T> inline void delete_2d(T** const ptr)  { delete[] ptr; }
    
    int main()
    {
    	int zeilen  = 100444;
    	int spalten = 5;
    
    	int** const array = new_2d<int>(zeilen, spalten);
    
    	array[48532][3] = 4711;
        int test = array[48532][3];
    
    	delete_2d<int>(array);
    }
    

    Mit einem Aufruf von malloc() und free() sollte das auch in C zu programmieren sein!
    😉



  • Wilma schrieb:

    Mit einem Aufruf von malloc() und free() sollte das auch in C zu programmieren sein!

    ja, weniger kryptisch und ohne pointer-auf-pointer orgien.

    // 'array' objekt
    typedef struct array2d
    {
      int *data;
      int width;
      int height;
    } array2d_t;
    
    // 'array' anlegen
    int create (array2d_t *arr, int width, int height)
    {
      arr->data = malloc (width * height * sizeof(int));
      if (arr->data == 0)
        return 0;
      arr->width = width;
      arr->height = height;
      return 1;
    }
    
    // 'array' loeschen
    void delete (array2d_t *arr)
    {
      free (arr->data);
    }
    
    // lesezugriff
    int get (array2d_t *arr, int x, int y)
    {
      return arr->data[x + arr->width*y];
    }
    
    // schreibzugriff
    void put (array2d_t *arr, int x, int y, int v)
    {
      arr->data[x + arr->width*y] = v;
    }
    
    // test
    int main (void)
    {
      array2d_t arr;
      int test;
    
      if (0 == create (&arr, 100444, 5)) // array anlegen
      {
        puts ("f*ck!!!");
        exit (0);
      }
      put (&arr, 48532, 3, 4711);   // array[48532][3] = 4711;
      test = get (&arr, 48532, 3);  // test = array[48532][3];
      delete (&arr);                // wech damit
    
      printf ("%d\n", test);
    }
    


  • Wilma schrieb:

    Tim schrieb:

    Ja, man nimmt einfach einen T** und alloziert einmal Spalte und dann die Zeilen, also die klassische Variante die du schon vorgeschlagen hast 😉

    Ich stell mir vor, dass ein int-Array mit 100444 Zeilen und 5 Spalten dynamisch erzeugt werden soll. Zeilen- und Spaltenanzahl sind zur Compilezeit nicht bekannt.
    Bei der "klassischen Methode" 100445 Aufrufe von malloc() um das Array zu erzeugen und 100445 Aufrufe von free(), um den Speicher wieder freizugeben.

    a) es mag sicher Situationen geben in der die klassische Methode nicht optimal ist. Ich habe sicher nichts anderes behauptet. Und komplexer wird die Lösung durch extreme Größen auch nicht.

    b) Warum das ganze nicht transponiert ablegen?

    c) Viel Spass beim Ändern der Größe.



  • Tim schrieb:

    a) es mag sicher Situationen geben in der die klassische Methode nicht optimal ist. Ich habe sicher nichts anderes behauptet. Und komplexer wird die Lösung durch extreme Größen auch nicht.

    ... sondern nur extrem langsam.

    Tim schrieb:

    b) Warum das ganze nicht transponiert ablegen?

    Ein echter Tim- Brocken ... was meinst Du damit? Singen statt in C minor in C#?

    Tim schrieb:

    c) Viel Spass beim Ändern der Größe.

    Ich glaube, Du überbewertest das. Erstens ist resizen bei der klassischen Methode sowieso schon nicht trivial und zweitens dürften die Aufgabenstellungen hauptsächlich darauf fallen, daß Du zur Compiletime keinen Pfiff Ahnung hast, wie groß das maximal wird, was Du zu bearbeiten hast, das aber zur Runtime feststellen kannst. Dann schnappe ich mir den Speicher bevorzugt komplett und schmeiße ihn genauso hinterher wieder weg.
    Zudem führt die Mikrospeicherhäppchenverwaltung zur Fragmentierung, was bei fehlender GC entsprechende Probleme nach sich zieht.

    Ich vermute daher eher, daß die "klassische Methode" in den selteneren Fällen die Optimale ist.



  • pointercrash() schrieb:

    Tim schrieb:

    b) Warum das ganze nicht transponiert ablegen?

    Ein echter Tim- Brocken ... was meinst Du damit? Singen statt in C minor in C#?

    er will zeilen mit spalten vertauschen, um weniger pointer zu haben. bei 'ner grossen, quadratischen matrix oder bei mehr als zweidimensionalen arrays ist das aber auch doof.
    🙂



  • ~fricky schrieb:

    pointercrash() schrieb:

    Tim schrieb:

    b) Warum das ganze nicht transponiert ablegen?

    Ein echter Tim- Brocken ... was meinst Du damit? Singen statt in C minor in C#?

    er will zeilen mit spalten vertauschen, um weniger pointer zu haben. bei 'ner grossen, quadratischen matrix oder bei mehr als zweidimensionalen arrays ist das aber auch doof.
    🙂

    Ich denke, er meint pointercrash()s Ansatz, d.h. das Arrays manuell zu "flatten" und als eindimensionales Array abzulegen und sich später über Offsets die korrekte Postition zu berechnen eines Elements.

    Mit einem Aufruf von malloc() und free() sollte das auch in C zu programmieren sein!

    Auch wenn ich hier der Spielverderber sein muß, aber bisher hat kein Versuch, das Problem gelöst. Hier noch mal die Anforderungen:

    1. die Dimensionen (Höhe, Breite) werden erst zur Laufzeit ermittelt,
    2. mit diesen Dimensionen soll ein Array mit einem einzigen malloc-Aufruf erzeugt werden, auf das
    3. mit array[x][y] zugegriffen werden kann (0 <= x < höhe, 0 <= y < breite).
    4. Die Lösung muß in Ansi-C geschrieben sein.

    Der erste gute Ansatz in C setzte vor_raus, daß "spalten" zur Kompilierzeit bekannt ist und verstößt gegen 1).

    Der C++ Ansatz erfüllt alle drei Anforderungen, ist aber C++ und verstößt damit gegen 4).

    pointercrash()s Ansatz erüllt 1), 2) aber nicht 3).

    Happy coding! In meinen Augen nicht möglich, vllt bin ich aber auch einfach nur zu dämlich 😉



  • NDEBUG schrieb:

    Auch wenn ich hier der Spielverderber sein muß, aber bisher hat kein Versuch, das Problem gelöst. Hier noch mal die Anforderungen:

    1. die Dimensionen (Höhe, Breite) werden erst zur Laufzeit ermittelt,
    2. mit diesen Dimensionen soll ein Array mit einem einzigen malloc-Aufruf erzeugt werden, auf das
    3. mit array[x][y] zugegriffen werden kann (0 <= x < höhe, 0 <= y < breite).
    4. Die Lösung muß in Ansi-C geschrieben sein.

    Happy coding! In meinen Augen nicht möglich, vllt bin ich aber auch einfach nur zu dämlich 😉

    Hab' noch ein Ding gefunden, das bei quadratischen Arrays funktioniert hat, also Höhe = Breite. Da es ein Sonderfall ist, hab' ich's nicht gepostet, magst es haben? (muß es aber noch entmüllen).



  • NDEBUG schrieb:

    Der C++ Ansatz erfüllt alle drei Anforderungen, ist aber C++ und verstößt damit gegen 4).
    ...In meinen Augen nicht möglich...

    warum sollte in C nicht gehen, was in C++ möglich ist?
    🙂



  • Hab' noch ein Ding gefunden, das bei quadratischen Arrays funktioniert hat, also Höhe = Breite. Da es ein Sonderfall ist, hab' ich's nicht gepostet, magst es haben? (muß es aber noch entmüllen).

    Klar!

    warum sollte in C nicht gehen, was in C++ möglich ist?

    Wenn du eine Möglichkeit siehst, ein Programm zu schreiben, das die Anforderungen erfüllt. Poste es!



  • NDEBUG schrieb:

    Wenn du eine Möglichkeit siehst, ein Programm zu schreiben, das die Anforderungen erfüllt. Poste es!

    ungefähr so:

    #define TYPE int
    
    TYPE **Create2DArrayAsPointerList (int width, int height)
    {
      int s, plain;
      TYPE *a, **b;
    
      plain = width * height * sizeof(TYPE);
      a = malloc (plain + height * sizeof (TYPE*));
      if (a == 0)
        return 0;
    
      b = (TYPE**)(a + plain);
    
      for (s=0; s<height; s++)
        b[s] = a + s*height; 
    
      return b;
    }
    ...
    TYPE **p = Create2DArrayAsPointerList (..., ...);
    p[x][y] = irgendwas;
    ...
    

    🙂



  • NDEBUG schrieb:

    Hab' noch ein Ding gefunden, das bei quadratischen Arrays funktioniert hat, also Höhe = Breite. Da es ein Sonderfall ist, hab' ich's nicht gepostet, magst es haben? (muß es aber noch entmüllen).

    Klar!

    So, das hat 2004 funktioniert und tut immer noch. Warum es nicht mit abweichenden Dimensionen will, weiß ich momentan nicht, bzw, was man dagegen tun kann. Bin unter Zeitdruck und hab bald wieder die Quengler am Hals 😉

    void square(void)
    {	
    	int i, j, back, ad;
    	const int dim = 5;
    	const int zeilen = dim, spalten = dim;
    
    	int *adresse;
    	int *feld;
    	int **array;
    	feld = malloc( sizeof(int) * zeilen * spalten);
    	if (feld)
    	{
    		back = 0;
    		for (i = 0; i < zeilen; i ++)
    			for (j = 0; j < spalten; j++)
    				feld[i * zeilen + j] = back++;
    	}
    	array = malloc(sizeof(int*) * zeilen);
    
    	if (array)
    	{
    
    		for (i = 0; i < zeilen ; i++ )
    		{
    			adresse = (feld + (spalten * i));
    			array[i] = adresse;
    		}
    
    		for (i = 0; i < zeilen; i ++)
    			for (j = 0; j < spalten; j++)
    				back = array[i][j];
    	}
    }
    


  • ^^du musst noch die mallocs zusammenschieben.
    🙂



  • ~fricky schrieb:

    ^^du musst noch die mallocs zusammenschieben.
    🙂

    Ja, ich hab's schon gesehen, Du hängst einfach an, ich hab's auf zwei mallocs verteilt. Ist immer noch weniger, als eine Batterie von mallocs durchzureißen.
    Ich hab' damals als frischer C- Wiedereinsteiger so Matrizen gelagert, aber nie wieder genau das Problem gehabt, aber auch heute mag es keine krummen Dimensionen, war ein vertagtes Problem, das nie wieder aktuell geworden ist.
    Vielleicht kannst Du in kurzen Worten sagen, was da schiefhängt?
    Muß bloß jetzt wieder los, die Gschroppen einschmieren (Kinder haben Windpocken) und im Wohnzimmer fasse ich bei dem Radau eh keinen ruhigen Gedanken. :p



  • Sieht gut aus. Noch nicht getestet, aber was ich nachvollziehen kann, macht es das was verlangt ist. Bis auf eine Kleinigkeit, auch wenn ihc mich irren kann, müßte es nicht so heißen?

    ~fricky schrieb:

    // ...
    for (s=0; s<height; s++)
        b[s] = a + s*width; // statt s*height; 
    // ...
    

    pointercrash() dein Listing schau ich mir nachher zu Hause an.

    Danke!



  • NDEBUG schrieb:

    Bis auf eine Kleinigkeit, auch wenn ihc mich irren kann, müßte es nicht so heißen?

    ~fricky schrieb:

    // ...
    for (s=0; s<height; s++)
        b[s] = a + s*width; // statt s*height; 
    // ...
    

    kann sein, hab's nur schnell hingehackt und oberflächlich getestet. diese pointerlisten-sache finde ich sowieso reichlich blödsinnig. sinnlose speicherverschwendung, nur um array[x][y] schreiben zu dürfen.
    🙂



  • ~fricky schrieb:

    NDEBUG schrieb:

    Bis auf eine Kleinigkeit, auch wenn ihc mich irren kann, müßte es nicht so heißen?

    ~fricky schrieb:

    // ...
    for (s=0; s<height; s++)
        b[s] = a + s*width; // statt s*height; 
    // ...
    

    kann sein, hab's nur schnell hingehackt und oberflächlich getestet. diese pointerlisten-sache finde ich sowieso reichlich blödsinnig. sinnlose speicherverschwendung, nur um array[x][y] schreiben zu dürfen.
    🙂

    hey, ich bin anfänger, eig war meine frage nur, ob´s möglich ist... weil ich mir nich ausmalen konnte, ob sowas überhaupt funktioniert 😞



  • TTP schrieb:

    hey, ich bin anfänger, eig war meine frage nur, ob´s möglich ist... weil ich mir nich ausmalen konnte, ob sowas überhaupt funktioniert

    kein problem, irgendwie bekommt man alles hin.
    btw. mein code von da oben^^ ist übrigens ziemlicher mist. zeigt zwar das prinzip, aber es sind viele bugs drin. z.b. kann man den speicher nicht free'n, weil die pointerliste hinten ist.
    🙂



  • hmm, dann frag ich ma direkt:
    mit welchem Code setzt ich das denn jetzt ab besten um? ich hab jetzt die version die "tausend" mal allokiert und free't



  • Kommt auf die Größe des Arrays und deine Anforderungen an. Wenn du unbedingt mit array[x][y] auf die Daten zugreifen möchtest, dann würde ich im Moment noch mit der "klassichen" Methode arbeiten, sonst würde ich auf jedenfall mit pointercrash()s "flattening" Methode arbeiten. Weiterhin ist die Frage, ob du dein Array oft in der Größe ändern mußt. Das würde dann wieder für die Klassische Methode sprechen, da realloc den Inhalt der alten Speicherbereiche mit in die neuen Speicherberieche übernimmt. Mit pointercrash()s Methode müßtest du die Werte manuell wieder richtig anordnen. Und ~frickys Ansatz funzt aber ist eher ein Hack.

    Kommt also drauf an!


Anmelden zum Antworten