Подтвердить что ты не робот

Возврат указателя struct

Предположим, что у меня есть следующая структура и функция, возвращающая указатель:

typedef struct {
  int num;
  void *nums;
  int size;
} Mystruct;

Mystruct *mystruct(int num, int size)
{ 
   //Is the following correct? Is there a more efficient way?
   Mystruct mystruct;
   mystruct.num = num;
   mystruct.size = size;
   mystruct.nums = malloc(num*sizeof(size));
   Mystruct *my;
   *my = mystruct;
   return my;
}

Я хочу определить любой указатель Mystruct, используя указанную выше функцию. Должен ли я объявлять переменную Mystruct, определять свойства Mystruct, назначать ему указатель и сразу же возвращать указатель или определять свойства свойства mystruct через указатель?

4b9b3361

Ответ 1

Должен ли я объявлять переменную Mystruct, определить свойства Mystruct, назначьте указатель на него и верните указатель

Определенно нет, поскольку переменная, определенная в функции (в классе "авто" хранения) исчезнет по мере выхода функции, и вы вернете висячий указатель.

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

Mystruct *mystruct(int num, int size)
{
   Mystruct *p = malloc(sizeof(MyStruct));
   ....
   return p;
}

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

Ответ 2

Вы не можете использовать переменную, потому что она будет освобождена при выходе из функции. Например:

Mystruct *mystruct(int num, int size)
{
   MyStruct x;
   x.num = 1;
   ...
   return &x;
}

Дает ошибку сегментации или нарушение доступа, поскольку память для x освобождается, как только вы выходите. Таким образом, вам нужно выделить память для структуры (и обязательно ее освободить позже) или объявить глобальный, который останется навсегда. Пример для последнего...

Mystruct *mystruct(int num, int size)
{
   MyStruct *x;
   x = (MyStruct*)malloc( sizeof( MyStruct ) );
   x->num = 1;
   ...
   return x;
}

Ответ 3

Если вы пишете общий код и не знаете, как его можно использовать, полезно предоставить оба варианта:

int mystructm(Mystruct *storage, int num, int size)
{
    int rv = 0;

    storage->num = num;
    storage->size = size;
    storage->nums = malloc(num*sizeof(size));
    if (!storage->nums)
        return -1;

    return 0;
}

Mystruct *mystruct(int num, int size)
{
    Mystruct *mp = (Mystruct *)malloc(sizeof(Mystruct));
    if (mp)
    {
        if (mystructm(mp, num, size) == -1)
        {
            free(mp);
            mp = NULL;
        }
    }

    return mp;
}

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

Ответ 4

Выделение нового Mystruct и возврат указателя к нему обычно выглядят более или менее следующим образом:

Mystruct *mystruct(int num, int size)
{
   Mystruct *result;

   result = malloc(sizeof(MyStruct));
   if (!result)
     return NULL;

   result->num = num;
   ...

   return result;
}

Позже, когда вы закончите с Mystruct, выделенным здесь с помощью malloc, он должен быть снова освобожден с помощью free().

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

Ответ 5

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


EDIT (после редактирования исходного вопроса) Глядя на ваше редактирование вопроса, у вас наверняка возникнут проблемы с "моим" указателем. Это неинициализируется и может указывать на любую область памяти. Когда вы попытаетесь скопировать структуру в нее, вы, вероятно, получите ошибку seg.

Ответ 6

Еще один способ сделать это.

int mystruct(Mystruct *mystruct, int num, int size){
   if(mystruct == NULL)
      return -1;

   mystruct->num = num;
   mystruct->size = size;
   ::
   return 0;
}

int main(){
   Mystruct my;

   if(mystruct(&my, 3, 4) != 0){
      fprintf(stderr, "Cannot init!\n");
      exit(0);
   }
   ::
}