Каков наилучший способ разрушить структуру в C
В C++ у нас есть структуры, в которых есть конструктор и деструктор. Это значительно облегчает жизнь, особенно когда она имеет указатели, поэтому динамически распределяет память в структуре. Вы даже можете использовать библиотеку std::shared_pointer для работы с указателями.
class A{
private:
int size;
double* stack;
public:
A(int size) : this->size(size){}
~A(){free(stack);}
};
Но мой лектор по математике не любит C++ и предпочитает все на C. Поэтому мне пришлось использовать C вместо этого и придумал следующую структуру:
typedef struct vectorOfDoubles{
double* stack;
int size;
} vector;
Я составил функцию, которая вычисляет медиану вектора двойников.
double median_(const vector* v) {
vector n; // creates vector class object
n.stack = (double*)malloc(sizeof(double)*(n.size = v->size)); // takes double ptr and allocates the right amount of memory for it
memcpy(n.stack, v->stack, sizeof(double)*n.size); // copies the array of doubles.
sort(&n); // sorts the array of doubles
if(v->size%2) // checks for odd size
return n.stack[(v->size/2+1)]; // return median for odd size
else
return (n.stack[(v->size/2)]+n.stack[(v->size/2+1)])/2; // return median for even size
}
В качестве примера плохих практик я не освободил память. Когда функция возвращает свое значение, она разрушает локальные переменные и структуры. Но моя структура имеет указатель, который содержит выделенную память. Вряд ли после некоторого исследования в интернете я не нашел ни одного хорошего метода разрушения для этих ситуаций.
Мой вопрос заключается в том, как старомодные программисты на Си имели дело с такими ситуациями, когда они хотят освободить указатели в структуре, но у них нет деструктора для структуры, который выполнялся бы для выполнения определенной работы?
3 ответа
Простой указатель нуждается в *alloc()
и, наконец, free()
,
Структура с динамическими полями заслуживает vector_alloc()
а также vector_free()
,
Старый школьный ароматизированный результат:
// Return non-0 on error
int vector_alloc(vector *ptr, size_t size) {
assert(ptr);
ptr->stack = calloc(size, sizeof *(ptr->stack));
if (ptr->stack) {
ptr->size = size;
return 0;
}
ptr->size = 0;
return 1;
}
void vector_free(vector *ptr) {
assert(ptr);
free(ptr->stack);
ptr->stack = NULL;
ptr->size = 0;
}
double median_(const vector* v) {
vector n;
if (vector_alloc(&n, v->size)) return 0.0/0.0;
memcpy(n, v->stack, sizeof *n->stack *n.size);
sort(&n);
double y;
if(v->size%2)
y = n.stack[(v->size/2+1)];
else
y = (n.stack[(v->size/2)]+n.stack[(v->size/2+1)])/2;
vector_free(&n);
return y;
}
Если вы хотите освободить объект, который использует какое-то иерархическое хранилище (то есть внутренние указатели на другой объект) в C, я обычно пишу свободную функцию, специфичную для этого объекта. Например:
void free_my_obj(my_obj_t *my_obj)
{
free(my_obj->a);
free_my_obj2(my_obj->my_obj2);
free(my_obj);
}
В начале: n.stack=…malloc();
В конце: free(n.stack);
Каждый malloc() в начале блока должен иметь соответствующий free(); ближний конец блока