2014-12-31 4 views
0

Я пытаюсь реализовать быстрый способ применения силовой работы на матрице в C++ (O (logn)). Поэтому у меня было определить умножение и электропитанию, как вы можете увидеть нижеУтечка памяти C++ в рекурсии

int ** matrixmul(int ** A, int ** B, int n) { 
    int ** result = (int **) calloc(sizeof(int *), n); 
    for (int i = 0; i < n; ++i) 
    result[i] = (int *) calloc(sizeof(int), n); 

    for (int i = 0; i < n; ++i) { 
     for (int j = 0; j < n; ++j) { 
      int sum = 0; 
      for (int k = 0; k < n; ++k) { 
       sum += A[i][k] * B[k][j]; 
      } 
      result[i][j] = sum; 
     } 
    } 
    return result; 
} 

int ** matrixpow(int ** m, int n, int p) { 
    if (p == 1) { 
     return m; 
    } else if (p % 2 == 0) { 
     return matrixmul(matrixpow(m, n, p/2), matrixpow(m, n, p/2), n); 
    } else { 
     return matrixmul(matrixmul(matrixpow(m, n, (p - 1)/2), matrixpow(m, n, (p - 1)/2), n), m, n); 
    } 
} 

Функция matrixmul не является универсальным для умножения матриц, это только для тех квадратов.

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

+4

Считаете ли вы использование 'std :: vector ' over 'int *'? – fredoverflow

+0

'int ** result = (int **) calloc (sizeof (int *), n);' с каждым из этих вызовов вы теряете результирующий указатель предыдущего вызова. Если бы вы решили использовать 'realloc()' и передать результаты распределения в качестве параметра? –

+0

Вы должны создать временные переменные для хранения результатов matirxpow, передать их в 'matrixmul' и освободить их после' matrixmul' в обоих предложениях 'else'. – Kimi

ответ

4

Заменить ** с векторами и избегать использования calloc, таНос, новый и удалить.

std::vector< std::vector<int> > result = .... 

Это устранит проблемы с управлением памятью и вы сможете вернуть векторы по значению в C++ 11.

typedef std::vector< std::vector<int> > Matrix; 

Matrix matrixmul(const Matrix& A, const Matrix& B, int n) { 
    Matrix result(n); 
    for (int i = 0; i < n; ++i) 
    result[i] = std::vector<int>(n); 

    for (int i = 0; i < n; ++i) { 
    for (int j = 0; j < n; ++j) { 
     int sum = 0; 
     for (int k = 0; k < n; ++k) { 
     sum += A[i][k] * B[k][j]; 
     } 
    result[i][j] = sum; 
    } 
    } 
    return result; 
} 
+0

Итак, для избежания потери памяти ваше решение состоит в том, чтобы выделить память в стеке, а не в кучу, чтобы память была освобождена после выполнения программы, когда деструктор будет вызван по умолчанию? Надеюсь, у меня все получилось. Спасибо;) – gabyk00

+1

Ни один вектор не выделяет память на кучу. Это dectructor вектора, который удаляет эту память. Проверьте, что RAII (ресурс aquisiton является инициализацией), как переносить манекен памяти в классе. Векторный класс просто управляет этим автоматическим способом. –

+0

Но есть еще. Когда вы возвращаете то, что происходит, это то, что указатель на память просто перемещается без копирования данных из-за ссылок на lvalue. –

1

Если вы хотите продолжать использовать int** по какой-то причине, вы можете также сделать свою программу обрабатывать бесплатно должным образом освободив A и B до возвращения результата в matrixmult. Скорее всего, это переменные, которые просачиваются, как только выполняется matrixmult, вы теряете способность ссылаться на них когда-либо снова. Вы можете освободить эту память довольно легко, так как все имеет размер п по всему вас код:

for(int i = 0 ; i < n ; i++) { 
    for(int j = 0 ; j < n ; j++) { 
     free(A[i][j]); 
     free(B[i][j]); 
    } 
    free(A[i]); 
    free(B[i]); 
} 

Кроме того, эта строка кода кажется странным:

int ** result = (int **) calloc(sizeof(int *), n); 

Первый параметр calloc должно быть число элементов вы хотите, а второй должен быть размером. Я считаю, что это должно быть

int ** result = (int **) calloc(n, sizeof(int *)); 
+0

Я бы также рекомендовал использовать C + + новый/удалить метод управления памятью вместо C malloc/free, если это вообще возможно. Он на самом деле является типичным и будет давать более значимые ошибки (на самом деле выдает ошибку, а не просто тихо возвращается null). Если вы собираетесь использовать C++, зайдите все! –

+0

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

+0

@RubixRechvin Тем не менее, будет потеряна память, оставшаяся от вашего soluiton.Подумайте, что происходит с ранее выделенным блоком, когда функция называется рекурсивно. –