2D Array Can't Pass As Parameter

Hi, all

This program is meant to create a 2d array from user input and then proceed to display this array but with the number of elements swapped with each other in both dimensions (ie input will be 2 rows of 4, the output will be 4 rows of 2). The part I am having trouble most with is trying to get this 2d array to be passed as a parameter into my void function calls. Along with a few other compiling errors (which I'll list below the code), one that sticks out to me is the error that says my parameter name was not declared in the function's scope. I look at other examples of 2d arrays being passed as parameters online and there doesn't seem to be a reason I can find as to why my array is having problems. Can someone help me find the reason and the fix to this issue I'm having with passing my 2d array? I've thoroughly tried to find similar examples of this problem online, but for whatever reason I just can't figure it out. Thanks.

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
#include <iostream>
using namespace std;

//this is a program meant for swapping columns and rows in arrays
//

int a, b;

void errorMsg() {cout << "ERROR. Number is not within range. Try again: " << endl;}

void inputMsg() 
{
    cout << "Enter in the first integer (1-10): " << endl;
    InputA: cin >> a;
    if (a<1 || a>10) {errorMsg(); goto InputA;}
    cout << "Enter in second integer (1-10): " << endl;
    InputB: cin >> b;
    if (b<1 || b>10) {errorMsg(); goto InputB;}    
} 

void arrayAssign(int array[a][b])
{
    for (int c=0; c<a; c++) {
        for (int d=0; d<b; d++) {
            cout << "Insert int. digit for row " << c+1 << 
            " column " << d+1 << endl;
            cin >> array[c][d];
    if (array[c][d] < 0 || array[c][d] > 100) {errorMsg(); d--;}
        }
    }
}

void inverseArray(int array[a][b]) 
{
    cout << "Congrats!!! Here is your reversed 2D Array!" << endl;
    for (int j=0; j<b; j++) {
        for (int k=0; k<a; k++) {
            cout << array[k][j] <<endl;
            
            /* Calculate this:
            0, 0 -> 0, 0
            0, 1 -> 1, 0
            0, 2 -> 2, 0 etc.
            */
        }
    } 
}

int main()
{
    
    inputMsg();
    int a2[a][b];

    
    arrayAssign(a2);
    inverseArray(a2);
        
    return 0;
}


The compiler errors:

21:29: error: array bound is not an integer constant before ']' token
21:32: error: array bound is not an integer constant before ']' token
In function 'void arrayAssign(...)':
27:20: error: 'array' was not declared in this scope
At global scope:
33:30: error: array bound is not an integer constant before ']' token
33:33: error: array bound is not an integer constant before ']' token
In function 'void inverseArray(...)':
38:21: error: 'array' was not declared in this scope
In function 'int main()':
53:16: warning: array of array of runtime bound [-Wvla]
> 21:29: error: array bound is not an integer constant before ']' token
Like the error message says, array sizes need to be integer constants, known to the compiler when you compile it.

Aside from the meaningless global names, do this.
1
2
const int a = 10;
const int b = 5;


But having done that, you can't input the values.

In short, if you want a run-time length for array like storage, then use std::vector.

1
2
    InputA: cin >> a;
    if (a<1 || a>10) {errorMsg(); goto InputA;}

And learn to use a while loop.
Hello nodesc,

Thank you for using code tags.

I have reworked your program into something that should work better for you. Some of the code may be ahead of what you know. In that case let me know what you do not understand and I will explain it better.

As you read through the code you will notice I have changed some of the variable names to make the code easier to understand.

Using "i", "j" and "k" in for loops is OK, but do not feel that you have to use these variables. Sometimes it is better to use a variable name for the loop iterator that makes more sense.

Other than for loops try to avoid using single letter variable names especially at the global scope.


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
#include <iostream>
#include <limits>
#include <string>

using namespace std;  // <--- Best not to use.

//this is rowsUsed program meant for swapping columns and rowsUsed in arrays
//

//int a, b;  // <--- Moved to "main".
constexpr unsigned MAXROWS{ 10 }, MAXCOLS{ 10 };
constexpr unsigned MIN{ 1 }, MAX{ 10 }, MAXINPUT{ 100 };

void errorMsg()
{
    cerr << "\n     ERROR. Number is not within range. Try again:\n\n";
}

void inputMsg(unsigned& rows, unsigned& cols)
{
    std::string PROMPT{ "Enter in the first integer (" + std::to_string(MIN) + " - " + std::to_string(MAX) + "): " };

    while (std::cout << PROMPT && !(cin >> rows) || rows < MIN || rows > MAX)
    {
        if (!std::cin)
        {
            std::cerr << "\n     Invalid Input! Must be a number.\n\n";

            std::cin.clear();  // <--- Resets the state bits on the stream.
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
        }
        else if (rows < MIN || rows > MAX)
        {
            errorMsg();
        }
    }

    std::cout << '\n';

    PROMPT = "Enter in the second integer (" + std::to_string(MIN) + " - " + std::to_string(MAX) + "): ";

    std::cout << PROMPT;
    //cout << "Enter in second integer (1-10): " << endl;

InputB: 
    cin >> cols;

    if (cols < 1 || cols > 10)
    {
        errorMsg(); goto InputB;
    }
}

void arrayAssign(int array[][MAXCOLS], unsigned rowsUsed, unsigned colsUsed)
{
    std::cout << '\n';  // <--- Added.

    for (unsigned row = 0; row < rowsUsed; row++)
    {
        for (unsigned col = 0; col < colsUsed; col++)
        {
            cout << "Insert int. digit for row " << row + 1 <<
                " column " << col + 1 << ": ";

            cin >> array[row][col];

            if (array[row][col] < MIN || array[row][col] > MAXINPUT)
            {
                errorMsg();
                
                col--;
            }
        }

        std::cout << '\n';  // <--- Added.
    }
}

void inverseArray(int array[][MAXCOLS], unsigned rowsUsed, unsigned colsUsed)
{
    cout << "Congrats!!! Here is your reversed 2D Array!" << endl;

    for (unsigned j = 0; j < colsUsed; j++)
    {
        for (unsigned k = 0; k < rowsUsed; k++)
        {
            cout << array[k][j] << endl;

            /* Calculate this:
            0, 0 -> 0, 0
            0, 1 -> 1, 0
            0, 2 -> 2, 0 etc.
            */
        }
    }
}

int main()
{
    unsigned rows{}, cols{};  // <--- ALWAYS initialize all your variables.

    inputMsg(rows, cols);

    int a2[MAXROWS][MAXCOLS]{};  // <--- ALWAYS initialize all your variables. This sets the entire array to (0)zeros.

    arrayAssign(a2, rows, cols);

    inverseArray(a2, rows, cols);

    return 0;
}

Lines 11 and 12 are something that you should get use to using. It makes the program much easier to maintain when you only have 1 place to make a change.

Line 14 you have as a 1 line piece of code. This is fine, but save using this method for a couple of years in the future when you are more use to the error messages and how to read them and fix them.

Starting is not the best example, but its layout will work better for you in the beginning for dealing with error messages. It also makes more sense when working with a larger function.

The function, as short as it is, may work better defined as an "inline" function. Even then it may still be the compiler's choice to use it.

The "inputMsg" function I have started to change to eliminate the "goto"s which most of the time is a bad way to program, but they still have a use on occasion.

The while loop replaces the "goto" and gives you better control of the input. In the future you may find that up to maybe 1/2 of the program is just checking for errors on input, but now is a good time to learn and understand this.

The while loop from line 23 - 36 can be copied to replace lines 45 - 51.

In the "arrayAssign" function there are minor changes compared to what you started with.

The "inverseArray" function I have not worked on yet. Still thinking about how to do this.

The comments in "main" should be enough.

Something to notice is the use of blank lines to break up the code and make it easier to read and follow. Since memory and storage are not a problem these days make your code easy to read. The first benefit is to you. The second benefit is to you making errors easier to find.

Looking back at line 12 "MAXINPUT" may not be the best name and can be changed if you think of something better. It was just a thought at the time.

The use of the constant variables in lines 11 and 12 are to replace the magic numbers in your code like:
if (array[c][d] < 0 || array[c][d] > 100). Say that you have a program with 2000 lines of code and the number 100 needs to be changed in 60 of those lines it is very possible that you will miss 1 or 2 maybe more and it may not show up for a while that there is a problem.

Andy
Perhaps:

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
#include <iostream>
#include <limits>
#include <string>
#include <iomanip>

template<typename T = int>
auto getNum(const std::string& prm)
{
	const auto notsp {[&]() {while (std::isspace(static_cast<unsigned char>(std::cin.peek())) && std::cin.peek() != '\n') std::cin.ignore(); return std::cin.peek() != '\n'; }};
	T n {};

	while ((std::cout << prm) && (!(std::cin >> n) || notsp())) {
		std::cout << "Not a number\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	return n;
}

constexpr unsigned MAXROWS {10}, MAXCOLS {10};
constexpr unsigned ARRMIN {1}, ARRMAX {10}, MAXINPUT {100};

using MyArray = int[MAXROWS][MAXCOLS];

auto& errorMsg(int minval, int maxval)
{
	return (std::cerr << "\nERROR. Number is not within range " << minval << " - " << maxval << ". Try again.\n\n");
}

void inputMsg(unsigned& rows, unsigned& cols)
{
	std::string prmpt {"Enter the number of rows (" + std::to_string(ARRMIN) + " - " + std::to_string(ARRMAX) + "): "};

	do {
		rows = getNum(prmpt);
	} while ((rows < ARRMIN || rows > ARRMAX) && errorMsg(ARRMIN, ARRMAX));

	prmpt = "Enter the number of cols (" + std::to_string(ARRMIN) + " - " + std::to_string(ARRMAX) + "): ";

	do {
		cols = getNum(prmpt);
	} while ((cols < ARRMIN || cols > ARRMAX) && errorMsg(ARRMIN, ARRMAX));
}

void arrayAssign(MyArray array, unsigned rowsUsed, unsigned colsUsed)
{
	std::cout << '\n';

	for (unsigned row = 0; row < rowsUsed; ++row)
		for (unsigned col = 0; col < colsUsed; ++col) {
			auto& elem {array[row][col]};

			const std::string prmpt {"Enter int. digit for row " + std::to_string(row + 1) +
				" column " + std::to_string(col + 1) + " (" + std::to_string(ARRMIN) + " - " + std::to_string(MAXINPUT) + "): "};

			do {
				elem = getNum(prmpt);
			} while ((elem < ARRMIN || elem > MAXINPUT) && errorMsg(ARRMIN, MAXINPUT));

		}
}

void inverseArray(MyArray array, unsigned rowsUsed, unsigned colsUsed)
{
	std::cout << "\nCongrats!!! Here is your reversed 2D Array!\n";

	for (unsigned j = 0; j < colsUsed; ++j) {
		for (unsigned k = 0; k < rowsUsed; ++k)
			std::cout << std::setw(3) << array[k][j] << ' ';

		std::cout << '\n';
	}
}

int main()
{
	unsigned rows {}, cols {};
	MyArray a2 {};

	inputMsg(rows, cols);
	arrayAssign(a2, rows, cols);
	inverseArray(a2, rows, cols);
}


Just accept getNum() that displays a prompt and inputs a number and only returns when a number is entered.
Topic archived. No new replies allowed.