-2

There is an error while passing the array as a function parameter. I am unable to figure out how to read elements of an array in a separate function and then print it using a separate function. Both functions have an error I am unable to correct.

#include <iostream>
using namespace std;

int m,n;

void getData(int (&arr)[m][n]){
for (int i=0;i<m;i++){
    cout<<"Enter elements of row "<<i+1<<endl;
    for (int j=0;j<n;j++){
        cin>>arr[i][j];
    }
}
}

void printArray(int arr[m][n]){
for (int i=0;i<m;i++){
    for (int j=0;j<n;j++){
        cout << arr[i][j]<<" ";
    }
    cout<<endl;
}
}

int main(){
cout << "Enter the number of rows of the array:\n";
cin >> m;
cout << "Enter the number of columns of the array:\n";
cin >> n;

int arr[m][n];

getData(arr);
printArray(arr);

return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mohit Singh
  • 143
  • 11
  • How will I call this function from inside the main? – Mohit Singh Dec 14 '20 at 01:56
  • You cannot. C++ does not provide for VLA (*Variable Length Arrays*). `int arr[m][n];` is a 2D VLA. In C you can use VLAs (but compiler support is optional beginning with C11). You should use `std::vector>` for your input of an unknown number of rows and columns. See [std::vector](https://en.cppreference.com/w/cpp/container/vector) – David C. Rankin Dec 14 '20 at 02:15
  • Note that `g++` does allow VLAs in C++, but it is definitely an extension over Standard C++. – Jonathan Leffler Dec 14 '20 at 06:44

1 Answers1

2

If you are still stuck, then as noted in the comment, the biggest problem with your code is the use of a Variable Length Array. C++ does not provide VLAs, C did beginning with C99, but as of C11 made compiler support for them optional. In short, you can't use VLAs in C++ (except by non-standard compiler extension), and for portable code in C, they are best avoided.

std::vector

C++ provides std::vector for creating a container of like elements of unknown number. The header is <vector>. std::vector provides automatic memory management for you. There are several ways to add to a vector, the general way is with the .push_back() member function that simply adds the new element at the end. You declare a simple vector of int as:

std::vector<int>

For your 2D array of int, you simply use a vector of vectors (much like a 2D array is simply an array or arrays). You declare a vector of vectors to int as:

std::vector<std:vector<int>>

(just a vector of vector<int>)

Your Code Creating a m x n Array

To begin, you would obtain the number of rows (m) and number of columns (n) from the user:

int main (void) {
    
    int m = 0, n = 0;                               /* don't use global variables */

Avoid the use of global variables. Declare variables in the scope needed and pass as parameters to any function requiring them.

With ALL user-input you must VALIDATE EVERY INPUT. If you take nothing else from this answer, learn that you must check the return (stream-state) following every user-input to determine whether the input succeeded or failed. Blindly using a variable after user-input without verifying it contains valid input will invoke Undefined Behavior following a failed input. You can validate the rows and columns input as:

    std::cout << "number of rows in array: ";
    if (!(std::cin >> m)) {                         /* validate EVERY input */
        std::cerr << "error: invalid integer input.\n";
        return 1;
    }
    std::cout << "number of cols in array: ";
    if (!(std::cin >> n)) {                         /* ditto */
        std::cerr << "error: invalid integer input.\n";
        return 1;
    }

From main() if the user fails to provide valid integer input for the rows or columns, the program outputs an error and returns EXIT_FAILURE (1).

You can declare your vector of vectors at the beginning as there is no requirement to specify the number of elements at the time of declaration (you can specify the number of elements to minimize the number of times reallocation is needed behind the scenes), Here:

    // int arr[m][n];   /* VLAs are NOT part of C++, use std::vector<std::vector<int>> */
    std::vector<std::vector<int>> arr{};

Your getData() Function

Since you are taking input within getData(), it must return a value indicating if all input succeeded or failed. You can make that type int and return 1/0 (true/false) or use type bool and return (true/false). Since you want to collect a specific number of rows and a specific number of columns, you must pass m and n as parameters to your function. With minimal error checking, and handling a manual EOF if the user presses Ctrl + d (or Ctrl + z on windows), you could do:

int getData (int m, int n, std::vector<std::vector<int>>& v)
{
    for (size_t i=0; i<(size_t)m; i++) {        /* loop m times filling temp vector */
        std::vector<int> vtmp{};                /* temp vector to fill */
        std::cout << "Enter elements of row[" << i+1 << "]: ";
        for (size_t j=0; j<(size_t)n;) {        /* loop n time adding n int to temp vect */
            int itmp;                           /* temp integer */
            if (std::cin >> itmp) {             /* you must VALIDATE EVERY USER-INPUT */
                vtmp.push_back(itmp);           /* on good input, add to temp vector */
                j++;                            /* increment loop var only on good input */
            }
            else {  /* handle error */
                if (std::cin.eof())             /* if manual EOF, user canceled */
                    return 0;                   /* return failue */
                /* otherwise display error, prompt for next input needed */
                std::cerr << "  error: invalid integer input.\n" <<
                            "arr[" << i << "][" << j << "]: ";
                std::cin.clear();               /* clear stream state */
                /* clear bad input to end-of-line */
                std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
            }
        }
        v.push_back(vtmp);      /* add temp vector to arr (vector of vectors) */
    }
    
    return 1;       /* return success */
}

Note above integer input is read into a temporary integer variable itmp and a row of data at a time is collected in a temporary vector<int> named vtmp. After successfully adding n integers to vtmp the temporary vector is added to your vector of vectors with v.push_back(vtmp);.

Your printArray() Function

Your printArray() function does not need m or n passed as parameters, since after your have added your data to the vector, a vector can report the number of elements it contains through the .size() member function. To output your simulated 2D array you can make use of a Range-based for loop, e.g.

void printArray (const std::vector<std::vector<int>>& v)
{
    for (const auto& r : v) {                   /* loop over rows */
        for (const auto& c : r)                 /* loop over cols */
            std::cout << std::setw(3) << c;     /* output col value */
        std::cout.put('\n');                    /* output newline */
    }
}

Back in main() before calling printArray() you will VALIDATE that getData() succeeded, e.g.

    if (!getData (m, n, arr)) {                     /* validate getData succeeded */
        std::cerr << "error: getData() failued to fill arr.\n";
        return 1;
    }
    
    std::cout << "\nArray content:\n\n";            /* output array */
    printArray (arr);

Putting it altogether, you could do:

#include <iostream>
#include <iomanip>
#include <vector>
#include <limits>

int getData (int m, int n, std::vector<std::vector<int>>& v)
{
    for (size_t i=0; i<(size_t)m; i++) {        /* loop m times filling temp vector */
        std::vector<int> vtmp{};                /* temp vector to fill */
        std::cout << "Enter elements of row[" << i+1 << "]: ";
        for (size_t j=0; j<(size_t)n;) {        /* loop n time adding n int to temp vect */
            int itmp;                           /* temp integer */
            if (std::cin >> itmp) {             /* you must VALIDATE EVERY USER-INPUT */
                vtmp.push_back(itmp);           /* on good input, add to temp vector */
                j++;                            /* increment loop var only on good input */
            }
            else {  /* handle error */
                if (std::cin.eof())             /* if manual EOF, user canceled */
                    return 0;                   /* return failue */
                /* otherwise display error, prompt for next input needed */
                std::cerr << "  error: invalid integer input.\n" <<
                            "arr[" << i << "][" << j << "]: ";
                std::cin.clear();               /* clear stream state */
                /* clear bad input to end-of-line */
                std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
            }
        }
        v.push_back(vtmp);      /* add temp vector to arr (vector of vectors) */
    }
    
    return 1;       /* return success */
}

void printArray (const std::vector<std::vector<int>>& v)
{
    for (const auto& r : v) {                   /* loop over rows */
        for (const auto& c : r)                 /* loop over cols */
            std::cout << std::setw(3) << c;     /* output col value */
        std::cout.put('\n');                    /* output newline */
    }
}

int main (void) {
    
    int m = 0, n = 0;                               /* don't use global variables */
    
    std::cout << "number of rows in array: ";
    if (!(std::cin >> m)) {                         /* validate EVERY input */
        std::cerr << "error: invalid integer input.\n";
        return 1;
    }
    std::cout << "number of cols in array: ";
    if (!(std::cin >> n)) {                         /* ditto */
        std::cerr << "error: invalid integer input.\n";
        return 1;
    }
    
    // int arr[m][n];   /* VLAs are NOT part of C++, use std::vector<std::vector<int>> */
    std::vector<std::vector<int>> arr{};
    
    if (!getData (m, n, arr)) {                     /* validate getData succeeded */
        std::cerr << "error: getData() failued to fill arr.\n";
        return 1;
    }
    
    std::cout << "\nArray content:\n\n";            /* output array */
    printArray (arr);
}

(note: you will want to review Why is “using namespace std;” considered bad practice?)

Example Use/Output

$ ./bin/vla_input
number of rows in array: 3
number of cols in array: 3
Enter elements of row[1]: 1 2 3
Enter elements of row[2]: 4 5 6
Enter elements of row[3]: 7 8 9

Array content:

  1  2  3
  4  5  6
  7  8  9

With intentional error in input:

$ ./bin/vla_input
number of rows in array: 3
number of cols in array: 3
Enter elements of row[1]: 1 2 3
Enter elements of row[2]: 4 bananas 6
  error: invalid integer input.
arr[1][1]: 5 6
Enter elements of row[3]: 7 8 9

Array content:

  1  2  3
  4  5  6
  7  8  9

There are many, many ways to structure the input routine. You can have it prompt for and display a prompt for each element, or as you proposed, and is done above, simply prompt for each row of integer values. Here, on error, the user is given the indexes of the next element required.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85