Вопрос по c – определить функцию, возвращающую указатель структуры

11

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

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, ruby), почему он определяет его как

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

не

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

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

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

так,struct Person *Person_create такой же какstruct Person * Person_create, а такжеstruct Person* Person_create? * позиция не имеет значения? allenhwkim
да, пробелы вокруг* здесь не важно Will Ness
@bighostkimAstericks and Pointers Mahesh
Понять разницу междуPerson * а такжеPerson. Person * указатель на объект в то время какPerson это сам объект. Оба разных типа, как, какint * а такжеint отличаются. Mahesh

Ваш Ответ

5   ответов
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

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

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

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

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

2

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

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

3

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

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

1

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

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

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

Похожие вопросы