Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.75/12: Рейтинг темы: голосов - 12, средняя оценка - 4.75
-=ЮрА=-
Заблокирован
Автор FAQ
1

Устал искать баг

03.08.2011, 17:13. Просмотров 2230. Ответов 23
Метки нет (Все метки)

Проблемма проста - нужно удалить из вещественной матрицы строку и столбец, верней ряд строк и столбцов (условие - нулевой элемент на главной диагонале, даже привожу рисунок)

Пропускаю матрицу А и вектор свободных членов В через вот такой фильтр
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() указывает на одни и теже строки и столбцы, проверка элементов матрицы показала отсутсвие ошибок. А и В созданы и инициализированы правильно!
Суть задачи - где в моём коде просчёт?Готов к другим вариантам удаления строк и столбцов, жду...
0
Изображения
 
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.08.2011, 17:13
Ответы с готовыми решениями:

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

Устал от утечек памяти
С этими утечками памяти в C++ просто беда. Посоветуйте, что можно сделать? Может быть есть какие-то...

std::regex : баг на сайте или баг компилятора?
http://en.cppreference.com/w/cpp/regex/regex_match этот код выкидывает throw... Добавлено через...

Ошибка в коде (очень устал искать)
Уже несколько раз проходил отладкой, не пойму, в чём ошибка. Часа 2-3 бьюсь. Задание: Выделить...

MS Access - УСТАЛ УЖЕ ИСКАТЬ ПРИЧИНУ СВОЕЙ ОШИБКИ
как сделать поля с выбором варианта?.. например пол- выбрать &quot;м&quot; или &quot;ж&quot; тип данных ставлю...

23
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
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;
т.к. еперь на этом месте еще не проверенный элеент
0
xAtom
922 / 747 / 299
Регистрация: 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;
}
1
-=ЮрА=-
Заблокирован
Автор FAQ
03.08.2011, 20:17  [ТС] 4
Ты хочешь сказать что memcpy (move, не важно какая из них) работала не со строкой, а со всем оставшимся массивом???
0
03.08.2011, 20:17
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
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) смещались причем с заходом на другую строку.....
1
-=ЮрА=-
Заблокирован
Автор FAQ
04.08.2011, 09:16  [ТС] 6
Матрица размером 4000х4000, поэтому и не могу дебагом нормально что-то выловить...
0
Stas0n
3 / 4 / 1
Регистрация: 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;
        }
    }
Т.е. мы просто не выводим пустые строчки....
Вроде неплохая идея(это намного производительней, чем сдвигать строчки\столбцы), а вот реализация хромает.. падает прога
0
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
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) может оказаться все, что угодно.....
0
Stas0n
3 / 4 / 1
Регистрация: 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;
}
0
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
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 который занимает несколько байт в памяти, а на его месте
//переменный типа чар в один байт... :)
0
Stas0n
3 / 4 / 1
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 14:26 11
Ну так ведь я не прошу вывести то очищенную строчку.. я просто проверяю - если пустая, то не печатаю...
Разве это неправильно?
0
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
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 Посмотреть сообщение
Ну так ведь я не прошу вывести то очищенную строчку.. я просто проверяю - если пустая, то не печатаю... Разве это неправильно?
В какой строке проверка?
0
Stas0n
3 / 4 / 1
Регистрация: 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;
        }
    }
Может подскажешь, как столбец удалить?
0
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
04.08.2011, 15:16 14
1 Если "доковыривать" твой код. То удалять строку нет необходимости. Достаточно в первом элементе текущей строки поставить 0. И потом при записи в файл проверять это условие. Это будет пошустрее
2. Как удалять столбик, что то не придумывается в таком варианте. только по штучно

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

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

Добавлено через 1 минуту
Это условие
C++
1
matrix[i][i]!=NULL
не будет работать
0
Stas0n
3 / 4 / 1
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 16:33 15
Нельзя ставить ноль... Ноль в матрице так же может быть элементом.
0
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
04.08.2011, 16:39 16
да да. я и сказал об этом
0
Stas0n
3 / 4 / 1
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 16:43 17
Вот так и получается, что код не ахти какой((
0
Deviaphan
Делаю внезапно и красиво
Эксперт С++
1307 / 1222 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
04.08.2011, 16:43 18
Можно вообще не удалять ни столбцы, ни строки. Сохранить список "нулевых" индексов и пропускать их при записи в файл. Если дополнительной никакой работы не будет над матрицей происходить после "удаления" строк/столбцов, то это самый эффективный вариант.
0
Stas0n
3 / 4 / 1
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 16:54 19
?????
0
voral
966 / 660 / 147
Регистрация: 16.03.2008
Сообщений: 3,173
04.08.2011, 17:13 20
Создаешь еще одну матрицу такого же размера. Заполняешь, например, 1цами. Пройтись по диагонали основной матрицы. А в вспомогательной проставлять 0 в тех элементах, которые должны быть удалены). Потом формируешь результирующую матрицу на основании первых двух.

Добавлено через 11 минут
Как бы то ни было в итоге мы все равно получаем по элементное копирование одного массива в другой. ТС предложил неплохой вариант. Массив остается прежний, но копирование происходит только при наличии 0 в диагонали. При чем копирование производим кусками памяти.
0
04.08.2011, 17:13
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.08.2011, 17:13

Подскажите где искать и что искать
Необходимо реализовать простенький на мой взгляд скрипт. Он должен выполнять следующее: Зашел...

Я устал ждать
Ребята, вот я пишу код ну написал 5 строк нажал на кнопку start или debag и жду сижу блин...

Яша устал?
Такая проблема... Часов в 11 вечера любимый 1ГБ сказал что база сильно грузит сервер SQL и рубанул...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru