C++ задача про динамические массивы и функции

Помогите решить задачу пожалуйста.
Написать программу, в которой имеется двумерный массив 5х5, состоящий из случайных чисел. Программа подсчитывает сумму элементов побочной диагонали.
Если сумма больше 200, то программа создает два одномерных динамических массива, в один записывает четные элементы массива, в другой – нечетные.
Если сумма меньше 200, то создается три одномерных динамических массива, первый - с элементами большими 10 из первых двух столбцов, второй - с элементами меньшими 30 из последних двух столбцов и третий динамический массив заполняется элементами среднего столбца, которые больше 50. Реализовать решение при помощи функций.

Что именно не получается? Что пробовали делать?

Не могу сообразить каким образом реализовать формирование динамических массивов, чтобы код был компактным и были соблюдены все условия. Проблем с подсчетом суммы элементов побочной диагонали нет и как подсчитать элементы массива согласно условиям тоже. Не могу собрать это все в кучу. Понимаю, что нужно использовать указатели, но как это сделать не могу понять, как реализовать чтобы размер нового массива был равен сумме элементов из условия?

Тут основная сложность в том, что в задании вроде бы просят динамические массивы, а не просто заранее создать максимального размера.

Если надо использовать обычные массивы из С, а не std::vector.

Потому что с С-массивами принято делать так, чтобы они освобождались (delete/free) на том же уровне, где и создавались (new/malloc).

Но вообще технически вроде бы никто не мешает вернуть указатель из функции и потом освободить снаружи как-то так:

void createArray(int** result, int* resultSize)
{
    ...........
    *resultSize = 8;
    *result = new int[8];
    ...............
}

int main()
{
    int* arr;
    int size;
    createArray(&arr, &size);

    // вывод arr
    for (int i = 0; i < size; .......
    ........

    delete arr;
}

Ну и еще тут видимо требуется менять размер массива по мере необходимости (то есть понадобилось добавить элемент — увеличил массив).

Обычно для оптимизации производительности для этого создают дополнительную абстракцию, в которой хранятся два размера: реальный и используемый. Чтобы не пересоздавать при каждом добавлении элемента (то есть выделять новый блок памяти размером N+1, копировать массив, удалять старый), а иногда увеличивать например в 2 раза. Это и есть упрощенный std::vector, кстати :slight_smile:
https://stackoverflow.com/a/3536261/964478

Но тут может сойдет и по одному (но функции типа createArray, resizeArray, addElement все равно стоит создать).

В случае сырых указателей надо использовать 2 прохода:
вначале вычислить необходимую длину массива, а затем, выделив под него память, заполнить.

Есть функция, которая считает согласно условиям требуемое количество элементов. Как к ним обратиться в качестве из функции которая создает динамические массивы и можно ли это или как реализовать решение данной задачи? Я только начал разбираться с этим, начал с С++, а он невероятно сложный, поэтому не судите строго))

void Create(int arr[][5], int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            arr[i][j] = rand() % 100;
        }
    }
}


void Show(int arr[][5], int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
        
          cout << setw(5) << arr[i][j] << " ";
        }
        cout << "\n";
    }
}
void Sec_Diag(int arr[][5], int size)
{
    int sum = 0;
    int count_even = 0;
    int count_odd = 0;
    int count_ten = 0;
    int count_thr = 0;
    int count_fif = 0;
    
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            if (i + j == 4)

                sum += arr[i][j];

        }

    }
    cout << "Sum of the Secondary diagonal is " << sum << endl;

    if (sum > 200)
    {

        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                if (arr[i][j] % 2 == 0)
              
                    count_even++;

                else
               
                    count_odd++;
               
            }

        }
        cout << "Amount of even elements is " << count_even << endl;
        cout << "Amount of odd elements is " << count_odd << endl;
    }  
    else
    {
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                if (arr[i][j] > 10 && i < size && j <= 1)

                    count_ten++;

                else if (arr[i][j] < 30 && i < size && j >= 3)

                    count_thr++;

                else if (arr[i][j] > 50 && i < size && j == 2)
                    
                    count_fif++;
            }

        }
        cout << "Amount of the elements more than 10 " << count_ten << endl;
        cout << "Amount of the elements less than 30 " << count_thr << endl;
        cout << "Amount of the elements more than 50 " << count_fif << endl;
    }
}
int main()
{
    srand(time(NULL));
    int const size = 5;
    int arr[size][size];
    Create(arr, size);
    Show(arr, size);
    cout << endl;
    Sec_Diag(arr, size);

Sec_Diag лучше разделить на CalculateSecondaryDiagonal, GetOddMatrixValues, GetEvenMatrixValues и т.п.

Есть два варианта:

Если вы выбрали второй, то либо просто сделать два цикла в функции (сначала посчитать, потом создать и заполнить), либо сделать функции типа CountXXX, GetXXX (CountOddMatrixValues, GetOddMatrixValues) и вызывать внутри второй первую, то есть первый проход выносится в CountXXX.

Еще чтобы не повторять два раза основную логику (обход с проверкой четности и т.д.) можно сделать функцию принимающую функцию (как std::accumulate и т.п.), но это вряд ли ожидается преподом если это совсем начальный уровень :partyparrot:

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <functional>

using namespace std;

const int MATRIX_SIZE = 5; // в С++ статический 2D С-массив иначе всё равно сложно передать в функцию без указания размера константой (в C99 можно с dynamic VLA)

void FillRandomMatrix(int matrix[][MATRIX_SIZE])
{
    for (int i = 0; i < MATRIX_SIZE; i++)
    {
        for (int j = 0; j < MATRIX_SIZE; j++)
        {
            matrix[i][j] = rand() % 100;
        }
    }
}

void PrintMatrix(int matrix[][MATRIX_SIZE])
{
    for (int i = 0; i < MATRIX_SIZE; i++)
    {
        for (int j = 0; j < MATRIX_SIZE; j++)
        {
            cout << setw(5) << matrix[i][j] << " ";
        }
        cout << "\n";
    }
}

void PrintArray(int* arr, int size)
{
    for (int i = 0; i < size; i++)
    {
        cout << arr[i] << " ";
    }
}

void TraverseOddMatrixValues(int matrix[][MATRIX_SIZE], function<void(int)> callback)
{
    for (int i = 0; i < MATRIX_SIZE; i++)
    {
        for (int j = 0; j < MATRIX_SIZE; j++)
        {
            int val = matrix[i][j];
            if (val % 2 != 0)
            {
                callback(val);
            }
        }
    }
}

int CountOddMatrixValues(int matrix[][MATRIX_SIZE])
{
    int c = 0;
    TraverseOddMatrixValues(matrix, [&c](int val) { c++; }); // https://en.cppreference.com/w/cpp/language/lambda
    return c;
}

void GetOddMatrixValues(int matrix[][MATRIX_SIZE], int* arr)
{
    int i = 0;
    TraverseOddMatrixValues(matrix, [&i, arr](int val) { arr[i++] = val; });
}

int main()
{
    srand(time(NULL));
    int matrix[MATRIX_SIZE][MATRIX_SIZE];
    FillRandomMatrix(matrix);
    PrintMatrix(matrix);
    
    int oddValuesCount = CountOddMatrixValues(matrix);
    int* oddValuesArr = new int[oddValuesCount];
    GetOddMatrixValues(matrix, oddValuesArr);
    cout << "Odd values: ";
    PrintArray(oddValuesArr, oddValuesCount);
    
    return 0;
}

https://rextester.com/DAMFU44299

Как раз выйдет без кучи портянок.
Еще надо передавать:
-флаг подсчета/заполнения
-указатель на число - кол-во или заполняемый массив
-диапазон колонок
А вот основной массив бы я оставил глобальным, ибо лень :laughing: Сказав, что надо обернуть в класс, а их еще не проходили)

Так флаг не нужен если функцию передавать.

Еще, кстати, можно и в Count/Get функцию передавать, чтобы и этот код не дублировать.

int Count(int matrix[][MATRIX_SIZE], function<void(int[][MATRIX_SIZE], function<void(int)>)> operation)
{
    int c = 0;
    operation(matrix, [&c](int val) { c++; }); // https://en.cppreference.com/w/cpp/language/lambda
    return c;
}

void Extract(int matrix[][MATRIX_SIZE], function<void(int[][MATRIX_SIZE], function<void(int)>)> operation, int* arr)
{
    int i = 0;
    operation(matrix, [&i, arr](int val) { arr[i++] = val; });
}

int main()
{
    ...
    
    int oddValuesCount = Count(matrix, TraverseOddMatrixValues);
    int* oddValuesArr = new int[oddValuesCount];
    Extract(matrix, TraverseOddMatrixValues, oddValuesArr);
    cout << "Odd values: ";
    PrintArray(oddValuesArr, oddValuesCount);
    
    return 0;
}

https://rextester.com/SKY30556

Так функции можно передавать просто возвращающие лог. значение.
Еще удобно, поменяв флаг, разово вызвать саму себя для заполнения массива.
Когда 2 прохода, часто удобен именно флаг. Его значение нужно задать по умолчанию, чтобы не выворачивать наружу.

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

Не понял что это значит, но скорее всего это не нужно.
Смотрите мой пример выше. На function можно не обращать внимание для начала, просто вместо TraverseOddMatrixValues скопировать этот цикл в CountOddMatrixValues и GetOddMatrixValues заменив вызов callback(val) на увеличение счетчика (в CountOddMatrixValues) и запись значения в переданный массив (в GetOddMatrixValues).