need help returning or passing by reference a 2-d array

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • jza
    New Member
    • Feb 2007
    • 4

    need help returning or passing by reference a 2-d array

    Hello all,

    I am fairly new to c, coming from a Java background. I am working on a mathematical program and I have a function that needs to return a 2-d array. After some web searching, I have determined that in c, it is better to just pass the array in the function. Since arrays are passed by reference, I expected for the updated array to be passed back with the correct values filled in, however, only the first row of the array is returned (with the rest of the rows filled with zeroes) upon returning from the function. I know that the values are being properly filled in since I verify that before returning from the function (that fills the array). Sorry for the long post, just trying to explain the situation. Below is a simplified version of the code that I'm using

    Code:
    void createVectorSeries(float input[], float output[][COLS])  {
      /* populate the output array */
    }
    
    void main() {
      float output[ROWS][COLS] ;
      /* fill input array */
      createVectorSeries(input, output) ;
    Sample output:
    Code:
    0.3 0.4 0.5 0.6
    0      0    0   0
    0     0    0    0
    any help is appreciated
  • Ganon11
    Recognized Expert Specialist
    • Oct 2006
    • 3651

    #2
    It might help to see more of the code, especially the function. You may have to pass the array using pointers or double-pointers.

    Comment

    • jza
      New Member
      • Feb 2007
      • 4

      #3
      here are the 2 principle functions. The rest of the code just reads data from a file, creates an array from the data and breaks it down and passes it (as signal[] ) to getCorrelationI ntegral. Let me know if that's enough, or too much information.

      Code:
      
      /*
       * Get the vector series of a signal, given the signal,
       * the interval time (tau) and the embedding dimension (m)
       */
      void getVectorSeries(float signal[], int tau, int m, float vectorSeries[][COLS])  {
      
      //      int v ; for(v = 0 ; v < 10 ; v++) printf("%f \t", signal[v])    ;
      //      debug("at getVectorSeries . . . ") ;
      
              int a, b;
              int i = 0, j = 0 ;
              for(a = 0 ; a < (SZ_WINDOW - m) ; a += tau) {
                      for(b = a ; b < (m+a) ; b++) {
      //                      segment[j++] = signal[b] ;
                              vectorSeries[i][j++] = signal[b] ;
                      }
                      j = 0 ;
                      i++ ;
              }
      // //  make sure vector series is correct (it is )
      //      int v,vv ;
      //      printf("\n");
      //      for(v = 0 ; v < 10 ; v++) {
      //              for(vv = 0 ; vv < m ; vv++) {
      //                      printf("%f \t", vectorSeries[v][vv]);
      //              }
      //              printf("\n") ;
      //      }
      }
      
      
      /**
       * Get the correlation integral of a signal
       */
      void getCorrelationIntegral(float signal[], float* corrIntegral, int currentElectrode) {
      
              int vsNumRows=  (int)((int)(SZ_WINDOW - m) / tau) + 1 ;
              float vectorSeries[ vsNumRows] [ m ] ;
      //      printf("##%i", vsNumRows) ;
              getVectorSeries(signal, tau, m, vectorSeries) ;
      
              // //  make sure vector series is correct
              // -> for some reason, only the first row is returned (but it is correct in the getVectorSeries function, hmmm
              int v,vv ;
              printf("\n");
              for(v = 0 ; v < 10 ; v++) {
                      for(vv = 0 ; vv < m ; vv++) {
                              printf("%f \t", vectorSeries[v][vv]);
                      }
                      printf("\n") ;
              }
      
              float ratio = 0.01 ;
              float dist[m] ;
              int b = 0 ;
              float distance[ vsNumRows * (vsNumRows -1) ] ; // random distance here
              int t, s, col ;
              for(t = 0 ; t < vsNumRows ; t++) {
                      for(s = (t+1) ; s < vsNumRows; s++) {
                              float norm[m] ;
                              float sumOfDims = 0.0 ;
                              for(col = 0 ; col < m ; col++) {
                                      printf("%f-%f=%f\n",   vectorSeries[t][col], vectorSeries[s][col],   vectorSeries[t][col] - vectorSeries[s][col]) ;
                                      norm[col] = powf( fabsf( vectorSeries[t][col] - vectorSeries[s][col]), 2.0 ) ;
                                      debugFloatArray(norm, m) ;
                                      sumOfDims += norm[col] ;
                              }
                              distance[b++] = sqrt(sumOfDims) ;
      //                      debugFloatArray(distance,  vsNumRows * (vsNumRows -1) ) ;
                              if(distance[b] < RATIO) {
                                      H_eachElectrode++ ;
                              }
                    }
                      g_distanceSize =  vsNumRows * (vsNumRows -1) ;
                      H_electrode[g_windowNo][ (currentElectrode - 1) ] = H_eachElectrode ;
                      divideElectrodesArrayByDistanceSize() ;
              }
      }
      thanks

      Comment

      • AdrianH
        Recognized Expert Top Contributor
        • Feb 2007
        • 1251

        #4
        Originally posted by jza
        Hello all,

        I am fairly new to c, coming from a Java background. I am working on a mathematical program and I have a function that needs to return a 2-d array. After some web searching, I have determined that in c, it is better to just pass the array in the function. Since arrays are passed by reference, I expected for the updated array to be passed back with the correct values filled in, however, only the first row of the array is returned (with the rest of the rows filled with zeroes) upon returning from the function. I know that the values are being properly filled in since I verify that before returning from the function (that fills the array). Sorry for the long post, just trying to explain the situation. Below is a simplified version of the code that I'm using

        Code:
        void createVectorSeries(float input[], float output[][COLS])  {
          /* populate the output array */
        }
        
        void main() {
          float output[ROWS][COLS] ;
          /* fill input array */
          createVectorSeries(input, output) ;
        Sample output:
        Code:
        0.3 0.4 0.5 0.6
        0      0    0   0
        0     0    0    0
        any help is appreciated

        Yeah, the problem is that you are passing a 2D array. You can't do that. It has to do with how arrays are handled when passed. If you declare a multi-dimensional array like you did, it gets allocated as one big chunk. However, if you pass that array, it will not be treated as one big chunk, but as a multi-pointer (in the case of a 2D array, it becomes a double pointer, 3D - triple pointer).

        What this means for your 2D example is that you must create a 1D array of pointers, and then allocate the pointers in each element to another array of floats. This will then be properly recognised by functions that are passed it.

        I've got to run, but I can explain why this occurs later. Unless someone else would like to do the honours?


        Adrian

        Comment

        • RRick
          Recognized Expert Contributor
          • Feb 2007
          • 463

          #5
          There's nothing wrong with passing a 2-D array to a subroutine. The definition in the code looks good. I suspect the problem lies in the code itself within. The quickest way to find out if the code is bad is to add a print statement for each row being calculated.

          If you want the number of columns to vary in your program, then you will have to give up on the 2-D array and implement an array of pointers. You pass m to getVectorSeries , but m must always equal COLS.

          Also, I would use doubles not floats for you calculations. Floats are only used in cases of emergencies where the arrays are too massive.

          Comment

          • AdrianH
            Recognized Expert Top Contributor
            • Feb 2007
            • 1251

            #6
            Originally posted by RRick
            There's nothing wrong with passing a 2-D array to a subroutine. The definition in the code looks good. I suspect the problem lies in the code itself within. The quickest way to find out if the code is bad is to add a print statement for each row being calculated.

            If you want the number of columns to vary in your program, then you will have to give up on the 2-D array and implement an array of pointers. You pass m to getVectorSeries , but m must always equal COLS.

            Also, I would use doubles not floats for you calculations. Floats are only used in cases of emergencies where the arrays are too massive.
            When C++ came out with those arrays, I wasn't able to get them to work. I guess I understand why now.

            RRick is right, the problem lies in the populating of the array inside of the function. That is where your error lies. The decision to use floats or doubles is yours, but you should know that though it is half the size of a double and possibly slightly faster, you will have less precision and thus are subject to more severe rounding errors. See Wikipedia’s IEEE 754 for more info.

            Sorry for the misinformation in the last response. Hope this helps.


            Adrian

            Comment

            • jza
              New Member
              • Feb 2007
              • 4

              #7
              Originally posted by RRick
              There's nothing wrong with passing a 2-D array to a subroutine. The definition in the code looks good. I suspect the problem lies in the code itself within. The quickest way to find out if the code is bad is to add a print statement for each row being calculated.
              Originally posted by AdrianH
              When C++ came out with those arrays, I wasn't able to get them to work. I guess I understand why now.

              RRick is right, the problem lies in the populating of the array inside of the function. That is where your error lies.

              Adrian
              If you'll notice in the code, I print out the array in the getVectorSeries (where it is populated) and this produces the correct output. I then print it after returning from getVectorSeries and only the first row is populated. This leads me to believe that the problem lies in how I'm passing the array. I really don't know what else to look for in the code itself. Do you agree with me?
              BTW, thanks for the info on floats, I'll switch to double

              Comment

              • RRick
                Recognized Expert Contributor
                • Feb 2007
                • 463

                #8
                You have some commented out code that does print the array, but it is hard coded for rows = 10. Earlier in your post, you print out an array with rows=3. Something is not matching here and that is probably the problem. Take a look and see what the sizes of the array is in both routines.

                You need to check this because I can't make much sense of the code in getCorrelationI ntegral. If the code in getCorrelationI ntegral compiles, then m and tau are global variables. This doesn't seem right.

                Comment

                • AdrianH
                  Recognized Expert Top Contributor
                  • Feb 2007
                  • 1251

                  #9
                  Originally posted by jza
                  If you'll notice in the code, I print out the array in the getVectorSeries (where it is populated) and this produces the correct output. I then print it after returning from getVectorSeries and only the first row is populated. This leads me to believe that the problem lies in how I'm passing the array. I really don't know what else to look for in the code itself. Do you agree with me?
                  BTW, thanks for the info on floats, I'll switch to double
                  I'm posting simple sample to show that a 2D array can be passed, modified and have it's modification seen in the caller in a row that is not 0. I'm going to take a closer look at your code in a minute.

                  Code:
                  #include <stdio.h>
                  
                  int const COLS=10;
                  int const ROWS=5;
                  
                  void f(int array[][COLS], int row, int col, int value)
                  {
                  	array[row][col]=value;
                  }
                  
                  int main()
                  {
                  	int array[ROWS][COLS] = {};
                  	f(array, 2, 3, 4);
                  	printf("array[2][3] = %d\n", array[2][3]);
                  	return 0;
                  }

                  Adrian

                  Comment

                  • AdrianH
                    Recognized Expert Top Contributor
                    • Feb 2007
                    • 1251

                    #10
                    Ahh, I think I see your problem. Here is the prototype:
                    Code:
                    void getVectorSeries(float signal[], int tau, int m, float vectorSeries[][COLS]);
                    Here is the code leading up to the call to getVectorSeries ():
                    Code:
                    /**
                     * Get the correlation integral of a signal
                     */
                    void getCorrelationIntegral(float signal[], float* corrIntegral, int currentElectrode) {
                    
                            int vsNumRows=  (int)((int)(SZ_WINDOW - m) / tau) + 1 ;
                            float vectorSeries[ vsNumRows] [ m ] ;
                    //      printf("##%i", vsNumRows) ;
                            getVectorSeries(signal, tau, m, vectorSeries) ;
                    Assuming that your compiler is not catching this, the problem is being caused by you allocating an array based on m columns. m is not defined here but I bet it is not 30.

                    In order to pass a multi-dimensional array, the caller and callee must agree as to what the sizes of all of the dimensions are except for the very first which can be variable. Otherwise, there is no way of properly calculating the location of an element in the array, which is physically just a block of memory with no information attached to it describing it.

                    This being the case, you can actually tell the compiler how many cols there are in one of two ways, by passing a variable or by creating a template function.

                    Variable Passing Method:
                    Code:
                    #include <stdio.h>
                    
                    #define COLS 10
                    #define ROWS 5
                    
                    void f(int cols, int array[][cols], int row, int col, int value)
                    {
                    	array[row][col]=value;
                    }
                    
                    int main()
                    {
                    	int array[ROWS][COLS] = {};
                    	f(COLS, array, 2, 3, 4);
                    	printf("array[2][3] = %d\n", array[2][3]);
                    	return 0;
                    }
                    Advantages over Templates
                    • Object size remains constant no matter how many different arrays with different number of columns you have.
                    • Function source can be hidden in the source file and not exposed to who ever wants to look at it. This is a design issue, making the code a black box so people don't start to rely on internal private matters that may change in the future.


                    Disadvantages over Templates
                    • The number of columns must come before the array in the parameter list.
                    • Because there is a separation between the array and the number of columns that it should have, there is a chance that you may inadvertently pass an array that has n columns but state that it has m columns (sort of like i'm thinking in your case).
                    • It is slightly slower as optimisations based on the number of columns cannot be done.
                      This is only really noticeable when the function is called thousands (if not more) of times or unless you are running this on a very slow system.
                    • I'm not sure if this is part of the ANSII C++ standard. It might be just a gnu extension.

                    Template Method
                    Code:
                    #include <stdio.h>
                    
                    #define COLS 10
                    #define ROWS 5
                    
                    template <int cols>
                    void f(int array[][cols], int row, int col, int value)
                    {
                    	array[row][col]=value;
                    }
                    
                    int main()
                    {
                    	int array[ROWS][COLS] = {};
                    	f(array, 2, 3, 4);
                    	printf("array[2][3] = %d\n", array[2][3]);
                    	return 0;
                    }
                    In the template method, the number of columns in the array is inferred by the array that it is passed.

                    Advantages over Variable Passing
                    • The number of columns is inferred by the array you pass it.
                    • It has a slight speed advantage because for each array with a different number of columns that is passed to the function f(), a whole new function f() is compiled, optimised for that number of columns.
                      This is only really noticeable when the function is called thousands (if not more) of times or unless you are running this on a very slow system.
                    • Should be accepted by any ANSII C++ compiler.


                    Disadvantages over Variable Passing
                    • Increase in the object size if you have many, many, many different arrays with equally as many different number of columns being passed to the template function. This concern is usually very minimal
                    • Template functions as yet, cannot be hidden in source code due to current compilation methods. This function, in its entirety, must be exposed to those functions who use it. Which usually means that it has to be put in to the header file.


                    If I am wrong, no great loss to me, I learned quite a bit from this conversation, but it wouldn’t help you much ;).

                    If I am right, please state what compiler you are using. I’d be interested.


                    Adrian

                    Comment

                    • jza
                      New Member
                      • Feb 2007
                      • 4

                      #11
                      Well, I figured it out and I'm sorry to say it was just a silly mistake on my part. In the function declaration for getVectorSeries , I set the column size to COLS, which I defined as the number of columns for the text file (89), but the actual number of columns for the vector series is m, which is 3.
                      Adrian, thanks for the elaborate explanation. Your solution wasn't exactly the problem as I had defined m as global after realizing I needed it in other functions, but it lead me to the actual problem. The part about the template being more optimized is interesting since this is a long computation and both getCorrelationI ntegral and getVectorSeries are called 10,000+ times. However, when I attempted to run that code it wouldn't compile and I couldn't find anything about function templates online either (only as part of class templates in C++). Is there something special that needs to be done to compile that? I'm using gcc 3.4 on Linux.
                      This is the error I get:
                      Code:
                      er.c:6: error: syntax error before '<' token
                      My function may actually be optimized already since I'm using a predefined value for the column size, rather than a passed in variable, but it would be interesting to compare the performance anyhow.

                      Rick, to answer your question (in case you care),
                      Originally posted by RRick
                      You have some commented out code that does print the array, but it is hard coded for rows = 10. Earlier in your post, you print out an array with rows=3. Something is not matching here and that is probably the problem. Take a look and see what the sizes of the array is in both routines.

                      You need to check this because I can't make much sense of the code in getCorrelationI ntegral. If the code in getCorrelationI ntegral compiles, then m and tau are global variables. This doesn't seem right.
                      I use 10 for briefness, I'm reading data from a file with 60,000 lines, so I'm obviously not going to output it all, should have mentioned that. The output I put above is also just a sample.

                      Comment

                      • AdrianH
                        Recognized Expert Top Contributor
                        • Feb 2007
                        • 1251

                        #12
                        Originally posted by jza
                        Well, I figured it out and I'm sorry to say it was just a silly mistake on my part. In the function declaration for getVectorSeries , I set the column size to COLS, which I defined as the number of columns for the text file (89), but the actual number of columns for the vector series is m, which is 3.
                        Adrian, thanks for the elaborate explanation. Your solution wasn't exactly the problem as I had defined m as global after realizing I needed it in other functions, but it lead me to the actual problem. The part about the template being more optimized is interesting since this is a long computation and both getCorrelationI ntegral and getVectorSeries are called 10,000+ times. However, when I attempted to run that code it wouldn't compile and I couldn't find anything about function templates online either (only as part of class templates in C++). Is there something special that needs to be done to compile that? I'm using gcc 3.4 on Linux.
                        This is the error I get:
                        Code:
                        er.c:6: error: syntax error before '<' token
                        My function may actually be optimized already since I'm using a predefined value for the column size, rather than a passed in variable, but it would be interesting to compare the performance anyhow.

                        Rick, to answer your question (in case you care),


                        I use 10 for briefness, I'm reading data from a file with 60,000 lines, so I'm obviously not going to output it all, should have mentioned that. The output I put above is also just a sample.
                        gcc didn’t catch this problem probably because it is not as typesafe as g++, which would have caught this immediately as an error.

                        As for using templates, it is only advantageous if you are going to be dumping arrays of different column sizes into your function. Otherwise it will generate the same object code as the code with the hardcoded 30 in it.

                        Oh, and if you are using gcc, you are programming in C, not C++, so templates will not work as they are attributed to C++. If you wanted to use function templates, change the extension of your file from .c to .cpp and it will probably detect the extension and compile it as C++, otherwise use g++ as your compiler.

                        Since C++ is a derivative of C, most things you do in C are valid in C++. (Except the new C99 standard no longer makes C a subset of C++, so there are some things that are not ANSII C++ legal in C).

                        Cya,


                        Adrian

                        Comment

                        Working...