Как сделать функцию, которая заполняет массив, отправленный функции? Вместо массива в его параметрах - PullRequest
0 голосов
/ 01 мая 2018

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

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <string>

using namespace std;

class Functions
{
private:
    int input{};
    int numRows{};
    int numColumns{};
    int holder{};

public:
    void rndArrayMaxNumber (int x, int y)
    {
        int tempArray [x][y]{};
        srand(time(0));

        for (int j=0;j<x;j++)
        {
            for (int i=0;i<y;i++)
            {
                tempArray[j][i]= (rand()%99)+1;
            }
        }

        for (int j=0;j<x;j++)
        {
            for (int i=0;i<x-1;i++)
            {
                for (int k=0;k<y-1;k++)
                {
                    if (tempArray[i][k] < tempArray[i][k+1])
                    {
                        holder=tempArray[i][k];
                        tempArray[i][k]=tempArray[i][k+1];
                        tempArray[i][k+1]=holder;
                    }
                }

            }
        }

        for (int j=0;j<y;j++)
        {
            for (int i=0;i<y-1;i++)
            {
                for (int k=0;k<x-1;k++)
                {
                    if (tempArray[k][i] < tempArray[k+1][i])
                    {
                        holder=tempArray[k][i];
                        tempArray[k][i]=tempArray[k+1][i];
                        tempArray[k+1][i]=holder;
                    }
                }

            }
        }

        for (int i=0;i<y;i++)
        {
            for (int k=0;k<x;k++)
            {
                cout << tempArray[i][k] << "\t";
            }
            cout << endl;
        }
        cout << endl << "The greatest number is " << tempArray[0][0];
    }

    void arrayChoice ()
    {
        cout << "Enter the number of rows: ";
        cin >> numRows;
        cout << "Enter the number of columns: ";
        cin >> numColumns;
        cout << endl;
    }

    void menu ()
    {
        while (input!=7)
        {
            cout << "1. 2D array random numbers and show highest number" << endl;
            cout << "2. Exit" << endl << endl;
            cout << "Enter the number of the menu option you want to proceed with: ";
            cin >> input;
            cout << endl;
            switch (input)
            {
                case 1:
                    arrayChoice();
                    rndArrayMaxNumber(numRows, numColumns);
                    cout << endl << endl;
                    break;
            }
        }
    }
};

int main()
{
    Functions program;
    program.menu();
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Массивы не могут быть надежно динамически измерены, поскольку стандарт C ++ требует, чтобы размер всех массивов был известен при компиляции программы. Некоторые компиляторы допускают использование динамически изменяемых массивов в качестве расширения, но, поскольку все вещи нестандартны, на поддержку нельзя рассчитывать. Лучше избегать массивов переменной длины, если только по причине переносимости. И есть много других причин ( обсуждение здесь ).

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

OK. Так что вы делаете вместо этого? Общее решение

std::vector<std::vector<int>> array_2d(x, std::vector<int>(y));

Затем вы передаете array_2d по ссылке, чтобы минимизировать копирование

void rndArrayMaxNumber (std::vector<std::vector<int>> & array_2d)

Нет необходимости пропускать x и y. vector знает, насколько она велика.

Это просто и в значительной степени самообеспечение. Это, наверное, все, что вам нужно. Скорее всего, вы не будете задавать этот вопрос или читать этот ответ, если пишете высокопроизводительный код.

Тем не менее, у него есть некоторые недостатки в производительности, поскольку один vector гарантированно является непрерывным блоком памяти, а vector из vector s - нет. Это обрекает программу на погоню за указателями в памяти и склонность к плохому поведению в кэшировании. Каждый раз, когда программе приходится покидать процессор и высокоскоростной кэш, чтобы извлечь данные из ОЗУ (или, не дай бог, файл подкачки), вы оставляете среду, работающую в нескольких гигагерцах, за одну, работающую в сотнях мегагерц или хуже.

Подробнее о том, как это неприятно, можно получить здесь: https://blog.codinghorror.com/the-infinite-space-between-words/

Плюс каждое распределение имеет свои затраты. Одно большое выделение может стоить намного меньше, чем 1 vector размера x и x vector размера y.

В связи с этим я рекомендую простой матричный класс, основанный на одном vector.

#include <iostream>
#include <vector>


// template because if you are going to write this, why restrict yourself to just int?
template<class TYPE>
class Matrix
{
private:
    // good to know how big you are
    size_t rows, columns;
    // and the vector containing the data 
    std::vector<TYPE> matrix;
public:
    Matrix(size_t numrows, size_t numcols) :
            rows(numrows), // remember the size
            columns(numcols), 
            matrix(rows * columns) // and allocate storage
    {
    }

    // does the same thing as the other constructor, except it sets a default value
    Matrix(size_t numrows, size_t numcols, TYPE init) :
            rows(numrows), columns(numcols), matrix(rows * columns, init)
    {
    }

    // gets the value at row, column and allows it to be modified        
    TYPE & operator()(size_t row, size_t column)
    {
        // check bounds here if you want
        // note the indexing math mapping 2 dimensions into 1
        return matrix[row * columns + column];
    }

    // gets a copy of the the value at row, column
    TYPE operator()(size_t row, size_t column) const
    {
        return matrix[row * columns + column];
    }

    // obvious what the next two methods do
    size_t getRows() const
    {
        return rows;
    }
    size_t getColumns() const
    {
        return columns;
    }

};

// handy dandy output helper.
friend std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
    for (int i = 0; i < in.getRows(); i++)
    {
        for (int j = 0; j < in.getColumns(); j++)
        {
            out << in(i, j) << ' ';
        }
        out << '\n';
    }

    return out;
}

Обратите внимание, что этот ответ вообще не вводит new в уравнение.

Если вы хотите пойти по маршруту, вам нужно сделать гораздо больше работы. Как объявить 2d-массив в C ++, используя new? поможет вам начать этот путь, но, опять же, вам лучше обернуть один массив, как здесь: Как создать оператор индекса для класса Matrix?

Обратите особое внимание на невыполненный конструктор копирования и оператор присваивания. Это волшебный соус для создания хорошего матричного класса вокруг динамического массива, и по причинам, которые я могу отнести только к садизму, они исключены из этого примера. Прочитайте Что такое правило трех? для получения информации о том, зачем они нужны. Стоит прочитать ссылку «Правило трех», даже если вы используете vector, потому что вы не можете написать нетривиальный C ++ без твердого контроля над правилом трех ( и его друзьями Five и Zero ).

Документация по std::vector

0 голосов
/ 01 мая 2018

Есть несколько способов решения этой проблемы.

вы можете использовать функции begin () и end (), определенные в заголовке. Они возвращают первый и один после последнего указателя в массиве. Это позволяет вам сделать что-то вроде этого

void arr(int *b, int *e)
{
        /*code that reads/changes array i.e b[1] = 1 b[3] = 2 etc.*/
}
int main() {
        int a[10]; 
        arr(begin(a), end(a)); 
}

Другим способом является передача указателя на первый элемент в массиве вместе с размером массива

void arr(int *b, size_t sz)
{
        /*code that reads/changes array */
}
int main() {     
        int a[10]; 
        arr(a, 10); 
}

Вы также можете передать массив через ссылку или указатель на функцию, например так:

void array_function(T (*pointer_to_array)[n])

, где T представляет тип, а n представляет размер массива. Таким образом, передача массива типа int размером 10 будет выглядеть следующим образом:

int a[10];

array_function(&a);

и оттуда вы можете получить доступ к элементам массива в теле функции, используя оператор deference и subscript:

*pointer_to_array[element] изменения, внесенные в переменную в функции, отражаются в массиве a

Вы также можете передать массив по ссылке:

void array_function(T (&reference_to_array)[n])

массив передается функции аналогичным образом, но без адреса оператора &

int a[10];

array_function(a);

к массиву и его элементам можно получить доступ в теле функции, используя имя параметра и оператор индекса:

reference_to_array[element]

, поэтому любые изменения, внесенные в reference_to_array, также отражаются в a

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...