Unklare Compilerfehlermeldung



  • Ein statisch Array mit der Länge 2 ist nicht Typegleich mit der Länge 2+1.



  • Versteh ich nicht. Die Antwort ist zu kurz.



  • Kompilier mal:

    void doit(int x[3][3])
    {
    }
    
    int main() {
    	int a[3][2];
    	doit(a);
    	return 0;
    }
    


  • Ich sehe jetzt nicht wieso das meine Frage beantworten soll.

    Meiner Ansicht nach ist es völlig egal was für ein Array ich übergebe. Meine Methodendklaration sieht ja auch nicht so aus wie in deinem Beispiel. Mein Problem wäre das hier:

    void doit(int** x)
    {
    }
    
    int main() {
        int a[3][2];
        doit(a);
        return 0;
    }
    

    macht meiner Meinung nach das gleiche wie

    void doit(int** x)
    {
    }
    
    int main() {
        int a[67][100];
        doit(a);
        return 0;
    }
    

    a ist doch ein 2-Dimensionaler Pointer.


  • Mod

    HändyÄndy schrieb:

    void doit(int** x)
    {
    }
    
    int main() {
        int a[67][100];
        doit(a);
        return 0;
    }
    

    Ein Zeiger ist etwas anderes als ein Array. Es ist zwar richtig, dass ein Array beim Aufruf einer Funktion sich als ein Zeiger auf sein erstes Element ausgibt, hier ist dies jedoch ein Zeiger auf auf einen int[100]. Und eben nicht ein Zeiger auf einen Zeiger. Und deshalb passt dies nicht zusammen.



  • Achso. Okay, ich hab meinen Aufruf jetzt einfach modifiziert und rufe sie jetzt so auf:

    gs.gibbsSampling( (int**) ts, 48, 7, (double**) p, 49, 100, 1000, 900 );
    

    Kappt auch, finde ich allerdings jetzt nich besonders logisch, dass man das casten muss. Naja...

    Vielen Dank für die hilfreichen Antworten.



  • Ich habe mir mal erlaubt die code-tags durch cpp-tags zu ersetzen und den code neu zu formatieren...

    HändyÄndy schrieb:

    void gibbsSampling(
        int** timeSeriesData, int trows, int tcols,
        double** probs, int prows, int pcols,
        int numOfIterations,
        int numOfIterationsToSkip );
    

    und ich rufe sie so auf:

    RandomNumberGenerator rng;
    GibbsSampler gs( &rng );
    int ts[...][...];
    double p[...][...];
    gs.gibbsSampling( ts, 48, 7, p, 49, 100, 1000, 900 );
    

    HändyÄndy schrieb:

    Mir ist das nicht ganz klar, weil meinem Wissen nach ein 2-dimensionales Array doch auch als double** oder int** deklariert werden kann. Insofern müsste es doch passen wenn ich die Methode so aufrufe. Warum geht das trotzdem nicht?

    Weil Du Dich geirrt hast. Ein Zeiger auf ein Zeiger auf int (p) ist nicht dasselbe wie ein Zeiger auf ein Array aus ints (q), siehe unten.

    int a[2] = {1,2};             p     x     a            y
    int b[2] = {3,4};            [.]-->[.]-->[1]    q    +---+
    int *x[2] = {&a[0],&b[0]};         [.]   [2]   [.]-->|[1]|
    int y[2][2] = {                       \              |[2]|
       {1,2},                              \  b          +---+
       {3,4},                               >[3]         |[3]|
    };                                       [4]         |[4]|
    int **p = x;                                         +---+
    int (*q)[2] = y;
    

    Hier symbolisiert "." eine Speicheradresse. Die Elemente des y-Arrays sind wiederum Arrays.

    kk



  • HändyÄndy schrieb:

    gs.gibbsSampling( (int**) ts, 48, 7, (double**) p, 49, 100, 1000, 900 );
    

    Kappt auch, finde ich allerdings jetzt nich besonders logisch, dass man das casten muss. Naja...

    Wenn Du mit "Klappt auch" meinst, dass es kompiliert, dann ja. Wenn Du damit meinst "Es tut das, was ich will", nein, tut es nicht. Das ist ein ReinterpretCast. Hier sagst Du dem Compiler: "Hey, ich weiß es besser, also halt die Schnauze". Aber Du weißt es nicht besser. Also lass die Finger davon. Es funzt eh nicht.



  • Vielleicht Boost::Matrix verwenden?



  • Zeus schrieb:

    Vielleicht Boost::Matrix verwenden?

    Das würde ein wenig verschleiern, aber es rettet

    gs.gibbsSampling( ts, 48, 7, p, 49, 100, 1000, 900 );
    

    auch nicht. 🕶



  • HändyÄndy schrieb:

    void doit(int** x);
    
    int main() {
        int a[67][100];
        doit(a);
        return 0;
    }
    

    a ist doch ein 2-Dimensionaler Pointer.

    a ist ein Array aus Arrays und kein Zeiger. Und so etwas wie "zweidimensionale" Zeiger gibt es nicht. Es gibt aber Zeiger auf Zeiger. Du müsstest korrekterweise doit so deklarieren:

    void doit(int x[67] [100]);
    void doit(int x[123][100]);
    void doit(int x[]   [100]);
    void doit(int (*x)  [100]);
    

    (ist alles äquivalent)

    Die Geschichte der Menstru ... ähm... Zeiger und Arrays ist eine Geschichte voller Missverständnisse. Arrays sind keine Zeiger. Bei Parametertypen findet aber eine Transformation statt; denn Arrays kann man nicht "per value" übergeben. Wird ein Funktionsparameter mit dem Typ T[] oder T[N] deklariert, wird daraus automatisch ein T*. Das ist aber nur auf der obersten Ebene so. Das heißt dass ein int[2][2] zu einem int(*)[2] wird und auf der Aufruferseite ein "array-to-pointer" decay stattfindet.

    kk



  • volkard schrieb:

    Zeus schrieb:

    Vielleicht Boost::Matrix verwenden?

    Das würde ein wenig verschleiern, aber es rettet

    gs.gibbsSampling( ts, 48, 7, p, 49, 100, 1000, 900 );
    

    auch nicht. 🕶

    void gibbsSampling( int timeSeriesData[StatisticsObject::number30MinIntervals][StatisticsObject::numberOfDays], int trows, int tcols, double probs[(StatisticsObject::number30MinIntervals+1)][StatisticsObject::numberOfDays], int prows, int pcols, int numOfIterations, int numOfIterationsToSkip  );
    

    Auf Boost Matrix umsteigen, bedeutet, da fallen 4 Parameter weg.

    trows, tcols, prows, pcols 🙂



  • Zeus schrieb:

    Auf Boost Matrix umsteigen, bedeutet, da fallen 4 Parameter weg.
    trows, tcols, prows, pcols 🙂

    Ups, schnell umsteigen!



  • Meinst Du multi_array? Ja, könnte man machen.

    Ich habe mir so etwas ähnliches wie Iteratoren für beliebig-dimensionale Daten gebastelt (aber immer noch ein "rechteckiges Gitter") und benutze das gerne. Wenn's einen interessiert, versuche ich mal das Konzept durch ein Anwendungsbeispiel zu konkretisieren:

    template<typename Navigator>
    typename enable_if<(Navigator::dimensions == 2),
    void>::type show(Navigator nav)
    {
      const int width  = nav.size(0); // 1st dimension
      const int height = nav.size(1); // 2nd dimension
      const auto right = nav.make_offset(make_point(1,0));
      for (int y=0; y<height; ++y) {
        auto locator = nav.get_locator(make_point(0,y));
        for (int x=0; x<width; ++x) {
          std::cout << ' ' << *locator;
          locator += right;
        }
      }
    }
    

    Ein Navigator ist vergleichbar mit pair<Iterator,Iterator>. Ein Locator wäre der Iterator. Aber Statt ++ und -- unterstützt er += und -= in Verbindung mit einem "Offset", welcher keine Ganzzahl sein muss. Da ich aber vorwiegend ein lineares Memorylayout benutze, ist ein Locator i.d.R. ein Zeiger und Offsets vom Typ ptrdiff_t.

    kk


Anmelden zum Antworten