Форум программистов, компьютерный форум CyberForum.ru

Устал искать баг - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.65
-=ЮрА=-
Заблокирован
Автор FAQ
03.08.2011, 17:13     Устал искать баг #1
Проблемма проста - нужно удалить из вещественной матрицы строку и столбец, верней ряд строк и столбцов (условие - нулевой элемент на главной диагонале, даже привожу рисунок)

Пропускаю матрицу А и вектор свободных членов В через вот такой фильтр
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void compress(int m, double **a, double *b)
{
    for(int i = 0,j; i < m; i++)
    {
        if(a[i][i] == 0)
        {
            for(j = i; j < m - 1; j++)
                memcpy((void *)&a[j],(void *)&a[j + 1],m);
            for(j = 0; j < m; j++)
                a[j] = compress(m, i, a[j]);
            b = compress(m, i, b);
        }
    }
}
 
double * compress(int m, int i, double * vec)
{
    memcpy((void *)&vec[i],(void *)&vec[i + 1],m - (i + 1));
    return vec;
}
Всё время вылетает ошибка, try{}catch() указывает на одни и теже строки и столбцы, проверка элементов матрицы показала отсутсвие ошибок. А и В созданы и инициализированы правильно!
Суть задачи - где в моём коде просчёт?Готов к другим вариантам удаления строк и столбцов, жду...
Изображения
 
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
03.08.2011, 18:11     Устал искать баг #2
Как вариант:
1. Обходим матрицу. Двигаемся только по диагонали. Если встречаем 0. Уменьшаем счетчик столбцов/строк
2. Выделяем память под новую матрицу с размерами согласно текущему полученному счетчику строк/столбцов
3. Опять идем по матрице (по диагонали) и копируем во вторую только то, что нужно (т.е. если элемент в диагонали не равен 0)

Добавлено через 1 минуту
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
for(int i = 0,j; i < m; i++)
j -здесь зачем?

Добавлено через 6 минут
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
C++
1
2
for(j = i; j < m - 1; j++) 
memcpy((void *)&a[j],(void *)&a[j + 1],m);
Здесь, как я понял, вы сдивгаете строку. Т.е. согласно рисунку 5 ячеек начина с ячейки со значением "8".. Т.е. на последней строке вы вылетаете за пределы. К томуже еще перебиваете первые ячеки следующей строки (если текущая не последняя)

Добавлено через 4 минуты
К тому же у вас m не изменяется, а элементы сдвигаются

Добавлено через 8 минут
C++
1
for(j = 0; j < m; j++)
Тут тоже вроде нужно не до m, а до i

Добавлено через 10 минут
Стоп. у вас же double..... А последний параметр memcpy размер в байтах. нет?

Добавлено через 6 минут
Не проверял. Но вроде так. (Это как я понял ваш алгоритм только без memcpy). Но нужно еще освободить память. Или просто возвращать новый размер
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void compress(int m, double **a, double *b)
{
    for(int i = 0,j; i < m; i++)
    {
        if(a[i][i] == 0)
        {
            for(j = i; j < m - 1; ++j)
                for(k=0;k<m;++k)
                    a[j][k]=a[j+1][k];
            for(j = i; j < m - 1; ++j)
                for(k=0;k<m;++k)
                    a[j][k]=a[j][k+1];
            --m;
        }
    }
}
Добавлено через 1 минуту
Ах да. Наверно надо в 15 строку вставить
C++
1
--i;
т.к. еперь на этом месте еще не проверенный элеент
xAtom
 Аватар для xAtom
910 / 735 / 60
Регистрация: 09.12.2010
Сообщений: 1,346
Записей в блоге: 1
03.08.2011, 20:14     Устал искать баг #3
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
memcpy((void *)&vec[i],(void *)&vec[i + 1],m - (i + 1));
Видишь как получается ты указываешь только количество элементов массива, но функции memcpy, memccpy, memcmp, memmove и так далее, работают не с массивом а буфером, то есть нужно указывать полный размер данных. Вот написал код по твоей задаче

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
using namespace std;
 
 
void cross_remove(double** mat, int& size) {
    int  r;
    for(int i = 0; i < size; i++) {
        if( mat[i][i] == 0.0 ) {
        
          for(r = i; r < size - 1; r++) 
              memcpy(*((mat) + r), *((mat) + r + 1), sizeof(double) * size);
 
          for(r = 0; r < size; r++) 
              memcpy( *((mat) + r) + i,  *((mat) + r) + i + 1, (size - (i + 1)) * sizeof(double));
 
          size -= 1;
          cross_remove(mat, size);
        } 
    }
}
 
 
int main(void) {
 
   const int N = 4;
   int r, c;
 
   double** arr = new double*[N];
   for(int n = 0; n < N; n++)
        *((arr) + n) = new double[N];
 
   // статическая матрица для примера будет служить
   double   mat[N][N] = {
        {  0.0,    3.5,        40.5 ,   5.8 },
        {  2.4,     5.5,       23.5,    7.8 },
        {   9.4,     4.5,      0.0,      1.8 },
        {   8.4,     8.5,      23.5,    3.3 }
   };
 
   // с копировать её в динамическую матрицу
   for(r = 0; r < N; r++)
        memcpy(arr[r],  mat[r], sizeof(double) * N);
 
 
   int size  = N;  // переменная нужна для возвращения размера матрицы
   cross_remove((double**)arr, size);
 
   for(r = 0; r < size; r++) {
     for(c = 0; c < size; c++)
        cout << arr[r][c] << '\t';
     cout.put('\n');
   }
 
   for(r = 0; r < N; r++) {
       delete[] *((arr) + r);
       *((arr) + r) = NULL;
   }
   delete[] arr;
   arr = NULL;
 
   cin.get();
   return 0;
}
-=ЮрА=-
Заблокирован
Автор FAQ
03.08.2011, 20:17  [ТС]     Устал искать баг #4
Ты хочешь сказать что memcpy (move, не важно какая из них) работала не со строкой, а со всем оставшимся массивом???
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
03.08.2011, 20:49     Устал искать баг #5
Не со всем. Зависит от размера матрицы и платформы. Если размер double - 8 байт. И матрица 8x8 то копировася один следующий элемент. Если размер матрицы 14 то на последнем цикле
a[j][k]=a[j][k+1];
a[j][k+1]= черте что т.к. копировались только 6 байт из 8ми

Добавлено через 3 минуты
Т.е. при размере матрицы меньше 8 копировался кореженный следующий элемент; больше восьми (m/8) смещались причем с заходом на другую строку.....
-=ЮрА=-
Заблокирован
Автор FAQ
04.08.2011, 09:16  [ТС]     Устал искать баг #6
Матрица размером 4000х4000, поэтому и не могу дебагом нормально что-то выловить...
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 13:48     Устал искать баг #7
А что, если просто удалять из массива нужную строчку\ столбец?

Добавлено через 1 час 18 минут
Можно например просто удалить вот так delete[] matrix[i]. Это строку/столбец не удалит - только освободит память, где она лежала. Но все указатели (и место в массиве под нее) останется.
а при выводе можно делать так:
C++
1
2
3
4
5
6
7
8
9
10
    for (int i = 0; i < range-k; i ++)
    {
        if ( matrix[i][i]!=NULL)
        {
            for (int j = 0; j < range-k; j++)
            {
                ofs << matrix[i][j] << " ";
            } ofs << endl;
        }
    }
Т.е. мы просто не выводим пустые строчки....
Вроде неплохая идея(это намного производительней, чем сдвигать строчки\столбцы), а вот реализация хромает.. падает прога
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
04.08.2011, 14:02     Устал искать баг #8
Цитата Сообщение от hello19 Посмотреть сообщение
Можно например просто удалить вот так delete[] matrix[i]. Это строку/столбец не удалит - только освободит память, где она лежала. Но все указатели (и место в массиве под нее) останется.
каким образом это освободит память занимаемую столбцом?
Далее если предположить, что так можно освободить память, почему вы думаете, что там будет NULL?

Давайте рассмотрим пример. Для упрощения одномерный массив
C++
1
2
3
4
5
int *test = new test[6];
// разные действия над массивом
delete[]  test;
// некоторые действия
cout << test[4];
Давайте подумаем, что вернет cout и есть ли гарантия, что там NULL.
что значит test[4] ? Это значит, что у нас есть некая область памяти начинающаяся с адреса А и нам надо получить элемент соответствующего размера со смещением от этого адреса (в байтах) 4*sizeof(int). Но ты уже освободил эту память. И она может быть занята другими переменными. Соответственно по адресу (test+4) может оказаться все, что угодно.....
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 14:09     Устал искать баг #9
Извините, просто не кинул часть кода..
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int main()
{
    int range = 5;
 
    // Allocate  matrix
    double **matrix = new double*[range]();
    for (int i = 0; i < range; i++) 
    {
        matrix[i] = new double[range]();
    }
 
    // reading from file
    ifstream ifs("aa.txt");
    double q;
    int i = 0;
    int j = 0;
    while ( ifs >> q )
    {
        matrix[i][j] = q;
        j++;
        if ( j % range == 0 ) { i++; j = 0;}
    }
    ifs.close();
    // delete nessesary colums and rows
 
    // счетчит количества нулевых строк/столбцов
    int k = 0;
 
    
    for ( int i = 0; i < range; i++ )
    {
        if ( matrix[i][i] == 0 )
        {
            inf << i << endl;
            k++;
            delete matrix[i];
        }
    }
    inf.close();
    // output matrix 2
    ofstream ofs("bb.txt");
    for (int i = 0; i < range-k; i ++)
    {
        for (int j = 0; j < range-k; j++)
        {
            ofs << matrix[i][j] << " ";
        } ofs << endl;
    }
    for ( int i =0; i < range-k; i++)
    delete[] matrix[i];
    delete[] matrix;
}
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
04.08.2011, 14:24     Устал искать баг #10
Ну так сам то внимательно прочитай свой код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
range=3;
// заполняем
arr[0]={1,2,3};
arr[1]={1,2,3};
arr[2]={1,2,3};
// освобождаем
delete[] arr[1];
++k;
//обрати внимание arr[2] не сдвигается в памяти
// водим в цикл вывода марицы в файл
// i от 0 до range-k=3-1=2
ofs << arr[0];
ofs << arr[1]; // упс...... а у нас по этому адресу уже давным давно другая переменная, в то и
 //"несколько переменных типа char". 
// мы ведь хотим прочитать double который занимает несколько байт в памяти, а на его месте
//переменный типа чар в один байт... :)
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 14:26     Устал искать баг #11
Ну так ведь я не прошу вывести то очищенную строчку.. я просто проверяю - если пустая, то не печатаю...
Разве это неправильно?
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
04.08.2011, 14:29     Устал искать баг #12
однако можно так:
C++
1
2
 k++;  delete matrix[i];
 matrix[i]=NULL;
а потом
C++
1
2
if (matrix[i]!=NULL)
   for (int j = 0; j < range; j++)         {             ofs << matrix[i][j] << " ";         }
Но остается не закрытым вопрос удаления столбика

Добавлено через 40 секунд
Цитата Сообщение от hello19 Посмотреть сообщение
Ну так ведь я не прошу вывести то очищенную строчку.. я просто проверяю - если пустая, то не печатаю... Разве это неправильно?
В какой строке проверка?
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 14:56     Устал искать баг #13
Проверка при выводе:
C++
1
2
3
4
5
6
7
8
9
10
    for (int i = 0; i < range-k; i ++)
    {
        if ( matrix[i][i]!=NULL)
        {
            for (int j = 0; j < range-k; j++)
            {
                ofs << matrix[i][j] << " ";
            } ofs << endl;
        }
    }
Может подскажешь, как столбец удалить?
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
04.08.2011, 15:16     Устал искать баг #14
1 Если "доковыривать" твой код. То удалять строку нет необходимости. Достаточно в первом элементе текущей строки поставить 0. И потом при записи в файл проверять это условие. Это будет пошустрее
2. Как удалять столбик, что то не придумывается в таком варианте. только по штучно

Вообще алгоритм ТС (естественно после доработок) мне кажется оптимальным.
Пробегать каждый элемент накладно (в твоем варианте это тоже есть и вмое предложенном во 2 посте)
В моем (заполнение 0-ями) есть подводный камень - может быть реальный 0 не на диагонали

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

Добавлено через 1 минуту
Это условие
C++
1
matrix[i][i]!=NULL
не будет работать
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 16:33     Устал искать баг #15
Нельзя ставить ноль... Ноль в матрице так же может быть элементом.
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
04.08.2011, 16:39     Устал искать баг #16
да да. я и сказал об этом
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 16:43     Устал искать баг #17
Вот так и получается, что код не ахти какой((
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1284 / 1218 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
04.08.2011, 16:43     Устал искать баг #18
Можно вообще не удалять ни столбцы, ни строки. Сохранить список "нулевых" индексов и пропускать их при записи в файл. Если дополнительной никакой работы не будет над матрицей происходить после "удаления" строк/столбцов, то это самый эффективный вариант.
Stas0n
3 / 4 / 0
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 16:54     Устал искать баг #19
?????
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.08.2011, 17:13     Устал искать баг
Еще ссылки по теме:

Написать программу, которая буде искать и открывать файл. C++
C++ Как искать функции, работающие с определенным типом?
Как искать ответы на вопросы? C++
C++ Как искать ошибку?
Как правильно искать информацию по программированию на c++? C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
voral
361 / 341 / 46
Регистрация: 16.03.2008
Сообщений: 1,735
04.08.2011, 17:13     Устал искать баг #20
Создаешь еще одну матрицу такого же размера. Заполняешь, например, 1цами. Пройтись по диагонали основной матрицы. А в вспомогательной проставлять 0 в тех элементах, которые должны быть удалены). Потом формируешь результирующую матрицу на основании первых двух.

Добавлено через 11 минут
Как бы то ни было в итоге мы все равно получаем по элементное копирование одного массива в другой. ТС предложил неплохой вариант. Массив остается прежний, но копирование происходит только при наличии 0 в диагонали. При чем копирование производим кусками памяти.
Yandex
Объявления
04.08.2011, 17:13     Устал искать баг
Ответ Создать тему
Опции темы

Текущее время: 13:07. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru