ANSI C вы должны использовать malloc () при создании структуры? - PullRequest
15 голосов
/ 05 октября 2011

Допустим, у меня есть это struct в ANSI C:

typedef struct _point
{
    float x;
    float y;
} Point;

и эта функция для создания этого struct:

Point createpoint(float x, float y)
{
    Point p;
    p.x = x;
    p.y = y;
    return p; 
}

Это позволяет мне создать struct с помощью этой функции, т. Е.

int main()
{
    Point pointOne = createpoint(5, 6);  
    Point pointTwo = createpoint(10, 4);
    float distance = calculatedistancefunc(pointOne, pointTwo);

    /* ...other stuff */

    return 0;
}

Кто-то сказал мне, что этот код недействителен, потому что struct не получает malloc 'd в функции createpoint(float x, float y), прежде чем он будет возвращен, и что struct будет удален. Однако, когда я использую свой struct таким образом, он, похоже, не удаляется.

Итак, мой вопрос: я должен malloc это struct, и почему? / почему нет?

Ответы [ 5 ]

14 голосов
/ 05 октября 2011

Все, что вы делаете, совершенно правильно.Оператор -

return p;

в функции возвращает копию локальной переменной p.Но если вам нужен тот же объект, который был создан в функции, то вам нужно malloc его.Однако вам нужно free позже.

Point createpoint(float x, float y)
{
    Point p;
    p.x = x;
    p.y = y;
    return p; 
} // p is no longer valid from this point. So, what you are returning is a copy of it.

Но -

Point* createpoint(float x, float y)
{
    Point *p = malloc(sizeof(Point));
    p->x = x;
    p->y = y;
    return p; 
}// Now you return the object that p is pointing to.
7 голосов
/ 05 октября 2011

Вы можете вернуть struct в стек, ваш код действителен. Проблема может возникнуть, если вы вернете указатель на локальную переменную, но это не то, что вы делаете, вы возвращаете копию, это нормально.

5 голосов
/ 05 октября 2011

C99 позволяет еще лучше создавать структуры в стеке.Учитывая приведенную ниже структуру

typedef struct
{
    float x;
    float y;
} Point;

, вы можете инициализировать ее в стиле конструктора C ++ с помощью следующего оператора:

Point p = (Point){0.4, 0.5};

, и, таким образом, вы можете сократить точку создания или запискуэто всего:

int main()
{
    Point pointOne = (Point){5, 6};
    Point pointTwo = (Point){10, 4};
    float distance = calculatedistancefunc(pointOne, pointTwo);
    //...other stuff
    return 0;
}
3 голосов
/ 05 октября 2011
Point createpoint(float x, float y)
{
    Point p;
    p.x = x;
    p.y = y;
    return p; 
} /

Все локальные переменные в функции удалены. after Функция возвращает.

1> передать по ссылке Так что если вы возвращаете указатель на эту локальную переменную, то после возврата функции эти переменные удаляются, так что указатели становятся недействительными.

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

0 голосов
/ 16 января 2014

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

StructType BuildStruct(void)
{
  StructType it;
  it.this=4;
  it.that=23;
  return it;
}

StructType myStruct;
myStruct = BuildStruct();

вполне вероятно, что будет хотя бы одна операция копирования, если не две; оператору return it; может потребоваться скопировать из локальной переменной it во временную структуру, а присвоение myStruct может потребоваться для копирования из временного расположения в myStruct. На самом деле ни одна ситуация не требует двух операций копирования; некоторые требуют один (который может быть выполнен вызывающим или вызываемым методом), а некоторые - нет, но необходимость копирования зависит от деталей как в вызывающем, так и в вызываемом методе.

Альтернативный дизайн будет:

void BuildStruct(StructType *it)
{
  it->this=4;
  it->that=23;
}

StructType myStruct;
BuildStruct(&myStruct);

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

...