Получить данные для двумерного массива в отдельной функции?

Ошибка при передаче массива в качестве параметра функции. Я не могу понять, как читать элементы массива в отдельной функции, а затем печатать их с помощью отдельной функции. Обе функции имеют ошибку, которую я не могу исправить.

#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;
}

Как я буду вызывать эту функцию из основного?

Mohit Singh 14.12.2020 02:56

Вы не можете. C++ не поддерживает VLA (массивы переменной длины). int arr[m][n]; — это 2D VLA. В C вы можете использовать VLA (но поддержка компилятора не является обязательной, начиная с C11). Вы должны использовать std::vector<std::vector<int>> для ввода неизвестного количества строк и столбцов. См. std::vector

David C. Rankin 14.12.2020 03:15

Обратите внимание, что g++ разрешает VLA в C++, но это определенно расширение стандартного C++.

Jonathan Leffler 14.12.2020 07:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
100
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы все еще застряли, то, как отмечено в комментарии, самая большая проблема с вашим кодом — это использование массива переменной длины. C++ не предоставляет VLA, C начал с C99, но начиная с C11 их поддержка компилятором стала необязательной. Короче говоря, вы не можете использовать VLA в C++ (за исключением нестандартного расширения компилятора), а для переносимого кода на C их лучше избегать.

станд::вектор

C++ предоставляет std::vector для создания контейнера одинаковых элементов неизвестного числа. Заголовок <vector>. std::vector обеспечивает автоматическое управление памятью. Есть несколько способов добавления к вектору, общий способ — с помощью функции-члена .push_back(), которая просто добавляет новый элемент в конец. Вы объявляете простой вектор int как:

std::vector<int>

Для вашего 2D-массива int вы просто используете вектор векторов (так же, как 2D-массив — это просто массив или массивы). Вы объявляете вектор векторов для int как:

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

(просто вектор vector<int>)

Ваш код, создающий массив m x n

Для начала вы должны получить количество строк (m) и количество столбцов (n) от пользователя:

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;
    }

Из main(), если пользователь не вводит допустимое целое число для строк или столбцов, программа выводит ошибку и возвращает EXIT_FAILURE (1).

Вы можете объявить свой вектор векторов в начале, так как нет необходимости указывать количество элементов во время объявления (вы можете указать количество элементов, чтобы свести к минимуму количество перераспределений, необходимых за кулисами), здесь:

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

Ваша функция getData()

Поскольку вы вводите данные в getData(), он должен возвращать значение, указывающее, все ли входные данные были успешными или нет. Вы можете сделать этот тип int и вернуть 1/0 (true/false) или использовать тип bool и вернуть (true/false). Поскольку вы хотите собрать определенное количество строк и определенное количество столбцов, вы должны передать m и n в качестве параметров своей функции. С минимальной проверкой ошибок и обработкой руководства EOF, если пользователь нажимает Ctrl + d (или Ctrl + z в Windows), вы можете сделать:

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 */
}

Обратите внимание, что целочисленный ввод считывается во временную целочисленную переменную itmp, а строка данных за раз собирается во временную vector<int> с именем vtmp. После успешного добавления целых чисел n к vtmp временный вектор добавляется к вашему вектору векторов с помощью v.push_back(vtmp);.

Ваша функция printArray()

Ваша функция printArray() не требует передачи m или n в качестве параметров, поскольку после того, как вы добавили свои данные в вектор, вектор может сообщать о количестве содержащихся в нем элементов через функцию-член .size(). Чтобы вывести смоделированный 2D-массив, вы можете использовать цикл for на основе диапазона, например.

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 */
    }
}

Вернувшись в main() перед вызовом printArray(), вы ПОДТВЕРДИТЕ, что getData() удалось, например.

    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);

Если поместить это в целом, вы можете сделать:

#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);
}

(примечание: вы захотите просмотреть Почему «использование пространства имен std;» считается плохой практикой?)

Пример использования/вывода

$ ./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

С преднамеренной ошибкой ввода:

$ ./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

Существует много-много способов структурировать подпрограмму ввода. Вы можете запросить и отобразить приглашение для каждого элемента или, как вы предложили, и сделано выше, просто запрашивать для каждой строки целочисленных значений. Здесь при ошибке пользователю даются индексы следующего требуемого элемента.

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

Другие вопросы по теме