Frage zum Übergeben von Arrays an Funktionen



  • Hallo,

    ich möchte ein Array an eine Funktion übergeben, ich bekomme allerdings die folgende Fehlermeldung:

    invalid types `float[int]' for array subscript

    ...und ich weiß nicht warum; da ich ja eigentlich den index vom array als integer definiert habe. Ich kann mir höchstens vorstellen, dass es an der fehlerhaften verwendung (oder nicht-verwendung) von pointern liegt (kann man einer funktion ein array als argument geben?), nen bischen rumprobieren hat mich aber nicht weitergebracht....

    Hier mal der entsprechende Code aus meinem Programm:

    float lattice_energy (float lattice) {
          int n = sizeof(lattice)/(sizeof(int)*sizeof(int));
          float energy=0.;
          for (int i=n-1; i>=0; i--){
            for (int j=n-1; j>=0; j--){
                if ((j==n-1) && (i==n-1)) {
                   energy=energy-lattice[i][j]*lattice[i][0]-lattice[i][j]*lattice[0][j];
                   }
                else if (j==n-1) {
                   energy=energy-lattice[i][j]*lattice[i][0]-lattice[i][j]*lattice[i+1][j];
                   }
                else if (i==n-1) {
                   energy=energy-lattice[i][j]*lattice[i][j+1]-lattice[i][j]*lattice[i+1][j];
                   }
                else {
                   energy=energy-lattice[i][j]*lattice[i][j+1]-lattice[i][j]*lattice[0][j];
                   }
            };
          };
          return energy;
    }
    

    Vielen Dank,

    Immortalis



  • [quote="Immortalis"]Hallo,

    ich möchte ein Array an eine Funktion übergeben, ich bekomme allerdings die folgende Fehlermeldung:

    invalid types `float[int]' for array subscript

    ...und ich weiß nicht warum; da ich ja eigentlich den index vom array als integer definiert habe. Ich kann mir höchstens vorstellen, dass es an der fehlerhaften verwendung (oder nicht-verwendung) von pointern liegt (kann man einer funktion ein array als argument geben?), nen bischen rumprobieren hat mich aber nicht weitergebracht....

    Hier mal der entsprechende Code aus meinem Programm:

    float lattice_energy (float lattice[])
    

    oder das gleiche aber netter

    float lattice_energy (float* lattice)
    

    und ups, jetzt geht

    int n = sizeof(lattice)/(sizeof(int)*sizeof(int));
    

    nicht mehr!

    also

    float lattice_energy (float* lattice,int n)
    


  • volkard schrieb:

    ...

    float lattice_energy (float lattice[])
    

    oder das gleiche aber netter

    float lattice_energy (float* lattice)
    

    ...

    Übergabe eines Zeigers auf ein eindimensionales Array - ich frag mich was das soll?

    Der Threadersteller arbeitet in seiner Funktion mit einem zweidimensionalen Array.
    😃



  • Einfacher wäre es doch sicherlich hier mit den STL-Containern zu arbeiten, die kann man auch ohne Probleme an eine Funktion übergeben und brauch sich für den Moment erstmal nicht mit den Zeigern rum quälen.



  • otto8 schrieb:

    Übergabe eines Zeigers auf ein eindimensionales Array - ich frag mich was das soll?

    Der Threadersteller arbeitet in seiner Funktion mit einem zweidimensionalen Array.
    😃

    Das ist genau dasselbe. Du musst lediglich dem Compiler ein wenig arbeit abnehmen.

    @volkard:
    Ich habe ja im anderen Thread gesagt, dass die Frage oft kommt. 😉 ( und ich habe diesen nach dem anderen gelesen. )

    Und hier ist auch schon mein Standardlink:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-212469-and-highlight-is-array+2+dimensionales.html



  • drakon schrieb:

    otto8 schrieb:

    Übergabe eines Zeigers auf ein eindimensionales Array - ich frag mich was das soll?

    Der Threadersteller arbeitet in seiner Funktion mit einem zweidimensionalen Array.
    😃

    Das ist genau dasselbe. Du musst lediglich dem Compiler ein wenig arbeit abnehmen.

    Du rätst mir innerhalb der Funktion mit reinterpret_cast zu casten, nein danke!
    😉



  • otto8 schrieb:

    Du rätst mir innerhalb der Funktion mit reinterpret_cast zu casten, nein danke!
    😉

    😕
    Nö, tue ich nicht. Aber ein 2 Dimensionales Array ist eigentlich ein 1 Dimensionales Array, bei welchem die Zeilen und Spalten vom Compiler ausgerechnet werden und so ein 1 dimensionaler Zugriff generiert wird.
    Und ob du das jetzt selbst machst, oder nicht spielt überhaupt keine Rolle. (Vor allem brauchst du da keinen cast.. keine Ahung, wie du da drauf kommst..)



  • otto8 schrieb:

    Der Threadersteller arbeitet in seiner Funktion mit einem zweidimensionalen Array.

    uih, das hab ich übersehen.
    dann entweder

    float lattice_energy (float** lattice)
    

    und er hat glück. nämlich wenn er das array genau so angelegt hat, oder er muß was anderes nehmen.
    sowas wie ne klasse Array2D zu benutzen, wäre super.

    ich würde gerne sehen, wie das array erzeugt wurde.



  • drakon schrieb:

    otto8 schrieb:

    Du rätst mir innerhalb der Funktion mit reinterpret_cast zu casten, nein danke!
    😉

    😕
    Nö, tue ich nicht. Aber ein 2 Dimensionales Array ist eigentlich ein 1 Dimensionales Array, bei welchem die Zeilen und Spalten vom Compiler ausgerechnet werden und so ein 1 dimensionaler Zugriff generiert wird.
    Und ob du das jetzt selbst machst, oder nicht spielt überhaupt keine Rolle. (Vor allem brauchst du da keinen cast.. keine Ahung, wie du da drauf kommst..)

    Ich will ein zweidimensionales Array als solches ansprechen können und nicht erst alles auf ein eindimensionales Array
    wärend der Laufzeit umrechnen müssen.
    Was heisst denn dem Compiler Arbeit abnehmen anderes, als während der Laufzeit Berechnungen durchzuführen, die zur
    Compilezeit hätten erledigt werden können. Wenn ein Zeiger auf ein zweidimensionales Array übergeben werden kann,
    dann macht man das auch. Übrigens ein reinterpret_cast auf so einen Zeiger ist immernoch besser als Berrechnungen
    während der Laufzeit - diese sind nur zumutbar wenn die Dimensionen (speziell der 2. Dim) des Arrays zur Compilezeit
    nicht verfügbar sind.



  • otto8 schrieb:

    Ich will ein zweidimensionales Array als solches ansprechen können und nicht erst alles auf ein eindimensionales Array
    wärend der Laufzeit umrechnen müssen.

    Okay, dann der C++ Weg:

    // Fixe Dimensionen (Am Beispiel 4*4 Array):
    // [TR1]
    #include <array>
    
    typedef std::tr1::array<std::tr1::array<float, 4>, 4> floatarray4_4;
    float lattice_energy(floatarray4 const & lattice);
    
    // Variable Dimensionen (Am Beispiel x*y Array):
    #include <vector>
    
    typedef std::vector<std::vector<float> > floatarrayXY;
    float lattice_energy(floatarrayXY const & lattice);
    

    cu André



  • otto8 schrieb:

    Ich will ein zweidimensionales Array als solches ansprechen können und nicht erst alles auf ein eindimensionales Array
    wärend der Laufzeit umrechnen müssen.
    Was heisst denn dem Compiler Arbeit abnehmen anderes, als während der Laufzeit Berechnungen durchzuführen, die zur
    Compilezeit hätten erledigt werden können. Wenn ein Zeiger auf ein zweidimensionales Array übergeben werden kann,
    dann macht man das auch. Übrigens ein reinterpret_cast auf so einen Zeiger ist immernoch besser als Berrechnungen
    während der Laufzeit - diese sind nur zumutbar wenn die Dimensionen (speziell der 2. Dim) des Arrays zur Compilezeit
    nicht verfügbar sind.

    Das ist zur Compile Zeit nicht schon fertig. Zur Laufzeit muss auch jedesmal eine Berechnung gemacht werden. Die Frage ist nur, was Immortalis hat. Ein 2 Dimensionales Array im Sinne von int a[..][..] oder ein 2 dimensionales new-Array.

    Wenn du ein Array hast, dass zur Laufzeit bekannt ist, kann man das ja direkt in der Funktion so implementieren (siehe auch den Link, den ich gepostet habe). Aber der Vorteil, wenn du einen Zeiger auf den Anfang übergibst ist halt, dass du dann nicht auf konstante Arrays angewiesen bist und auch ein dynamische angefordertes Array genau gleich behandeln kannst.

    #include <iostream>
    
    void foo (int* a , int l , int b )
    {
    	for (int x = 0; x < l ; x++ )
    	{
    		for (int y = 0; y < b ; y++ )
    			std::cout << a[x*b+y];
    		std::cout << "\n";
    	}
    }
    
    void init (int* a , int l , int b )
    {
    	for (int x = 0; x < l ; x++ )
    		for (int y = 0; y < b ; y++ )
    			a[x*b+y] = y;
    }
    
    int main ()
    {
    	//2 dimensionales new-Array
    	int** a = new int*[5];
    	for (int x = 0; x < 5; x++ )
    		a[x] = new int[10];
    
    	//2 dimensionales Array (ist eigentlich 1 dimensional)
    	int b[5][10];
    
    	//eindimensionales Array
    	int* c = new int[5*10];
    
    	//initialisierung von a
    	for (int x = 0; x < 5; x++ )
    		for (int y = 0; y < 10; y++)
    			a[x][y] = 2;
    
    	//initialisierung von b und c
    	init ( b[0] , 5, 10);
    	init ( c , 5 , 10);
    
    	//ausgabe von a
    	for (int x = 0; x < 5 ; x++ )
    	{
    		for (int y = 0; y < 10 ; y++ )
    			std::cout << a[x][y];
    		std::cout << "\n";
    	}
    
    	//ausgabe von b und c
    	foo ( b[0] , 5 , 10 );
    	foo ( c , 5, 10 );
    
    	//freigeben
    	for (int x = 0; x < 5; x++)
    		delete[] a[x];
    	delete[] a;
    
    	delete[] c;
    }
    

    Hier siehst du, dass a der einzige Fall ist, wo du wirklich [][] brauchst. Bei den anderen beiden Fällen ist das Array immer eindimensional im Speicher abgebildet und kann somit auch so angesprochen werden. Ob du da jetzt [x][y] oder [x*10+y] hast spielt am Ende keine Rolle, da das der Compiler einfach selbst hinschreibt. Berechnet muss der Zeiger auf den int genau gleich. Ausser mit dem Nachteil, dass du dich mit deiner Variante jedem dynamischen Array schon mal verwehrst, was mit der gezeigten Variante nicht ist.

    Und siehe da. Kein einziger (expliziter) cast.

    EDIT:
    Natürlich ist eine Variante, die das ganze wrappt eleganter und sollte vorgezogen werden. Aber für das Verständnis von Arrays ist das imo schon wichtig, dass man da den Unterschied kennt zwischen den Varianten von multidimensionalen Arrays. (und welche eigentlich keine sind).



  • drakon schrieb:

    int main ()
    {
    	//2 dimensionales new-Array
    	int** a = new int*[5];
    	for (int x = 0; x < 5; x++ )
    		a[x] = new int[10];
    

    Hab jetzt nicht voll die Zeit...
    aber warum holst Du Dir dieses Array nicht einfach so:

    int(*a)[10] = new int [5][10];
    

    ?



  • Weils dann nicht voll dynamisch wäre. (du kannst da die Grössen beide zur Laufzeit bestimmen und musst sie nicht schon zur Kompilierzeit bekannt sein).



  • Hallo und danke erstmal für die zahlreichen antworten :).

    Ich habe das Ganze jetzt mit float** gemacht, dann kommt die entsprechende Fehlermeldung nicht mehr. Dazu habe ich dann noch meine Arraygröße global festgelegt, was zwar nicht schön ist, aber in diesem Falle auch nicht weiter schlimm.

    int n=10;
    
    float create_lattice (int k) {
        float z[k][k];
        for (int y=k-1; y>=0; y--){
            for (int x=k-1; x>=0; x--){
                float random = createrandom12 ();
                if (random >=0.5){
                   z[y][x]=1;}
                else {
                   z[y][x]=-1;}
                };
            };
        return z[k][k];
    }
    
    float lattice_energy (float** lattice) {
          //int n = sizeof(lattice)/(sizeof(int)*sizeof(int));
          float energy=0.;
          for (int i=n-1; i>=0; i--){
            for (int j=n-1; j>=0; j--){
                if ((j==n-1) && (i==n-1)) {
                   energy=energy-lattice[i][j]*lattice[i][0]-lattice[i][j]*lattice[0][j];
                   }
                else if (j==n-1) {
                   energy=energy-lattice[i][j]*lattice[i][0]-lattice[i][j]*lattice[i+1][j];
                   }
                else if (i==n-1) {
                   energy=energy-lattice[i][j]*lattice[i][j+1]-lattice[i][j]*lattice[i+1][j];
                   }
                else {
                   energy=energy-lattice[i][j]*lattice[i][j+1]-lattice[i][j]*lattice[0][j];
                   }
            };
          };
          return energy;
    }
    
    int main() 
    { 
        float initial_lattice=create_lattice(n);
    }
    

    Wenn ich jetzt aber mit Zeigern arbeite und nicht mit Kopien, wie bei normalen Variablen, bekomme ich ein neues Problem. Was mache ich, wenn ich nicht mein Original modifizieren will, sondern eine Kopie erstellen möchte, die ich modifizieren kann? Gibts dafür irgendeine einfache Lösung?

    float change_lattice (float** lattice){
          float new_lattice = lattice;
          //int n = sizeof(lattice)/(sizeof(int)*sizeof(int));
          for (int y=n-1; y>=0; y--){
            for (int x=n-1; x>=0; x--){
                if (lattice[x][y]==1){
                   new_lattice[x][y]==-1;
                   float d_energy=lattice_energy (lattice)-lattice_energy (new_lattice);
                   if (accept_reject(d_energy)=true)
                      new_lattice=lattice;
                   else
                      new_lattice[x][y]=1;
                }
                else {
                   new_lattice[x][y]==-1;
                   float d_energy=lattice_energy (lattice)-lattice_energy (new_lattice);
                   if (accept_reject(d_energy)=true)
                      new_lattice=lattice;
                   else
                      new_lattice[x][y]=1;
                }
            };
          };
    return new_lattice;
    }
    


  • create_lattice sollte dir crashen, wenn du das ausführst.. Du greifst da ausserhalb des Speichers zu. (beim return).

    Wenn du ein Array kopieren willst, musst du das von Hand machen. Also Objekt erstellen und jedes einzelne Element kopieren. (in einer Schlaufe).

    Ich habe allerdings das Gefühl, dass du dir nicht so sicher bist, was du da eigentlich machst.. Und würde dir daher eher zu einem Container der Standardbibliothek raten, wie schon mehrmals vorgeschlagen. Da kannst du das genauso machen, wie du es willst, kannst ohne Mühe kopieren und läufst nicht Gefahr irgendwie den Speicher/Programm zu zerschiessen.


Anmelden zum Antworten