2014-01-13 2 views
1

Я изучаю C и меня интересует подход «лучшей практики» к написанию функций. Желательно ли возвращать указатель на динамически создаваемую память или заполнять блок памяти, который был статически распределен?Каковы последствия возврата указателя в качестве противопоставления заполнению параметра?

Пожалуйста, рассмотрим функции allocatef и populatef в качестве примера

char* allocatef(size_t size){ 
    char* result = malloc(8*size); 
    // do other stuff 
    return result; 
} 

, который мы можем взаимодействовать, через main следующим образом

int main(void){ 
    char* data = allocatef(sizeof(int)); 
    // do stuff 
    free(data); 
} 

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

void populatef(char* data){ 
    // do stuff 
} 

и память статически распределена в main, что избавляет нас от потенциальной утечки памяти. Возможно, одним из недостатков является то, что вызывающий абонент должен знать точный тип ввода populatef.

int main(void){ 
    char data[8 * sizeof(int)]; 
    populatef(data); 
    // no need to perform a destroy 
} 

Я нашел некоторые важные вопросы here и here, но эти опасения C++ и производительности соображений. Меня больше интересует безопасность памяти и стандартное поведение среди опытных программистов С.

+0

В C? Это подразумевает, что теперь есть проблемы с владением, о которых нужно беспокоиться. : P – cHao

+0

Пожалуйста, объясните подробнее. – jesterII

+1

Ваше решение будет принято. –

ответ

0

С точки зрения безопасности памяти нет ответа «лучшей практики», который лучше всего подходит для каждой ситуации. Вся суть написания на C заключается в том, что вы можете выбрать, как управлять своей памятью, а не делать это одинаково все время.

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

//functions exported from module A 
struct Data * allocate_data(); 
void initialize_data(Data *); 
void deinitialize_data(Data *); 
void deallocate_data(Data *); 

//module B: 
int main(void){ 
    Data * allocate_data(); 
    initialize_data(data); 
    //do stuff 
    deinitialize_data(data); 
    deallocate_data(data); 
} 

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

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

Чтобы перейти ко второй версии, это просто вопрос о том, чтобы структура данных была частью открытого интерфейса. Преимущество заключается в том, что код вызывающего абонента выделяет эту структуру в стеке rn статически, а недостатком является то, что если вызывающий абонент отвечает за всю логику распределения (например, убедитесь, что размер массива выделенной памяти одинаковый размер массива передается функции инициализации).

Мы могли бы обеспечить соблюдение этого, делая пустой struct Data; заявления в заголовке Data.h и в том числе фактического struct Data { char * payload; } заявления в файле Data.c.

+0

Это отличный ответ с практическим примером. Возможно, будучи наивным программистом на Java/Python, гибкость C для меня несколько необычна. – jesterII

+0

Хотя в случае Python он также может быть подобным образом гибким, поскольку «новый» и «init» являются отдельными методами. :) – hugomg

Смежные вопросы