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

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

03.08.2011, 17:13. Просмотров 2396. Ответов 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
Изображения
 
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.08.2011, 17:13
Ответы с готовыми решениями:

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

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

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

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

23
1195 / 822 / 180
Регистрация: 16.03.2008
Сообщений: 3,950
Записей в блоге: 1
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
929 / 754 / 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
1195 / 822 / 180
Регистрация: 16.03.2008
Сообщений: 3,950
Записей в блоге: 1
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
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
1195 / 822 / 180
Регистрация: 16.03.2008
Сообщений: 3,950
Записей в блоге: 1
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
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
1195 / 822 / 180
Регистрация: 16.03.2008
Сообщений: 3,950
Записей в блоге: 1
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
3 / 4 / 1
Регистрация: 13.07.2011
Сообщений: 313
04.08.2011, 14:26 11
Ну так ведь я не прошу вывести то очищенную строчку.. я просто проверяю - если пустая, то не печатаю...
Разве это неправильно?
0
1195 / 822 / 180
Регистрация: 16.03.2008
Сообщений: 3,950
Записей в блоге: 1
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
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
1195 / 822 / 180
Регистрация: 16.03.2008
Сообщений: 3,950
Записей в блоге: 1
04.08.2011, 15:16 14
1 Если "доковыривать" твой код. То удалять строку нет необходимости. Достаточно в первом элементе текущей строки поставить 0. И потом при записи в файл проверять это условие. Это будет пошустрее
2. Как удалять столбик, что то не придумывается в таком варианте. только по штучно

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

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

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

Добавлено через 11 минут
Как бы то ни было в итоге мы все равно получаем по элементное копирование одного массива в другой. ТС предложил неплохой вариант. Массив остается прежний, но копирование происходит только при наличии 0 в диагонали. При чем копирование производим кусками памяти.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.08.2011, 17:13

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

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

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

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

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

Скотт Мейерс устал от С++
http://scottmeyers.blogspot.ru/2015/12/good-to-go.html Кто-нибудь хочет последовать его примеру?...

Устал уже от BSOD
Всем привет, помоги разобраться.. BSOD выкидывает каждый день. За частую при нагруженной работе, и...


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

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

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