0

I have a function in my class which should get a multi-dimensional array. the problem is that the value of these dimensions is calculated in the class, using another function and is stored in some public variables. so all the other functions within the class can read the value stored in these vars. the definition of function is like this:

double calcSS(double tfpairexp[][max_ctrl_no][max_rep_no])

where max_ctrl_no and max_rep_no are those public variables. and I call the function like this:

calcSS(tfpairexp);

but the compiler gives error for the definition of the function. and if I put some constant numbers instead of those vars, there is no error. But I don't know the dimension when the program begins. what should I do?

Update

void tripleofgenes(int begind,int endind) {             
            for (int tf1=0; tf1<tfact; ++tf1)
            {   
                    for (int tf2=tf1+1; tf2<tfact; ++tf2)
                    { 
                        double tfpairexp[cchips][max_ctrl_no][max_rep_no];
                        double w,d;
                        int ctrl_no;int c, ctr;
                        for (int j = 0; j < cchips ; j += c)
                        {
                            c = chips[j].crepls;
                            int ctrl_no=0;
                            for (int *p = chips[j].ctrl ; p && (ctr=*p)>=0; ++p,ctrl_no++) {
                                for (int k = 0; k < c; ++k)
                                {
                                    double tf1exp=chips[k+j].vals[tf1].val-((chips[k+j].useextra) ? chips[ctr].extra[tf1] : chips[ctr].mean[tf1].val);
                                    double tf2exp=chips[k+j].vals[tf2].val-((chips[k+j].useextra) ? chips[ctr].extra[tf2] : chips[ctr].mean[tf2].val);
                                    tfpairexp[j][ctrl_no][k]=interactionFunc(tf1exp,tf2exp,1);
                                }
                            }
                        }
                        for (int tg=begind; tg<=endind; ++tg) 
                            if (tf1!=tg){

                        calcSS(tfpairexp);

                        }


                    }
            }
        fclose(f);
    }

    double calcSS(double ***tfpairexp)
    {
    for (int row = 0; row <= 1 ; row++)
                for (int col = 0; col <= 1 ; col++) {
                    int cond=0;
                    for (int j = 0; j < cchips; j += c) {
                        c = chips[j].crepls; // the number of replicants
                        int ctrl_no=0;
                        for (int *p = chips[j].ctrl; p && (ctr=*p)>=0; ++p,ctrl_no++) {
    a = tfpairexp[j][ctrl_no][k];}
    }
    }
    }
    }
Sampson
  • 265,109
  • 74
  • 539
  • 565
Pegah
  • 672
  • 2
  • 13
  • 23
  • void tripleofgenes(int begind,int endind) { for (int tf1=0; tf1 – Pegah Jan 24 '11 at 14:33
  • @Pegah: this function and calcSS() both is defined in your class, right? – Nawaz Jan 24 '11 at 14:33
  • @Pegah: then you don't need to pass dimensions, as you already have them in that function. Just define your `calcSS()` as `calcSS(double ***arr)`.. and access the elements as `arr[i][j][k]` as you usually do! – Nawaz Jan 24 '11 at 14:33
  • I have done it exactly this way. You can see it up there too. But it says here: calcSS(tfpairexp); that I call calcSS, that it can't find the proper function. – Pegah Jan 24 '11 at 14:33
  • @Pegah: see my answer again; i've updated it. by the way, can you post the error message also? why don't you post all relevant things at once? – Nawaz Jan 24 '11 at 14:33
  • @Nawaz: It doesn't matter that you know the dimensions, you cannot convert a `char[][x][y]` to a `char***`. They are not compatible types. – CB Bailey Jan 24 '11 at 14:33
  • @Pegah: if possible, paste both these functions here at pastebin: http://pastebin.com/ .. and give me the link.. – Nawaz Jan 24 '11 at 14:33
  • the error is in German, because my linux is German. It says: Keine passende Funktion fuer Aufruf von net::calc(double &), – Pegah Jan 24 '11 at 14:33
  • @Charles: that is what confuses me; his posts are not clear enough to me. – Nawaz Jan 24 '11 at 14:33
  • http://pastebin.com/xgnsyTnH I think Charles is right. – Pegah Jan 24 '11 at 14:33
  • @Pegah: when you call your function, do this : `calcSS((double ***)tfpairexp)`... that is, cast it to `double***` type.... and follow the function as I defined it in my answer. – Nawaz Jan 24 '11 at 14:33
  • thanks. during compile it gives no error. but when running, when it comes to d=tfpairexp[j][ctrl_no][k]; it gives this error: "Segmentation fault" – Pegah Jan 24 '11 at 14:33
  • @Pegah: It looks you dont know even the basics of C++. Your index exceeds the maximum value! – Nawaz Jan 24 '11 at 14:33
  • No I know these things. when I put the "for"s which fill the array, in the calcSS function itself, there is no error and it works fine. But I want to send it through another function to calcSS, and I have copy/pasted the exact for into triple function. Of course I know that the index should not exceed. – Pegah Jan 24 '11 at 14:33
  • for (int j = 0; j < cchips ; j += c) { c = chips[j].crepls; int ctrl_no=0; for (int *p = chips[j].ctrl ; p && (ctr=*p)>=0; ++p,ctrl_no++) { for (int k = 0; k < c; ++k) { [k]=interactionFunc(tf1exp,tf2exp,1); } } } – Pegah Jan 24 '11 at 14:33
  • was in the calcSS func. and it worked corectly. which shows that there is no problem with the indexes. the problem arose when I decided to calculate the values of array outside calcSS and send it to calcSS. anyway, thanks for the answers. – Pegah Jan 24 '11 at 14:33
  • was in the calcSS func. and it worked corectly. which shows that there is no problem with the indexes. the problem arose when I decided to calculate the values of array outside calcSS and send it to calcSS. Thanks for all your help and for the answers. I appreciate your time. – Pegah Jan 24 '11 at 14:33
  • @Pegah If you have updates on your question, please edit your question. Posts below should be *answers only*. – Sampson Jan 24 '11 at 14:34

2 Answers2

2

The kind of arrays in you are using here (C-style) are not really designed to be used with dynamic sizes, though you can use new to allocate them that way. One solution for function calling is do use a double *** and three size_t parameters for dimensions to pass into a function, but that still requires you to declare the array in the caller with dimensions as large as you will ever need. or you will corrupt your process memory and likely crash.

A better solution is to use vector which is designed from the beginning to deal with array with runtime-determined sizes. You can either declare a multi-D vector and use it directly, or go for a single-dimensional vector and do a bit of math at access time to convert a triple of coordinates into an index into the vector.

Either way, you need the vector header, here is how I recommend placing that setup:

#include <vector> // in your includes

using std::vector; // at global scope immediately after all #includes

Some code samples. I'll use cchips for the size of the third dimension based on another answer. The multidimensional solution looks something like this:

// at global scope
typedef vector< vector<double> > vec2double;
typedef vector< vector<vec2double> > vec3double;

// in the caller of your calcSS after you know how big to make the array {
    vec3double tfairexp(cchips, vec2double(max_ctrl_no, vector<double>(max_rep_no)));
    // now fill up tfairexp
    calcSS(tfairexp);
// }

// important: pass a reference here, or you will copy the whole array at call time!
void calcSS(vec3double &tfairexp) {
    // you can use cchips etc here but don't have to:
    for (size_t i = 0; i < tfairexp.size(); i++) {
        for (size_t j = 0; j < tfairexp[0].size(); j++) {
            for (size_t k = 0; k < tfairexp[0][0].size(); k++) {
                // access tfairexp[i][j][k] here
            }
        }
    }
}

That solution will actually do 1+j+j*k allocations of dynamic arrays. You could instead write a wrapper class that would "own" the vector and do the dimension-translation stuff, and have the class you're currently writing use that. I'm making some stylistic sacrifices to continue to use your "public class member variables for dimension sizes" approach. However, this one more closely models how the compiler translates C-style multidimensional arrays, and only does one memory allocation per run:

// as a member of your class -- returns a live reference that can be assigned to!
double &vec3_get(vector<double> &array, const size_t i, const size_t j, const size_t k) {
    return array[i*max_ctrl_no*max_rep_no + j*max_rep_no +k];
}

// in caller of calcSS {
    vector<double> tfairexp(cchips*max_ctrl_no*max_rep_no);
    // fill in by doing vec3_get(tfairexp, i, j, k) = val;
    calcSS(tfairexp)
// }

// again, pass a reference to the vector!
void calcSS(vector<double> &tfairexp) {
    for (size_t i = 0; i < cchips; i++) {
        for (size_t j = 0; j < max_ctrl_no; j++) {
            for (size_t k = 0; k < max_rep_no; k++) {
                // access vec3_get(tfairexp, i, j, k) here
            }
        }
    }
}
Walter Mundt
  • 24,753
  • 5
  • 53
  • 61
  • Thank you so much. the code is here: http://pastebin.com/UTg3Dd2P I think you thought that I don't know the size when filling the array. could you please have a look at it? – Pegah Jan 23 '11 at 12:03
  • Thanks. I tried your last solution and my problem was solved. Thank you again. – Pegah Jan 23 '11 at 16:57
  • No, I figured you knew how big it was when filling it in. However, there is a big difference between knowing how big an array is when filling it in (at runtime), and knowing how big an array is when writing your code (-> at compile time). Any size data you don't learn until the program is running has to be incorporated using dynamic allocation, either with operator new or with vectors and such. – Walter Mundt Jan 24 '11 at 09:57
0
double calcSS(double tfpairexp[][max_ctrl_no][max_rep_no])

One solution is to change the function signature to,

double calcSS(double ***tfpairexp, int M, int N, int P);

where M, N and P are dimensions of the arrray!

Or you can pass the instance of your class itself. After all, you've made the dimensions public in your class. And if this function is a member function of the class, then you don't even need to pass anything; you can access them from the function itself like this:

double calcSS(double ***tfpairexp)
{

      for(int i = 0 ; i < cchips ; i++ )
      {
           for(int j = 0 ; j < max_ctrl_no ; j++ )
          {
                for(int k = 0 ; k < max_rep_no ; k++ )
                {
                       //access elements as tfpairexp[i][j][k]
                }
          }
      }

}

You can see this answer if it solves your problem: using a function template

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Thanks for the answer. In a function, I calculate tfpairexp's values, then I call calcSS to use the values stored in tfpairexp. if I write the function like double calcSS(double ***tfpairexp, int M, int N, int P), how should I retrieve the values of array? second: yes, at first I wanted to define tfpairexp too as public, so all the functions could see it. but I had the same problem again, because of the dimensions. Could you please explain more what you mean? – Pegah Jan 23 '11 at 09:53
  • @Pegah: Are you new to C++? What is your experience with it? I think you need to get some book on C++ and read that first. :-) – Nawaz Jan 23 '11 at 10:07
  • No unfortunately I am not new. but I have always problem with pointers. I have written it like this: double tfpairexp[cchips][max_ctrl_no][max_rep_no]; then imagine: tfpairexp[0][0][1]=10; and so on. and then: calcSS(tfpairexp); and for the func definition: double calcSS(double ***tfpairexp). But it still gives error: it says "no proper function" in the line that is written: calcSS(tfpairexp); – Pegah Jan 23 '11 at 10:40
  • @Pegah : In C++, you cannot write `double tfpairexp[cchips][max_ctrl_no][max_rep_no];` IF dimensions are not defined as `const`. – Nawaz Jan 23 '11 at 10:44
  • @Pegah: can you post more code so that I can see what you're doing? – Nawaz Jan 23 '11 at 10:45
  • there is no problem with double tfpairexp[cchips][max_ctrl_no][max_rep_no] because all cchips,max_ctrl_no and max_rep_no are public are set to a value perviously. – Pegah Jan 23 '11 at 10:50
  • 1
    @Pegah: using variables for array dimensions is only supported by some compilers–it's not a part of the C++ standard (see [§ 5.19](http://www.open-std.org/jtc1/sc22/open/n2356/expr.html#expr.const) of C++98,C++03). Hence it may *be* a problem on some compilers. – outis Jan 23 '11 at 11:22
  • @Pegah: well, if you don't care about portable code (if you ever hope that others will use your project, you should) and your compiler supports it, you don't need to deal with it. If you do care, use `new[]` and `delete[]` if array dimensions need to vary. Better yet, use `std::vector` or [`boost::multi_array`](http://www.boost.org/doc/libs/1_45_0/libs/multi_array/doc/index.html) in either case. You should use c-style arrays only if you have very good, specific reasons. `std::vector` and `boost::multi_array` keep track of their own sizes, so you can query them when you need to know. – outis Jan 23 '11 at 11:29