How do I return a 2D array from a function

Pages: 12
Hi again, since I last posted I have got a much better understanding, and my program is coming along. I am making a lottery program for college, and I have to demonstrate use of functions and arrays, and I have read that it is wise to use NO global variables where possible. I have a few simple global variables as I know they will not change, but I am trying to keep everything local within functions.

My problem is, I am trying to return a 2D array from a function. This is necessary to me as I need to keep track of what line of the player's ticket a number is, up to 10 lines per ticket, as well as it's cell, 1-6, and I will later need to compare the 6 cells on each of up to 10 lines with the randomly generated numbers. I have read it is possible to persist the local 2D array in memory so it can be accessed in other functions. I only CHANGE the values from within it's own function, but I need to compare the array with the random generated balls in a separate function. I have seen a couple of examples of returning a small 1D or 2D array as the result of a function, however I cannot seem to get it to work for me. All this talk of pointers and whatnot...

below is my entire code, the problem is in the Input function, if I remove the asterisks and the return line, it functions as desired, however, as I said, I need to then get the array OUT of the function so I can use it elsewhere.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <string>
#include <iostream>

using namespace std;

const int BetLow   (1);     //used to make sure guesses
const int BetHigh (49);      //and balls are within range
char Pound = 156; //to use pound symbol in cout
unsigned int Wallet (50);   //Global wallet amount, only affected after user inputs data on all lines (removes £1 for each line) and when collecting winnings, if any
int Payout3 (10);
int Payout4 (100);
int Payout5 (2500);
int PayoutB (190000);
int Payout6 (4000000);
bool running = true;

//----------------------------------------ENTER NAME--------------------------------------------
string EnterName()
{
    string Name;

    cout << "Please enter your name:\n";

    getline (cin, Name);

    return (Name);
}



//----------------------------------------CHOOSE NUMBER OF LINES--------------------------------
int Ticket()
{
    int Lines = 0; //set number of lines to default of 0 upon entering this function

    do
    {
        cout << "\nHow many lines would you like to play with? (1-10)\n";

        cin >> Lines;

        if(Lines < 1 || Lines > 10) //feedback to player if they pick less than 1 or more than 10 lines
        {
            cout << "Must be between 1 and 10!\n\n";
        }

        if(Lines > Wallet && Wallet > 1) //feedback if player cannot afford this many lines
        {
            cout << "You do not have enough money for this many lines! You can afford up to " << Wallet << " lines!\n\n";
        }

        if(Lines > Wallet && Wallet == 1) //as above, correcting pluralisation for just £1
        {
            cout << "You do not have enough money for this many lines! You can only afford " << Wallet << " line!\n\n";
        }
    }
    while (Lines < 1 || Lines  > 10 || Lines > Wallet);


    return Lines;
}


//----------------------------------------CHOOSE SIX NUMBERS PER LINE, BUBBLE SORT, AND PRINT---
int *Input(int Lines)
{

    cout << "\n\nPlease choose your 6 lucky numbers: (1-49)\n";
    int *Guess[Lines][6];    //sets 2D array, where Lines is defined by user, and 6 is the amount of guesses on each line
    int Line = 0;

    for(int n = 0; n < 6; n++)  //input loop (still need to allow multiple lines, and check for duplicates!)
    {
        do
        {
            cout << n + 1 << ")\t";
            cin >> *Guess[Line][n];

            if (*Guess[Line][n] < BetLow)
            {
                cout <<"Too low, try again! (1-49)\n";
            }

            else if (*Guess[Line][n] > BetHigh)
            {
                cout << "Too high, try again! (1-49)\n";
            }
        }
        while(*Guess[Line][n] < BetLow || *Guess[Line][n] > BetHigh);
    }


    cout << "You picked:\n";

    for(int n = 0; n < 6; n++) //output loop, prints all data cells (need to bubble sort these per line!)
    {
        cout << Guess[Line][n] << "\t";
    }

    return Guess;
}


//----------------------------------------RANDOM NUMBER GENERATOR-------------------------------
void Generate()
{

}


//----------------------------------------COMPARE RANDOM BALLS WITH GUESSES PER LINE------------
int Compare()
{

}


//----------------------------------------PAYOUT------------------------------------------------
void Payout()
{

}


//----------------------------------------MAIN (LOOP FROM NUMBER OF LINES TO PAYOUT)------------
int main ()
{
    string Name = EnterName();
    //start game by asking for player's name
    cout << "\nWelcome, " << Name << "!\t\tYou have " << Pound << Wallet << " in your wallet to play with!\n\n";


    //------------------------------------MAIN LOOP---------------------------------------------
    do
    {
        int Lines = Ticket();

        Input(Lines);

        Wallet = Wallet - Lines; //subtract £1 for each line played
        cout << "You have " << Pound << Wallet << " left in your wallet.";



        //Generate();


        //Compare();


        //Payout();




        //end game when run out of money
        /*if(Wallet <= 0)
        {
            running = false;
        }*/
        running = false;
    }
    while(running==true);


    cout << "\n\n\nYou ran out of money. Thanks for playing!\n";




    return 0;
}




Thanks in advance, hopefully this is a simple fix, I know I am almost there, but I don't understand all this pointers nonsense, I just want the return value of the function to BE the array that is generated within it.

Thanks again!

(the error refers to line 100 in case you cannot find it at first glance)
Last edited on
I'm pretty sure that a function cannot return an array. You can pass it by reference (sorry I had wrote value before) and grab it that way I suppose.
Last edited on
I want to either return the array itself, or the values of the array, maintaining it's structure, so it is consistent across any other functions that make use of it. To be more concise, this is the function in question, isolated, as everything else works fine this far.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int *Input(int Lines)
{

    cout << "\n\nPlease choose your 6 lucky numbers: (1-49)\n";
    int *Guess[Lines][6];    //sets 2D array, where Lines is defined by user, and 6 is the amount of guesses on each line
    int Line = 0;

    for(int n = 0; n < 6; n++)  //input loop (still need to allow multiple lines, and check for duplicates!)
    {
        do
        {
            cout << n + 1 << ")\t";
            cin >> *Guess[Line][n];

            if (*Guess[Line][n] < BetLow)
            {
                cout <<"Too low, try again! (1-49)\n";
            }

            else if (*Guess[Line][n] > BetHigh)
            {
                cout << "Too high, try again! (1-49)\n";
            }
        }
        while(*Guess[Line][n] < BetLow || *Guess[Line][n] > BetHigh);
    }


    cout << "You picked:\n";

    for(int n = 0; n < 6; n++) //output loop, prints all data cells (need to bubble sort these per line!)
    {
        cout << Guess[Line][n] << "\t";
    }

    return Guess;
}
Last edited on
If you are going to be using it with other functions just declare the array in main. Arrays are always passed by reference, so just pass that sucker like all other variables. Then you will get it back.

1
2
3
4
5
6
void getBack( int Guess[], int size)
{

 //Do that ever you want to the array.

}


What I'm trying to say is the array is just like any other variable. Just make sure to pass the size when passing it around between functions.
I'm not sure why you're going with a 2d array here. What you want is a 1d array of int. What you have is a 2d array of pointers to int.

1
2
3
   int *Guess[Lines][6];    
   // ....
   cin >> *Guess[Line][n];


At this point Guess[line][n] points to a random place in memory. Dereferencing it and writing to it results in you trashing memory that you don't own.

If you want to return a pointer to an array, you need to allocate dynamic memory for it, as any variable allocated automatically in the function will be destroyed when the function returns. A simpler solution would be to pass the array into the function, let the function fill it, and return (which is the solution jlillie89 is espousing.)



Last edited on
You can return the array but only as an address (basically return <array_name>), so you can then assign this to a pointer. Unfortunately, you won't be able to use the pointer as a 2d array (with the [][] operators), however you can use the [] operator.

Here's a code to show you how you can pass a 2d array to a function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//...includes
int arr(int a[][10])
{
    //fill a with values
    return a;
}

int main()
{
    int *p, line,col,a[2][10];
    cin >> line >> col;
    p=arr(a);
    cout << p[line*10+col];
    return 0;
}


And here is some explanation if you are confused about pointers and what not:

What a pointer does is, well, point to an address. The name of an array is actually the address of the first element in the array (so the address of array[0]). With a 1d array (or a vector), using a pointer to access your desired element is a piece of cake (pointer[row_number]).

2d arrays are represented in memory as just "columns", since you can have lines so an array, in memory looks like this:

array[2][5]:
{1,2,3,4,5},{6,7,8,9,1}

and not like this:

{1,2,3,4,5},
{6,7,8,9,1}

so you can't use pointer[1][2] to access the value 8 but instead you have to write pointer[7], which basically means "give me the value that is stored 7 cells away from the first address). If you knew the number of columns in each cell, that would be:

pointer[line_number*elements_in_each_line + column_numer)

so

pointer [1*5 + 2] (remember that arrays are indexed from 0, so array[7] is actually the 8th element in the array.
Last edited on
Here's a code to show you how you can pass a 2d array to a function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//...includes
int arr()
{
    int a[2][10] = { {0,1,2,3,4,5,6,7,8,9}, {6,4,1,7,6,5,3,6,0,3} };
    return a;
}

int main()
{
    int *p, line,col;
    cin >> line >> col;
    p=arr();
    cout << p[line*10+col];
    return 0;
}


Please don't do this. The pointer to a returned from arr() does not point to valid memory (a ceases to exist when the function returns) and this code results in undefined behavior.
Last edited on
@cire Oups :p

He's right, must've missed that. Make sure you either create the array in main() or allocate it dynamically.

Though creating it in main() would make the arr() function useless since you can access the array directly using a instead of p.
Last edited on
Thanks for this hints thus far guys though I am still unable to progress. Again, I am trying to avoid global variables almost entirely, because though I could easily solve my problem this way, I worry that I might accidentally change the values from a function where I did not intend to, and therefore debugging would become a nightmare. I have seen my friends do this, and I vowed to avoid this from the start.

What do you mean by allocate it dynamically? would that not be what it is already, as it is allocated upon entering the function and lost at the end? I want to persist the array once the function is finished, however, I am not (in this instance) trying to pass variables from a function INTO this array, I am declaring the array locally to the function, storing values in the data cells based on user input, and currently printing them to show that they work, but they are of course lost once the function ends. I have tweaked it so I have multiple lines now working, which I will post the source code below, and hopefully you can see from that why I want to use a 2D array for this, as I need to distinguish not just the bets 1-6, but the grouping of 6 bets, per line, as many as 1-10 lines. Compile my code below and you will begin to see what I mean. How do I keep these values as something that a later function can then refer to? I will have a ball generating function called next, generating 7 balls (6 and a bonus), which will be easy as it is completely independent of any other functions, but the next one will then need to compare the numbers from the generator, with the numbers on the player's ticket, and you understand this must be done PER line, and I am trying to plan an algorithm that does this, so rather than manually coding "now check number one on line one with balls 1-7, then check number two on line one with balls 1-7", It would be "sequentially check the numbers on line one with all the balls, and flag how many matches you find, then do the same with line 2, etc".

So it would be a for loop within a for loop, as I now have in the Input function, as you will now see...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <string>
#include <iostream>

using namespace std;

const int BetLow   (1);     //used to make sure guesses
const int BetHigh (49);      //and balls are within range
char Pound = 156; //to use pound symbol in cout
unsigned int Wallet (50);   //Global wallet amount, only affected after user inputs data on all lines (removes £1 for each line) and when collecting winnings, if any
int Payout3 (10);
int Payout4 (100);
int Payout5 (2500);
int PayoutB (190000);
int Payout6 (4000000);
bool running = true;

//----------------------------------------ENTER NAME--------------------------------------------
string EnterName()
{
    string Name;

    cout << "Please enter your name:\n";

    getline (cin, Name);

    return (Name);
}



//----------------------------------------CHOOSE NUMBER OF LINES--------------------------------
int Ticket()
{
    int Lines = 0; //set number of lines to default of 0 upon entering this function

    do
    {
        cout << "\nHow many lines would you like to play with? (1-10)\n";

        cin >> Lines;

        if(Lines < 1 || Lines > 10) //feedback to player if they pick less than 1 or more than 10 lines
        {
            cout << "Must be between 1 and 10!\n\n";
        }

        if(Lines > Wallet && Wallet > 1) //feedback if player cannot afford this many lines
        {
            cout << "You do not have enough money for this many lines! You can afford up to " << Wallet << " lines!\n\n";
        }

        if(Lines > Wallet && Wallet == 1) //as above, correcting pluralisation for just £1
        {
            cout << "You do not have enough money for this many lines! You can only afford " << Wallet << " line!\n\n";
        }
    }
    while (Lines < 1 || Lines  > 10 || Lines > Wallet);


    return Lines;
}


//----------------------------------------CHOOSE SIX NUMBERS PER LINE, BUBBLE SORT, AND PRINT---
int Input(int Lines)
{

    cout << "\n\nPlease choose your 6 lucky numbers: (1-49)\n";
    int Guess[Lines][6];    //sets 2D array, where Lines is defined by user, and 6 is the amount of guesses on each line


    for (int Line = 0; Line < Lines; Line++)
    {
        cout << "Line " << Line + 1 << ":\n";

        for(int n = 0; n < 6; n++)  //input loop (still need to check for duplicates!)
        {
            do
            {
                cout << n + 1 << ")\t";
                cin >> Guess[Line][n];

                if (Guess[Line][n] < BetLow)
                {
                    cout <<"Too low, try again! (1-49)\n";
                }

                else if (Guess[Line][n] > BetHigh)
                {
                    cout << "Too high, try again! (1-49)\n";
                }
            }
            while(Guess[Line][n] < BetLow || Guess[Line][n] > BetHigh);
        }
    }


    cout << "\n\nYou picked:\n";

    for (int Line = 0; Line < Lines; Line++)
    {
        for(int n = 0; n < 6; n++) //output loop, prints all data cells (still need to bubble sort these, per line!)
        {
            cout << Guess[Line][n] << "\t";
        }
        cout << endl;
    }
}


//----------------------------------------RANDOM NUMBER GENERATOR-------------------------------
void Generate()
{

}


//----------------------------------------COMPARE RANDOM BALLS WITH GUESSES PER LINE------------
int Compare()
{

}


//----------------------------------------PAYOUT------------------------------------------------
void Payout()
{

}


//----------------------------------------MAIN (LOOP FROM NUMBER OF LINES TO PAYOUT)------------
int main ()
{
    string Name = EnterName();
    //start game by asking for player's name
    cout << "\nWelcome, " << Name << "!\t\tYou have " << Pound << Wallet << " in your wallet to play with!\n\n";


    //------------------------------------MAIN LOOP---------------------------------------------
    do
    {
        int Lines = Ticket();

        Input(Lines);

        Wallet = Wallet - Lines; //subtract £1 for each line played
        cout << "\nYou have " << Pound << Wallet << " left in your wallet.\n\n";



        //Generate();


        //Compare();


        //Payout();




        //end game when run out of money
        if(Wallet <= 0)
        {
            running = false;
        }
    }
    while(running==true);


    cout << "\n\n\nYou ran out of money. Thanks for playing!\n";




    return 0;
}

Is the use of arrays a requirement? This task is begging for a regular container, especially seeing as another function in the same program returns a string.
yes the string is returned from the EnterName function from local variable Name, and copied to the local Name variable in main, so that I can repeatedly print the player's name from within the main function as often as I like. The project requires that we demonstrate knowledge of arrays and functions, so I could just do one, and leave everything else global and linear, but like I said, my classmates have had major issues debugging theirs this way, and I want to get a distinction by using functions to what appears to me to be the professional standard. The EnterName function works beautifully for my purposes, and I now understand how to inject a parameter from one function INTO another using the parenthesis of each function when calling it, but what I am trying to do is RETURN variables from an array, to get them OUT of that function to be used, but not manipulated, in a separate function...

I hope I am making myself clear, I tend to go in circles when I try to explain something that is in my head, but I think I am right in my logic, I just need to get the values out of that function when they are created in the local array, so that the function that compares the ticket with the random balls has something TO compare...

What do you mean by a regular container? And is there a problem with returning a string from a function? How else would I call a function for name entry, and return a value that is readable as a name? surely the TYPE of variable is irrelevant here, and the type I am having trouble with now is simply integers.
Last edited on
I am declaring the array locally to the function, storing values in the data cells based on user input, and currently printing them to show that they work, but they are of course lost once the function ends.


Why not declare the array in main() and read Lines, send it to Input() to populate the array then, when you want to use the array, you send it to the specific function like Generate() for instance?
Again, I am trying to avoid global variables almost entirely


No one is suggesting the use of global variables. They're suggesting you declare the array within int main(), which means it's a local variable to main(). You would then pass this array by reference, which would mean any function that takes in this array would then have free reign to change the values within the array, thereby keeping your values intact.

You cannot define something within a function and expect that something to persist. You can return its' values, but you cannot return the memory location itself because it will be deconstructed upon function termination. You need to define your array within the main body of int main() and reference back to the array while in each function.
Last edited on
ooh I kinda gettit, so, because the functions are called from within main, variables declared IN main are in the scope of the other functions, without being a global variable?

Sooo... hold on let me see if I can figure this out a moment....
Last edited on
What do you mean by allocate it dynamically? would that not be what it is already, as it is allocated upon entering the function and lost at the end?

No. Dynamically allocated memory is allocated via new or new[].


I want to persist the array once the function is finished, however, I am not (in this instance) trying to pass variables from a function INTO this array,

Nobody said you were. What was suggested was that you do pass the array into this function so that the scope of the array is larger than the scope of the function. Nor do I see why this should raise concerns about global variables. If the array were a global variable, you wouldn't need to pass it in.

Btw, I missed this earlier but:
1
2
3
4
5
int Input(int Lines)
{

    cout << "\n\nPlease choose your 6 lucky numbers: (1-49)\n";
    int Guess[Lines][6];

is not valid C++. Lines must be a constant to define a dimension of an array. Undoubtedly you have a compiler extension enabled that allows variable length arrays, but this code won't compile when the extension is disabled (or on a compiler that doesn't implement that extension.)





What do you mean by a regular container?

vector, set, map, list, etc. Among other things, containers can be returned from functions normally.

And is there a problem with returning a string from a function?

string is a container, if your assignment is prohibiting them, you may be expected to modify an array of char instead.
Last edited on
so this functions the same as before, but I declared the array in main, injected it into the Input function, let Input run, and it continues the game loop as normal, how can I be sure that those array memory cells are now persisting, is there a debug option that displays all variables declared and values in them at any time?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    do
    {
        int Lines = Ticket();

        int Guess[Lines][6];    //declares the 2D array, where Lines is defined by user in the Ticket function, and 6 is the amount of guesses on each line


        Input(Lines, Guess);

        Wallet = Wallet - Lines; //subtract £1 for each line played
        cout << "\nYou have " << Pound << Wallet << " left in your wallet.\n\n";



        //Generate();


        //Compare();


        //Payout();




        //end game when run out of money
        if(Wallet <= 0)
        {
            running = false;
        }
    }
    while(running==true);
Last edited on
because the functions are called from within main, variables declared IN main are in the scope of the other functions, without being a global variable?


Not really. You still have to pass the variables to the function in order to change it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//includes

void change_array(int input_array[], int array_size)
{
     for(int i=array_size-1; i>=0; i--)
          input_array[i]=i;
}
int main()
{
    int array[10], size; cin >> size;
    for(int i=0; i<size; i++) array[i] = i;
    //now the array holds the values 0 through 9
    change_array(array,size);
    //and now 9 through 0
    return 0;
}
Last edited on
is there a debug option that displays all variables declared and values in them at any time?


It's called a for loop. :D But seriously, just create a for loop in both your function and the body of main (where it makes sense to have it... which means values will need to have been input by that time), that will output the information for the array and make sure they're both matching up. Or at the very least just do something like cout << Guess[0][0] << endl; and see if that indeed matches up with what you'd expect.
please see latest post, I have changed declaring the array locally in Input and now declare it within the do while loop that is my game loop in main. I then pass that array into the Input function, which does it's job and lets the user input the data, and it prints fine. Now I need to be certain that that data remains when Input finishes running, so that I can refer to it in the Compare function later on, which I imagine will be fairly simple, though it does leave me the question of what if I accidentally manipulate that data in another function instead of simple use it? Is there a way to lock the array that is in main so that ONLY the input function can manipulate those values?

And oh I think what you mean about containers doesn't really apply to me here, I can use any method I can figure out to make my program work, I just need to display use of at least one function and at least one array, but each of those, plus several other criteria (including commenting and layout) are all worth about 10% of the mark each, and like I said, I want a distinction in this baby :P

I have made Lines int constant now, but it functioned before, I'm not sure I get why this is necessary to change? I never change the value of the number of lines mid entry, only after each game. Which raises the question, why is it a constant if I can change it? That would imply to me that once it has a value, that value is constant, and therefore I cannot change the length of the first dimension in my array, but I can do that, with or without declaring Lines as const int...

Sorry if I miss the point with some of your tips, I am rapidly picking up new things by reading and re reading them, I am a newb here, and I do appreciate all your help =]
Pages: 12