2015-06-03 2 views
3

Я хочу знать, является ли указатель возврата из функции C хорошим/плохим? Если это плохая практика, что было бы хорошая практика в следующем примере:указатель возврата от функции C хороший/плохой дизайн?

вопросом является продолжением части: c function return static variable

в data.h файл:

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

typedef struct 
{ 
    int age; 
    int number; 
} person; 

person * getPersonInfo(); 

в data.c

#include "data.h" 
static struct person* person_p = NULL; 

person * getPersonInfo() 
{ 
    person_p = (struct person*)malloc(10 * sizeof(struct person)); 
    return person_p; 
} 

в main.c

#include "data.h" 

int main() 
{ 
    person* pointer = getPersonInfo(); 
    return 0; 
} 

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

+4

Если у вас есть функция, выполняющая 'malloc', вы также должны иметь функцию соответствия' free() ', даже если это всего лишь оболочка. Плохой дизайн - называть 'free (pointer)' в вашем 'main' - который вы не делаете в примере, тем самым утечка памяти ... kinda. – mtijanic

+7

Стандартное предупреждение: Пожалуйста, [не использовать] (http://stackoverflow.com/q/605845/2173917) возвращаемое значение 'malloc()' и family в 'C'. –

+1

'malloc' возвращает указатель и является большой частью стандартной библиотеки. Как вы думаете? – Eregrith

ответ

3

Единственная причина, по которой это плохо, потому что у вас нет структуры управления памятью. В вашем текущем коде у вас есть утечка памяти, потому что вы выделяете структуру person через malloc(), но не освобождаете ее.

Рассмотрим написание функцию-оболочку, которая обрабатывает, что управление памятью для вас, как так:

void freePerson(struct person * personToDelete) 
{ 
    free(personToDelete); 
} 

Затем в главном:

int main() 
{ 
    person* pointer = getPersonInfo(); 
    freePerson(pointer); // After you are done using it 
    return 0; 
} 

я также должен предостеречь от литья результаты malloc(). По моему опыту это может привести к неопределенному поведению.

+0

Как выглядит обертка, я не знаю об этом – ratzip

+0

Это не обязательно плохо - это просто переносит ответственность за освобождение выделенной памяти вызывающему абоненту –

+1

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

0

Это вопрос решения больше, чем все остальное.

Оба варианта является действительным до тех пор, пока вы в курсе каждых профи и против

возвращающей указатель плюсы:

  1. инкапсуляции распределения памяти динамических размеров памяти
  2. Поддержки на лета

Возврат указателя минус:

  1. только один возможный из параметров
  2. Память должна быть выделена в куче каждый раз, когда

принимая указатель, как входные профи как раз наоборот:

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

Принимая указатель в качестве входных минусов:

  1. Нет инкапсуляция выделения памяти
  2. Нет поддержки динамических размеров памяти на лета - размеры должны быть фиксированными или заранее оговоренного

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

+0

Что такое инкапсуляция, которую вы имеете в виду, это в C – ratzip

+0

Инкапсуляция - это термин, не относящийся к ООП - вы инкапсулируете выделение памяти в функции, которую вы используете для ее вычисления. –

+0

«только один возможный параметр out» Err ... no? C имеет указатели. Передача параметров указателями - это ежедневное программирование на языке C. Указатели-указатели существуют в значительной степени для единственной причины возврата динамической памяти через параметр. «Память должна распределяться в куче каждый раз». Нет, вы можете писать пулы статической памяти или использовать alloca или аналогичные. И там, где выделена память, на самом деле не связано с дизайном программы. – Lundin

0

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

1

Плохая практика - вернуть указатели на частные переменные. Кроме того, при существующем дизайне ваш .c файл может иметь только один экземпляр объекта person.

И почти необязательно сказать, что тот же код, который динамически выделяет объект, должен также нести ответственность за его освобождение. Код, который написан так, что какой-либо другой модуль в программе, как ожидается, очищает беспорядок, всегда заканчивается утечками памяти для каждого проекта.

Если вы пишете, по крайней мере, несколько сложный тип данных, где вам нужно ограничить доступ к закрытым переменным, у вас есть несколько экземпляров структуры и т. Д., Тогда лучше использовать вместо этого «непрозрачный тип». Пример (не тестировалось):

// data.h

#ifndef DATA_H 
#define DATA_H 

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

typedef struct person person; // opaque type 

person* person_create (void); 

void person_delete (person* p); 

void person_set_age (person* p, int age); 
int person_get_age (const person* p); 
// ... and so on, setters/getters 

#endif // DATA_H 

// данные.с

#include "data.h" 

struct 
{ 
    int age; 
    int number; 
} person;  


person* person_create (void) 
{ 
    return malloc(sizeof(struct person)); 
} 

void person_delete (person* p) 
{ 
    free(p); 
} 

void person_set_age (person* p, int age) 
{ 
    p->age = age; 
} 

int person_get_age (const person* p) 
{ 
    return p->age; 
} 

// Вызывающий:

#include "data.h" 

int main() 
{ 
    person* p = person_create(); 

    person_set_age(p, 50); 
    printf("%d", person_get_age(p)); 

    person_delete(p); 
    return 0; 
} 

Некоторые вещи, чтобы рассмотреть следующие вопросы:

  • Всегда используйте защитные заголовочные в час файлов.
  • Никогда не используйте пустой список параметров () для функций C (но всегда в C++).
  • Не отбрасывайте результат malloc в C (но всегда делайте это на C++).
  • В случае, если malloc не работает, должна быть добавлена ​​некоторая обработка ошибок.
+0

, data.c используется для хранения всех данных, необходимых программе, а затем основная функция в основном файле будет извлекать необходимые данные из файла data.c, в вашем примере выглядит данные хранятся в файле вызывающего абонента? А как насчет того, является ли человек массивом? – ratzip

+0

@ratzip При таком подходе все выделяется файлом data.c, и только этот файл знает, что с ним делать. Фактические данные хранятся в куче ... не в файле. Если вам нужен массив, просто 'person * p [n];' и вызовите функцию create в цикле. – Lundin

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