Passing a Pointer for a 2D Array to a Function

I regret having to ask this, as I know this subject has been discussed many times previously. I've spent several hours getting nowhere, though.

I have a 2 dimensional array,

const int STUDENTS = 10;
const int TESTS = 5;
int students = STUDENTS;
int tests = TESTS;
double scores[STUDENTS][TESTS];

I want to pass a pointer to this array to a function that is going to read values from a file and load them into the array. I've tried writing this pointer every way I can, but I haven't figured out how to satisfy my compiler.

Pointer: double *pScores;
Function Prototype: loadScores(double (*pScores)[TESTS], int, int);
Function Call: loadScores(double (*studentScoresPtr)[TESTS], int, int);
Function Definition: loadScores(double (*studentScoresPtr)[], int students, int tests)

cin >> (studentScoresPtr + (row * column));

The compiler doesn't like the way I reference the pointer. How could I make this work?

Thank you.
1
2
3
4
5
6
7
8
double** scores;
scores = new double*[STUDENTS];
for(long i = 0; i < STUDENTS; i++)
{
    scores[i] = new double[TESTS];
}

//now scores is the array you want 


That's from the top of my head, hope it works :)
Last edited on
Thanks, TheDestroyer. That looks interesting. I'm trying to understand what you are telling me.

I'm guessing that double** scores sets up an array of pointers to pointers named scores. scores is set to point to a pointer for 1D of the array, the rows indicated by STUDENTS. new is a term I've encountered in Java, which I think is used to disambiguate which instance of students I'm using, though I've always been unclear on how it works.

Inside the loop, the array of pointers is set to point to the columns indicated by TESTS, again with the new keyword.

It looks like you are using the same name for the pointer as for the array, which I guess is more efficient than creating a separate pointer to the array.

It looks like it increments only in 1D.

Is that correct? I would appreciate any insight on the code, if that is convenient for you.

I don't know if it matters, but I did not mention that the file that is being loaded into the array contains mixed data types. I need to pick off each line in the file and load them into the appropriate locations (not all go in the same array).
Last edited on
Well, explaining that is very easy.

double* ptr; is just a pointer that points to somewhere in memory. It holds a garbage value of a pointer, just like when you say

int i; contains a garbage value till you initialise it.

Now, if you write:

ptr = new double;, you're telling the pointer that I allocated some memory for a double, and I want you to point to that location. That creates a single slot for a single double.

For ptr = new double[N], you're allocating space for N doubles, and the pointer will point to the first element. A rule in C++ is, every array is a pointer, but not every pointer is an array; in other words, you can always represent an array with a pointer. Now to access the elements of ptr, you can dereference in 2 ways:

1
2
ptr[5] = 10.2; //dereference as an array, you're accessing the 6th element
*(ptr+5) = 10.2; //you're moving your pointers by 5 locations, and then accessing the element, which is equally like dereferencing by [] operator. 


Now in my code, you're allocating an array of pointers (with size STUDENTS), and each pointer in that array points to an array with size TESTS.

So the program allocates at the beginning STUDENTS elements, and then goes into each element of that array an allocates TESTS elements.

----------------

If you find this hard to understand, and since you came from a very easy language, Java, you may use C++ std containers. They're dynamic and change their size dynamically when you add elements to them. As a start, use vectors. You can get the same result from vectors as in my previous code as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <vector>

using namespace std;

int main()
{
    vector< vector<double> > scores; //notice the spacebar between the last 2 > symbols

    scores.resize(STUDENTS);
    for(unsigned long i = 0; i < scores.size(); i++)
    {
        scores[i].resize(TESTS);
    }
    // now scores is a 2D array, you can access it with [] operator (you can't dereference it like pointers, because it's an object).
}


That's way easier, isn't it? read more about vectors here:

www.cplusplus.com/reference/stl/vector/

Cheers :)
Last edited on
I'm not really a fan of multidimentional arrays... but even so I must really advise that you avoid that nested-new junk. Nested vectors are much better.

Although if you want to use "straight" arrays like in your original post, it's actually pretty simple:

1
2
3
4
5
6
7
8
const int STUDENTS = 10; 
const int TESTS = 5;
double scores[STUDENTS][TESTS]; 

//...

void loadScores(double pScores[STUDENTS][TESTS], int, int);  // <- this would work
void loadScores(double pScores[][TESTS], int, int);  // <- or this. 




TheDestroyer's idea to use nested vectors isn't a bad idea at all. One way to make it even easier is to pass the desired sizes to vector's constructor so you dont' have to do those resizes:

1
2
3
4
5
6
7
8
// this:
vector< vector<double> > scores(STUDENTS, vector<double>(TESTS));

// or more simply, this:
vector< vector<double> > scores(STUDENTS, TESTS);

// will immediately resize the vectos to the sizes you want, so there's no
//  need to do the resizing manually. 
@Disch: nice stuff with vectors, although I knew what constructors of vectors do, but never occured to me to initialise vectors in that nice way, thanks for the info ;-)

But another thing, I saw you always not approving of multidimensional arrays. I would like to just point out that multidimensional arrays are sometimes the only solution available, especially when using realistic systems for physics and maths. You're probably a software engineer, and probably just bother about creating software for users. I'm a physicist, and in my masters, I had to descritise objects from continuum to a 3D grid. Can you imagine how hard it would be to solve such a problem with a flat array? probably not hard with the idea, but with debugging and implemention.
Can you imagine how hard it would be to solve such a problem with a flat array? probably not hard with the idea, but with debugging and implemention.


You typically shouldn't work with the array directly. When you have a complex container like that, it really should be objectified.

A 3D array object is much easier to work with than a vector of a vector of a vector:

1
2
3
4
5
6
7
8
9
10
11
Array3D<double> foo(width,height,depth);

foo.resize( new_wd, new_ht, new_dp );

foo(x,y,z) = 3.14;
cout << foo(x,y,z);
// etc

cout << foo.width();
cout << foo.depth();
//etc. 


Under the hood, Array3D could be implemented as a flat 1D array. Or as a vector of a vector of a vector, or as a nested new pointer structure. What's more, you can change the implementation to whichever works best and/or gives the best performance in your program without having to change any of the code that actually uses the class.

It also makes things MUCH more clear and MUCH easier to pass to/from functions.


About the only thing I used straight multidimentional arrays for is lookup tables.
Last edited on
Thanks for your advice and assistance. I quickly tried implementing the code that TheDestroyer provided this morning, but the result is not an accurate representation of the contents of the file. I don't know what it is representing. I'm having to do a bit of interpretation, to adapt his code to my program, so I must have messed up somewhere (probably several somewheres). I have code that can read and display the contents of the file, so maybe I can mix that in to get what I need?

As you might surmise, I am writing this code to complete my homework assignment. For several reasons, we haven't covered this material in class. However, I've programmed in C for many years, and I've done all this stuff, years ago.

This assignment doesn't make complete sense to me. I asked the professor for explanation, but he was cryptic and brief. We are supposed to create a 2D array to hold test scores for 5 students. One dimension apparently is for the test scores, but we aren't told what the other dimension is supposed to hold. Maybe we get to choose what we stick in there? We are supposed to create parallel arrays to hold student names, student id, average score, and a letter grade.
Topic archived. No new replies allowed.