2016-01-10 2 views
2

Почему этот код для вычисления скалярного произведения двух векторов дает двойную свободную или коррупционную ошибку при компиляции с:Почему этот код C дает двойную свободу или коррупцию?

[email protected]:~/Dropbox/HPC-Practices$ gcc --version 
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 

код приходит от this reference.

// Computation of the inner product of vectors aa and bb. 

#include <stdio.h> 
#include <stdlib.h> 

int main() { 

    size_t nn = 100000000; 
    size_t total_mem_array = nn*sizeof(double); 

    double *aa; 
    double *bb; 
    double ss = 0.0; 

    aa = (double *) malloc(total_mem_array); 
    bb = (double *) malloc(total_mem_array); 

    int ii = 0; 

    for (ii = 0; ii < nn; ++ii) { 
    aa[ii] = 1.0; 
    bb[ii] = 1.0; 
    } 

    double sum1 = 0.0; 
    double sum2 = 0.0; 

    for (ii = 0; ii < nn/2 - 1; ++ii) { 
    sum1 += (*(aa + 0))*(*(bb + 0)); 
    sum2 += (*(aa + 1))*(*(bb + 1)); 
    aa += 2; 
    bb += 2; 
    } 
    ss = sum1 + sum2; 

    free(aa); 
    free(bb); 

    return 0; 
} 
+3

Как только вы сделаете aa + = ... ваш вызов free() не получит указатель, возвращаемый malloc(). То же самое для bb. –

+4

Возможное дублирование https://stackoverflow.com/questions/5414549/c-free-routine-and-incremented-array-pointers –

ответ

6

ошибка вызвана тем, что значение, передаваемое free() не то же самое значение, возвращаемое malloc(), как вы увеличиваете aa и bb.

Чтобы исправить это, вы можете, например, определить две дополнительные переменные указателя, которые используются только для управления памятью, то есть для распределения и освобождения. Когда память будет приобретена ими, назначьте ее aa и bb.

+2

Еще лучше сделать однократный вызов malloc и один бесплатный вызов. Память для aa и bb может находиться в одном блоке. Это микро-оптимизация, но она может улучшить память и будет на два меньше вызовов библиотеки. –

0

Вы можете упростить:

for (ii = 0; ii < nn/2 - 1; ++ii) { 
    sum1 += (*(aa + 0))*(*(bb + 0)); 
    sum2 += (*(aa + 1))*(*(bb + 1)); 
    aa += 2; 
    bb += 2; 
} 

к:

for (ii = 0; ii < nn/2 - 1; ++ii) { 
    sum1 += aa[ii * 2]  * bb[ii * 2]; 
    sum2 += aa[ii * 2 + 1] * bb[ii * 2 + 1]; 
} 

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

+1

Чтобы сделать симметрию еще более ясной, я бы, вероятно, использовал 'sum0 + = aa [ii * 2 + 0] * bb [ii * 2+ 0]; sum1 + = aa [ii * 2 + 1] * bb [ii * 2 + 1]; 'зная, что даже самый тупой компилятор с отключенной оптимизацией вряд ли фактически добавит 0. Обратите внимание на переименование переменных суммы. –