Funktionen und Arrays



  • Moin,
    ich bin noch ganz neu beim Programmieren und C++. Leider macht mein Programm nicht ganz das, was ich von ihm haben möchte und ich finde den Fehler nicht.

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <fstream>
    
    using namespace std;
    
    double Function(int **ArrayRechnen, int lange){
    double Ergebnissreturn;
    
    for (int i=0; i<=(lange-1); i++){
    for (int k=0; k<=(lange-1); k++){
        Ergebnissreturn += ArrayRechnen[i][k];
    }}
    return Ergebnissreturn;
    }
    
    int main()
    {   // Parameter
        int lange = 1000;
        int Array[lange][lange];
        int Steps= 100000000;
    
        int *Arrayb[lange];
        for (int i = 0; i < lange; ++i)
        {
            Arrayb[i] = Array[i];
        }
    
              // Füllen mit 1ern
        for (int a=0;a<lange;a++){
            for (int b=0;b<lange;b++){
                Array[a][b] = 1;
        }}
       srand(time(NULL));
       int ChooseX, ChooseY;
    
           for (int i=1; i<=Steps; i++) {
    
        ChooseX = static_cast<int> (lange*((double)rand() / (RAND_MAX)));
        ChooseY = static_cast<int> (lange*((double)rand() / (RAND_MAX)));
    
        Array[ChooseX][ChooseY]=-1*Array[ChooseX][ChooseY];
    
        double Ergebniss  = Function(Arrayb, lange);
        cout << Ergebniss << endl;
    }}
    

    Im Grunde sieht mein Programm so aus. Ich erzeuge ein 2D Array, befülle es mit Werten und rufe dann eine Funktion auf die mit bestimmten Elementen im Array rechnen muss. Bei kleinen Arraygrößen(10x10) und wenigen Steps(10000) läuft das Programm einwandfrei und es kommt das erwartet Ergebniss raus. Steigere ich aber die Größe meines Arrays oder die Anzahl der Steps, dann stürzt mein Programm ab.

    Woran könnte das liegen? Erzeuge ich bei jedem Aufruf meiner Funktion eine Kopie meines Array und die Kopien belegen irgendwann meinen Arbeitsspeicher?

    Ich wäre sehr dankbar über einen Tipp, wie ich mein Problem lösen kann.



  • erst mal grundsätzlich:
    willst du c oder c++ lernen?

    ist es eine hausaufgabe und deshalb das c-array?

    int *Arrayb[lange];             
        for (int i = 0; i < lange; ++i)
        {
            Arrayb[i] = Array[i];
        }
    

    wieso tust du das genau?

    Erzeuge ich bei jedem Aufruf meiner Funktion eine Kopie meines Array

    nein

    for (int i=1; i<=Steps; i++) {
    
        double Ergebniss  = Function(Arrayb);
        cout << Ergebniss;
    

    da fehlt was.
    bitte copy&paste deines gekürzten(!) codes.

    double Function(int **ArrayRechnen){
    double Ergebnissreturn;
    // Diverse Rechnungen mit Elementen aus dem 2D Array
    return Ergebnissreturn;
    }
    

    woher weißt du, wie lang dein array hier ist?

    bb

    PS: Ergebnis



  • Hallo Kasora:

    Ein paar Fragen und Anmerkungen:
    1: Mit was für einer Meldung stürzt dein Programm ab?
    2: Kannst du das an einer Array Größe bzw. einer Anzahl an Steps fest machen?
    3: Weist du wirklich, was folgender Code macht?

    int *Arrayb[lange];            
    for (int i = 0; i < lange; ++i)
    {
       Arrayb[i] = Array[i];
    }
    

    4: Warum überhaupt irgendwas umkopieren?
    5: Wenn du C++ benutzt, verwende std::vector oder std::array!
    6: Bist du sicher, dass dein "Diverse Rechnungen mit Elementen aus dem 2D Array" funktioniert?


  • Mod

    unskilled schrieb:

    int *Arrayb[lange];             
        for (int i = 0; i < lange; ++i)
        {
            Arrayb[i] = Array[i];
        }
    

    wieso tust du das genau?

    Das scheint mir der richtige Weg zu sein, Function mit Array verwenden zu können.

    Was nat. nicht heißen soll, dass es nicht zweckmäßiger wäre, die Signatur von Funktion anzupassen und überhaupt Containerklassen zu verwenden.


  • Mod

    Selbst wenn es C sein soll, ist die Benutzung der VLAs gerade genau anders herum, als man es haben wollte. Da wo du hier statische Compilerzeitgrenzen hättest, benutzt du VLA. Und da, wo VLA ausnahmsweise einmal nützlich wären, nämlich zur Übergabe mehrdimensionaler Arrays an Funktionen, machst du stattdessen irgendwelchen Murks:

    double Function(int **ArrayRechnen)
    

    Wichtige Regel für Arrays (Es gibt leider so viele wichtige Regeln für Arrays, dass diese hier es trotz enormer Wichtigkeit kaum in die Top-3 schafft):

    **Ein Array ist kein Zeiger und ein Zeiger ist kein Array!
    **
    Ein Array kann sich zwar unter gewissen Bedingungen wie ein Zeiger auf sein erstes Element verhalten, da ist aber auch Schluss: Ein Zeiger auf ein Array wird sich nie wie ein Zeiger auf einen Zeiger verhalten! Hier Zeiger auf Zeiger zu benutzen ist also komplett falsch, weil du die genannte Regel verletzt.



  • Danke schon mal für das vielen Antworten.

    Ich hab den Quellcode oben nochmal korrekt zusammengefasst.
    C++ möchte ich lernen.

    @Schlangemensch: Die 5 Zeilen versteh ich überhaupt nicht. Am Anfang hatte ich nur ein 1D Array und ich konnte das wunderbar in eine Funktion geben. Dann wollte ich das in 2D machen und es hat nicht mehr geklappt. Ich musste feststellen, dass ich kein 2D Array an eine Funktion geben kann. Ich habe ewig gesucht und bin irgendwie nicht schlauer geworden, wie man das korrekt macht. Dann hab ich das in einem Forum gefunden und es probiert und es hat geklappt ^^

    Bei meinem ungekürzten Programm hatte ich ein Array mit Größe 720x720 maximal geschafft zu erzeugen. Aber dadurch konnte ich nur noch 100 Schritte machen bevor es abgestürzt ist.

    Zeiger^^ Ich finde das ja noch sehr verwirrend.

    Was ist die korrekte Methode ein 2D Array an eine Funktion zu geben?


  • Mod

    Kasora schrieb:

    C++ möchte ich lernen.

    Dann mach hier Stopp. Vergiss all den Müll, den du über Zeiger und Arrays gehört hast und besorg dir stattdessen vernünftiges Lehrmaterial für C++. Nichts von alledem, was du hier gezeigt hast, würde man jemals in C++ benutzen. In C++ würde man die Container der Standardbibliothek benutzen. Die funktionieren ganz ohne komische Sonderregeln. Das heißt, du musst keine Verrenkungen anstellen, um sie in Funktionen zu benutzen, sondern es geht so einfach wie einen int an eine Funktion zu übergeben. Entsprechend sinkt auch das Fehlerpotential gewaltig.



  • Hi, ich habe mal ein grobes Grundgerüst zusammen geschrieben, damit du einen Einstieg hast.

    #include <iostream>
    #include <vector>
    
    double Function(const std::vector< std::vector <int > >& v) {
    
      return 42.; //Irgendwas was du berechnet hast...
    }
    
    int main() {
    //  Foo foo;
      const int size_i = 10;
      const int size_j = 10;
      std::vector< std::vector <int > > Array(size_i, std::vector<int>(size_j));
    
      //Als Beispiel, wie man durch ein Vektor von Vektoren durch iterieren kann
      for (auto& a : Array) {
        for (auto& number : a) {
          number = 42;
        }
      }
    
      double result = Function(Array);
    
      for (auto a : Array) {
        for (auto number : a) {
          std::cout << number << std::endl;
        }
      }  
    }
    

    Auch für die rand() Funktion gibt es inzwischen bessere Alternativen: http://www.cplusplus.com/reference/random/



  • Schlangenmensch schrieb:

    std::vector< std::vector <int > > Array(size_i, std::vector<int>(size_j));
    

    Das ist fast immer falsch; so auch hier.



  • Fytch schrieb:

    Schlangenmensch schrieb:

    std::vector< std::vector <int > > Array(size_i, std::vector<int>(size_j));
    

    Das ist fast immer falsch; so auch hier.

    Du willst mir auch bestimmt mitteilen, was daran falsch ist. Damit ich denselben Fehler nicht mehrfach mache.

    Etwas schöner wäre evt.

    std::vector< std::vector <int > > Array(size_i, std::vector<int>(size_j, 0));
    

    Dann ist auch jedes Element sicher mit 0 initialisiert.



  • Ich glaube, fytch möchte sowas sehen:

    vector<int> arr( 10 * 10 );
    

    und dann bei Elementzugriff den 2D Index auf einen linearen Index umrechnen.



  • Genau. Der semantische Unterschied zwischen std::vector< std::vector< int > > und std::vector< int > für 2D-Arrays ist, dass die erste Variante unterschiedlich lange Spalten erlaubt, was oftmals nicht erwünscht ist. Ferner braucht sie mehr Speicher und ist i.d.R. ineffizienter.



  • Ah cool danke. Lese mich jetzt in Vectoren ein und spiele damit rum.

    Ein paar Fragen hätte ich da noch:
    Was macht in der Zeile:
    double Function(const std::vector< std::vector <int > >& v) das & ???
    Warum schreibt man nicht
    double Function(const std::vector< std::vector <int>> V)

    Und was macht das auto& ??



  • Moin,
    ich hab gestern abend noch meine gesammten Quellcodes auf Vectoren umgeschrieben.
    Leider hat das den Fehler nicht behoben. Aber ich habe endlich den Fehler gefunden.

    ChooseX = static_cast<int> (lange*((double)rand() / (RAND_MAX)));
    

    Mit viel Pech wähle ich das Element "lange", aber das Array(jetzt Vektor) geht ja nur bis (lange-1). Dafür hab ich so lange gesucht in meinem Programm^^
    Jetzt komm ich mir voll dämlich vor. xD



  • Nimm besser eine std::uniform_int_distribution , dann ist auch sofort auf den ersten Blick klar, welche Range da zurückkommt. Dieses rumrechnen mit rand*irgendwas ist nicht nur fehleranfällig, sondern es liefert auch nicht exakt gleichverteilte Werte.

    Schlangenmensch hatte dich auch schon darauf hingewiesen, nicht rand() zu verwenden. Siehe auch (fun-Video): https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful Deine benutzte Formel ist in dem Video übrigens auch drin - und warum man sie NICHT benutzen sollte!



  • Kasora schrieb:

    Ah cool danke. Lese mich jetzt in Vectoren ein und spiele damit rum.

    Ein paar Fragen hätte ich da noch:
    Was macht in der Zeile:
    double Function(const std::vector< std::vector <int > >& v) das & ???
    Warum schreibt man nicht
    double Function(const std::vector< std::vector <int>> V)

    Und was macht das auto& ??

    Mit dem "&" werden Referenzen gekennzeichnet. Im Prinzip wird die Speicheradresse übergeben, wo die Variable liegt. Damit spart man sich, eine eventuelle teure Kopie. Und "const" damit man die Variable nicht verändern kann, sondern nur lesend drauf zugreifen.
    Bei dem "auto" Keywort is es ähnlich. "auto" leitet selbst den Variablen Typ her. Durch das "&" bekommst du eine Referenz. Damit die Änderungen die an den Variablen aus dem Vektor gemacht werden, auch wieder im Vektor ankommen.

    Fytch schrieb:

    Genau. Der semantische Unterschied zwischen std::vector< std::vector< int > > und std::vector< int > für 2D-Arrays ist, dass die erste Variante unterschiedlich lange Spalten erlaubt, was oftmals nicht erwünscht ist. Ferner braucht sie mehr Speicher und ist i.d.R. ineffizienter.

    Hm, wenn ich tatsächlich eine Matrix haben will, stimme ich dir da zu. Allerdings würde ich da wahrscheinlich zu einer entsprechenden Bibliothek (z.B. Eigen), greifen, denn die Umrechnung ist noch ein Punkt mehr, an dem man Fehler einbauen kann.
    Natürlich kann man das ganze auch selber kapseln und sich eine eigene Matrix Klasse schreiben, aber da war mir ein einfaches, "wie kann man mit std::vector arbeiten" Beispiel wichtiger.


Log in to reply