2012-05-04 3 views
8

Пожалуйста, медведь со мной, я м от других языков и новичку -с и изучать его из http://c.learncodethehardway.org/book/learn-c-the-hard-way.htmlопределить функцию, возвращающую указатель STRUCT

struct Person { 
    char *name; 
    int age; 
    int height; 
    int weight; 
}; 

struct Person *Person_create(char *name, int age, int height, int weight) 
{ 
    struct Person *who = malloc(sizeof(struct Person)); 
    assert(who != NULL); 

    who->name = strdup(name); 
    who->age = age; 
    who->height = height; 
    who->weight = weight; 

    return who; 
} 

Я понимаю, что вторая функция Person_create возвращает указатель структуры Person. Я не понимаю (может быть, потому что им с другого языка, Erlang, рубин), почему это определить его как

struct Person *Person_create(char *name, int age, int height, int weight) 

не

struct Person Person_create(char *name, int age, int height, int weight) 

и есть другой способ определить функцию вернуть структуру?

извините, если этот вопрос слишком прост.

+0

Понимать разницу между «Лицом *» и «Лицом». 'Person *' является указателем на объект, а 'Person' является самим объектом. Оба типа - это разные типы, например, как 'int *' и 'int' отличаются. – Mahesh

+1

Итак, 'struct Person * Person_create' совпадает с' struct Person * Person_create' и 'struct Person * Person_create'? Позиция '*' не имеет значения? – allenhwkim

+1

Да, пробелы вокруг '*' здесь неважны. –

ответ

11

Он определяется так, потому что он возвращает указатель на структуру, а не на структуру. Вы присваиваете возвращаемое значение struct Person *, а не struct Person.

можно вернуть полный-структуру, как и что:

struct Person Person_create(char *name, int age, int height, int weight) 
{ 
    struct Person who; 
    who.name = strdup(name); 
    who.age = age; 
    who.height = height; 
    who.weight = weight; 
    return who; 
} 

Но он не используется очень часто.

3

Функция возвращает who, что является struct Person * - указателем на структуру. Память для хранения структуры выделяется malloc(), и функция возвращает указатель на эту память.

Если функция объявлялись вернуть struct Person и не указатель, то who также может быть объявлена ​​как структура. По возвращении структура будет скопирована и возвращена вызывающему. Обратите внимание, что копия менее эффективна, чем просто возвращает указатель на память.

2

Структуры не являются указателями (или ссылками) по умолчанию в C/C++, как это, например, в Java. Функция Struct Person() должна возвращать сама структура (по значению, делая копию), а не указатель.

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

1

Чтобы скопировать всю структуру, а не только указатель, менее эффективен, потому что указатель sizeof обычно намного меньше sizeof всей структуры.

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

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

2

Функция Person_create возвращает указатель на struct Person, поэтому вам нужно определить возвращаемое значение как указатель (путем добавления *).Чтобы понять причину возврата указателя на структуру, а не на структуру, нужно понять, как C обрабатывает память.

Когда вы вызываете функцию в C, вы добавляете для нее запись на call stack. В нижней части стека вызовов находится функция main программы, в которой вы работаете, вверху - выполняемая в данный момент функция. Записи в стеке содержат информацию, такую ​​как значения параметров, переданных функциям, и все локальные переменные функций.

Существует еще один тип памяти, к которой у вашей программы к этому доступу относится: куча памяти. Здесь вы выделяете пространство, используя malloc, и оно не подключено к стеку вызовов.

Когда вы возвращаетесь из функции, стек вызовов вызывается и вся информация, связанная с вызовом функции, теряется. Если вы хотите вернуть структуру, у вас есть два варианта: скопируйте данные внутри структуры до того, как она выскочит из стека вызовов, или сохраните данные в кучной памяти и верните указатель на нее. Копировать байт данных для байта более дорого, чем просто вернуть указатель, и, таким образом, вы обычно захотите сделать это для экономии ресурсов (как в памяти, так и в цикле процессора). Тем не менее, это не происходит без затрат; когда вы храните свои данные в памяти кучи, вы должны помнить до free, когда вы прекратите использовать его, иначе ваша программа будет утечка памяти.

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