1

Тема: Динамічна пам'ять і матриці

Підкажіть де я наробив дурниць?

//Ввести цілочисельну матрицю 10×3 і створити нову матрицю з тих рядків 
//введеної матриці, які містять хоча б один елемент – двійку
#include "pch.h"
#include <iostream>
#include <ctime>
using namespace std;

int main()
{
    srand(time(NULL)); 
    setlocale(LC_CTYPE, "ukr");
    int a[10][3], i, j, rowc = 0, k = 0;
    cout << "Введiть матрицю з 10-ти рядкiв i 3-х стовпцiв:" << endl;
    int r[10] = { 0 };// r – масив кількості двійок в рядках матриці   
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 3; j++)
        {
            a[i][j] = (rand() % 16) - 1;
            if (a[i][j] == 2)
            {
                r[i]++;
            }
        }
    }
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 3; j++)
        {
            cout << a[i][j] << "\t";
        }
        cout << endl;
    }
    for (i = 0; i < 10; i++)// Обчислення кількості рядків з 2-ою     
        if (r[i] == 1)
            rowc++; // r[i]=1  означає, що в і-му рядку є двійки   
    int **b = new int *[rowc];// Виділення пам’яті для динамічної матриці b
    for (i = 0; i < rowc; i++)
        b[i] = new int[3];
    for (i = 0; i < 10; i++)
    {
        if (r[i] != 0)// Якщо в і-му рядку нулів немає, відбувається
        {
            for (j = 0;j < 3;j++)
            {
                b[k][j] = a[i][j];//копіювання рядка у нову матрицю      
                k++;   // і збільшення індексу рядка нової матриці.
            }
        }
    }
    cout << "\nМатриця, в рядках якої є двійки:" << endl;
    for (i = 0; i < rowc; i++)
    {
        for (j = 0; j < 3; j++)
            cout << b[i][j] << "\t";
        cout << endl;
    }
    // Звільнення пам’яті від динамічної матриці 
    for (int i = 0; i < rowc; i++)
        delete[] b[i];
    delete[]b;
    system("pause>>void");
    return 0;
}

Помилка:
https://replace.org.ua/uploads/images/9488/d21d315cf81e3e2910bc80e11323ecb8.png

Прихований текст

Також, я не впевнений чи правильно використав масив r[]

2 Востаннє редагувалося wander (14.01.2020 14:23:07)

Re: Динамічна пам'ять і матриці

Ну от маєте невизначену поведінку, через вихід за межі масиву (швидше за все).
А може і ще через що, у вашому коді чорт ногу зломить, тому беріть дебагер, ставте точку зупину у тому місці, та дивіться на індекси k, i, j та яких вони набувають значень, або коли хтось це зробить за вас, особисто у мене немає часу розбирати весь цей спагетті код.
Взагалі, це теж потенційне місце для UB

int **b = new int *[rowc];

, бо де гарантія, що rowc > 0?

3

Re: Динамічна пам'ять і матриці

ясно

adziri написав:

Ну от маєте невизначену поведінку, через вихід за межі масиву (швидше за все).
А може і ще через що, у вашому коді чорт ногу зломить, тому беріть дебагер, ставте точку зупину у тому місці, та дивіться на індекси k, i, j та яких вони набувають значень, або коли хтось це зробить за вас, особисто у мене немає часу розбирати весь цей спагетті код.
Взагалі, це теж потенційне місце для UB

int **b = new int *[rowc];

, бо де гарантія, що rowc > 0?

4 Востаннє редагувалося wander (14.01.2020 15:02:50)

Re: Динамічна пам'ять і матриці

del

5

Re: Динамічна пам'ять і матриці

adziri написав:

бо де гарантія, що rowc > 0?

Гм.

int a[10][3], i, j, rowc = 0, k = 0;
...
for (i = 0; i < 10; i++)
    if (r[i] == 1)
         rowc++;
int **b = new int *[rowc]; //при rowc==0 немає UB, але не можна звертатися до *b
for (i = 0; i < rowc; i++) //немає UB
      b[i] = new int[3]; 
for (i = 0; i < 10; i++)
   {
        if (r[i] != 0)
        {
            for (j = 0;j < 3;j++)
            {
                b[k][j] = a[i][j];//і лише тут буде UB, бо умова створення рядка - r[i]==1, а тут перевіряється r[i]!=0
                k++;   
            }
        }
    }

Зробіть умови на r[i] однаковими (або ==1, або !=0), і можна rowc на 0 не перевіряти.

6

Re: Динамічна пам'ять і матриці

koala написав:

при rowc==0 немає UB, але не можна звертатися до *b

adziri написав:

Взагалі, це теж потенційне місце для UB

Ну, так, не правильно виразився, це місце потенційно може спровокувати UB.

7

Re: Динамічна пам'ять і матриці

Загальні зауваження:
1. Визначайтеся з мовою. Якщо це C - то користуйтеся printf, якщо C++ - то беріть сучасний C++-ний <random>.
2. Визначайте розміри матриці (10х3) перед проголошенням масиву. Зміна розмірів - це очевидна зміна, і немає жодного сенсу робити програму прив'язаною до саме таких розмірів.

const unsigned int M = 10;
const unsigned int N = 3;
...
int a[M][N];

3. Про r[i]==1 уже написав - це неправильна умова, r[i]==2 теж означає, що там є двійки.
4. Оскільки це, знову ж таки, C++, подумайте про використання циклів по послідовностях (for(int i:a)).

Подякували: leofun011

8

Re: Динамічна пам'ять і матриці

#include "pch.h"
#include <iostream>
#include <ctime>
using namespace std;

int main()
{
    setlocale(LC_CTYPE, "ukr");
    srand(time(NULL));
    const unsigned int M = 10;
    const unsigned int N = 3;
    int a[M][N], i, j, rows = 0, k = 0;
    int r[M]{ 0 };
    cout << "Введiть матрицю з 10-ти рядкiв i 3-х стовпцiв:" << endl;
    for (i = 0;i < M;i++)
    {
        for ( j = 0; j < N; j++)
        {
            a[i][j] = rand() % 10;
            cout << a[i][j] << "\t";
            if (a[i][j] == 2)
            {
                r[i]++;
            }
        }
        cout << endl;
    }
    for ( i = 0; i < M; i++)
    {
        if (r[i] != 0)
        {
            rows++;
        }
    }
    int **b = new int *[rows];
    for (i = 0; i < rows; i++)
    {
        b[i] = new int[N];
    }
    for ( i = 0; i < M; i++)
        if (r[i] != 0)
        {
            for (j = 0; j < N; j++)
                b[k][j] = a[i][j];
                k++;
        }
    cout << "\nМатриця, в рядках якої є двiйки:" << endl;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < N; j++)
        {
            cout << b[i][j] << "\t";
        }
        cout << endl;
    }
    for (int i = 0; i < rows; i++)
    {
        delete[] b[i];
    }
    delete[] b;
    return 0;
}

Введiть матрицю з 10-ти рядкiв i 3-х стовпцiв:
2       6       5
6       3       3
7       3       6
4       1       8
6       1       0
4       3       0
1       3       4
5       0       5
2       0       4
6       3       5

Матриця, в рядках якої є двiйки:
2       6       5
2       0       4
Я вирішив написати все ще раз з нуля, але в мене виникла та сама проблема в тому ж рядку. Вирішення якої мене трохи здивувало

for (j = 0; j < N; j++)
            //{
                b[k][j] = a[i][j];
                k++;
            //}

Програма працює тільки без цих дужок, я навіть не розумію чим вони мішають

koala написав:

Загальні зауваження:
1. Визначайтеся з мовою. Якщо це C - то користуйтеся printf, якщо C++ - то беріть сучасний C++-ний <random>.
2. Визначайте розміри матриці (10х3) перед проголошенням масиву. Зміна розмірів - це очевидна зміна, і немає жодного сенсу робити програму прив'язаною до саме таких розмірів.

const unsigned int M = 10;
const unsigned int N = 3;
...
int a[M][N];

3. Про r[i]==1 уже написав - це неправильна умова, r[i]==2 теж означає, що там є двійки.
4. Оскільки це, знову ж таки, C++, подумайте про використання циклів по послідовностях (for(int i:a)).

9

Re: Динамічна пам'ять і матриці

grinyuk309 написав:

Програма працює тільки без цих дужок, я навіть не розумію чим вони мішають

Схоже, ви навіть не спробували:

adziri написав:

тому беріть дебагер, ставте точку зупину у тому місці, та дивіться на індекси k, i, j та яких вони набувають значень

10

Re: Динамічна пам'ять і матриці

grinyuk309 написав:

Програма працює тільки без цих дужок, я навіть не розумію чим вони мішають

А ви код вирівнюйте - і стане видно. З дужками:

    for ( i = 0; i < M; i++)
        if (r[i] != 0)
        {
            for (j = 0; j < N; j++)
            {
                b[k][j] = a[i][j];
                k++;
            }
        }

Без дужок:

    for ( i = 0; i < M; i++)
        if (r[i] != 0)
        {
            for (j = 0; j < N; j++)
                b[k][j] = a[i][j];
            k++;
        }

Тепер бачите, в чому відмінність?
Якби ви ще назвали змінні не i,j,k, а, скажімо, row_a, col, row_b, то все б стало взагалі зрозуміло.

11 Востаннє редагувалося wander (16.01.2020 00:20:47)

Re: Динамічна пам'ять і матриці

#include <iostream>

template <std::size_t N>
bool find_value(std::int32_t(&array)[N], std::int32_t const value) noexcept {
    for (std::size_t i = N; i--;) {
        if (value == array[i]) return true;
    }
    return false;
}

int main() {
    std::int32_t array[3][3]{{1, 5, 8},
                             {3, 2, 4},
                             {2, 7, 6}};
    
    std::int32_t new_array[3][3] = {};
    std::size_t  new_array_rows  = 0;
    for (std::size_t i = 0; i < 3; i++) {
        if (find_value(array[i], 2)) {
            std::memcpy(new_array + new_array_rows, array + i, sizeof(std::int32_t) * 3);
            new_array_rows++;
        }
    }
    
    for (std::size_t i = 0; i < new_array_rows; i++) {
        for (std::size_t j = 0; j < 3; j++) {
            std::cout << new_array[i][j];
        }
        std::cout << '\n';
    }
}

На колінці зроблено, можуть бути баги)

12

Re: Динамічна пам'ять і матриці

adziri написав:
template <std::size_t N>
bool find_value(std::int32_t(&array)[N], std::int32_t const value) noexcept {
    for (std::size_t i = N; i--;) {
        if (value == array[i]) return true;
    }
    return false;
}

Надмірність, неочевидність і велосипеди - наше все!

13 Востаннє редагувалося wander (15.01.2020 17:34:55)

Re: Динамічна пам'ять і матриці

koala написав:
adziri написав:
template <std::size_t N>
bool find_value(std::int32_t(&array)[N], std::int32_t const value) noexcept {
    for (std::size_t i = N; i--;) {
        if (value == array[i]) return true;
    }
    return false;
}

Надмірність, неочевидність і велосипеди - наше все!

Нічого такого чого б не робила стандартна бібліотека :)

14

Re: Динамічна пам'ять і матриці

adziri написав:

Нічого такого чого б не робила стандартна бібліотека :)

Тобто велосипед.

15

Re: Динамічна пам'ять і матриці

koala написав:
adziri написав:

Нічого такого чого б не робила стандартна бібліотека :)

Тобто велосипед.

Ну, таки

koala написав:

велосипеди - наше все

:)

16

Re: Динамічна пам'ять і матриці

Ага, я не помітив

koala написав:
grinyuk309 написав:

Програма працює тільки без цих дужок, я навіть не розумію чим вони мішають

А ви код вирівнюйте - і стане видно. З дужками:

    for ( i = 0; i < M; i++)
        if (r[i] != 0)
        {
            for (j = 0; j < N; j++)
            {
                b[k][j] = a[i][j];
                k++;
            }
        }

Без дужок:

    for ( i = 0; i < M; i++)
        if (r[i] != 0)
        {
            for (j = 0; j < N; j++)
                b[k][j] = a[i][j];
            k++;
        }

Тепер бачите, в чому відмінність?
Якби ви ще назвали змінні не i,j,k, а, скажімо, row_a, col, row_b, то все б стало взагалі зрозуміло.

17

Re: Динамічна пам'ять і матриці

#include <iostream>
#include <vector>
#include <random>
#include <algorithm>

int main() {
    
    const int WIDTH  = 3;
    const int HEIGHT = 10;
    
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 9);
    
    std::vector<std::vector<int>> array(HEIGHT);
    
    std::cout << "Array 10x3:" << '\n';
    for(auto & line : array) {
        line.resize(WIDTH);
        for(auto & element: line) {
            element = dis(gen);
            std::cout << element << '\t';
        }
        std::cout<<'\n';
    }
    
    std::vector<std::vector<int> *> result;
    for(auto & line : array)
        if( std::find( std::begin(line), std::end(line), 2) != std::end(line) )
            result.push_back(&line);
    
    std::cout << "Resulting array:" << '\n';
    for(auto & line : result) {
        for(auto & element: *line)
            std::cout << element << '\t';
        std::cout<<'\n';
    }    
    
    return 0;
}