проблемы с указателем структуры - PullRequest
0 голосов
/ 23 марта 2010

Я пытаюсь преобразовать структуру в другую структуру, но у меня возникают несовместимые проблемы с указателями в приведении и malloc в some_func (структура структур такая же)

struct stu1 **some_func(struct stu1 *my_struct)
{
   my_struct = (struct stu1 **)malloc(sizeof(struct stu1 *)*total_size);

   for(i=0;i<20;i++){
      my_struct[i] = (struct stu1 *)malloc(sizeof(struct stu1));
      printf("%s",my_struct[i++]->a);
   }
   return my_struct;
}

int main() 
{
   struct stu1 **my_struct;
   struct stu2 **my_struct2;
   struct stu3 **my_struct3;

   my_struct = some_func(my_struct);
   my_struct2 = (struct stu2**)some_func((struct stu1*)my_struct2);
   my_struct3 = (struct stu3**)some_func((struct stu1*)my_struct3);    
}

Ответы [ 4 ]

2 голосов
/ 23 марта 2010

Несколько проблем.

Во-первых, у вас повсюду несовместимые типы. В строке

my_struct = some_func(my_struct);

my_struct имеет тип struct stu1 **, но определение some_func ожидает параметр типа struct stu1 *; два типа не совпадают. Указатель на T отличается от указателя на указатель на T.

Во-вторых, ваша гимнастика не будет работать так, как вы ожидаете. Типы указателей не совместимы автоматически; их базовые типы должны быть совместимы, а разные типы структур несовместимы, даже если их макеты одинаковы, например ::

struct {int x, int y} foo;
struct {int x, int y} bar;
struct S {int x, int y} blurga;
struct S bletch;

foo, bar и bletch относятся к разным типам и несовместимы, даже если их макеты одинаковы. blurga и bletch относятся к одному типу (структура S). Если struct stu2 или struct stu3 имеют размеры, отличные от struct stu1, вы не выделите нужный объем памяти для my_struct2 и my_struct3.

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

struct stu1 **stu1_alloc(size_t count)
{
  struct stu1 **arr = malloc(sizeof *arr * count);
  if (arr)
  {
    size_t i;
    for (i = 0; i < count; i++)
    {
      arr[i] = malloc(sizeof *arr[i]);
      if (arr[i])
      {
        // initialize arr[i] as necessary
      }
    }
  }
  return arr;
}

struct stu2 **stu2_alloc(size_t count)
{
  struct stu2 **arr = malloc(sizeof *arr * count);
  if (arr)
  {
    size_t i;
    for (i = 0; i < count; i++)
    {
      arr[i] = malloc(sizeof *arr[i]);
      if (arr[i])
      {
        // initialize arr[i] as necessary
      }
    }
  }
  return arr;
}

struct stu3 **stu3_alloc(size_t count)
{
  struct stu3 **arr = malloc(sizeof *arr * count);
  if (arr)
  {
    size_t i;
    for (i = 0; i < count; i++)
    {
      arr[i] = malloc(sizeof *arr[i]);
      if (arr[i])
      {
        // initialize arr[i] as necessary
      }
    }
  }
  return arr;
}

int main(void)
{
  struct stu1 **my_struct = stu1_alloc(SIZE);
  struct stu2 **my_struct2 = stu2_alloc(SIZE2);
  struct stu3 **my_struct3 = stu3_alloc(SIZE3);
  ...
}

Да, единственное, что отличается между тремя функциями выделения, это тип. Однако, если разные типы структур имеют разные размеры или разные потребности в инициализации, это необходимо.

Обратите внимание на пару вещей. Прежде всего, я не использую результат malloc(). Для этого есть две причины. Во-первых, начиная с C89 и позже, вам не нужно: malloc() возвращает тип void *, который неявно преобразуется в целевой тип указателя. Во-вторых, и что еще более важно, если я забуду включить stdlib.h или иным образом не иметь прототип для malloc() в области видимости, то при отключении будет выдано предупреждение «несовместимые типы» (поскольку незадекларированные функции должны возвращать int, и вы не можете неявно преобразовать значение типа int в тип указателя). Если вы приводите возвращаемое значение malloc(), то вы подавляете это предупреждение и рискуете проблемы во время выполнения (поскольку значение, возвращаемое malloc(), будет преобразовано из void * в int, а затем из int в тип целевого указателя, который не гарантированно работает).

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

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

#define ALLOC_STU(target, size)                \
  do {                                         \
    target = malloc(sizeof *target * size);    \
    if (target)                                \
    {                                          \
      size_t i;                                \
      for (i = 0; i < size; i++)               \
      {                                        \
        target[i] = malloc(sizeof *target[i]); \
      }                                        \
    }                                          \
  } while(0)

int main(void)
{
  struct stu1 **my_struct;
  ...
  ALLOC_STU(my_struct, SIZE);
  ...
}

хотя я думаю, что отдельные функции распределения - более безопасный путь.

1 голос
/ 23 марта 2010
struct stu1 **some_func(struct stu1 *my_struct)
{
   my_struct = (struct stu1 **)malloc(sizeof(struct stu1 *)*total_size);

my_struct имеет тип struct stu1 *, но вы пытаетесь присвоить (приведенный) struct stu1 **

0 голосов
/ 23 марта 2010

С чего начать ...

  1. Вы должны соответствовать вашим типам. some_func () ожидает один указатель; в одном случае вы передаете двойной указатель (указатель на указатель).
  2. Внутри some_func () 1-й malloc () имеет несоответствие типов. Он пытается установить двойной указатель на один указатель.
  3. Внутри some_func () у второго malloc () есть другое несоответствие типов. Он пытается установить не указатель (структуру) на указатель.

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

Способ № 1. (Без проверки ошибок)

struct stu1 **some_func(int dim1, int dim2)
{
   struct stu1 **my_struct;
   int  i;

   /* Allocate space for an array of <dim1> pointers */
   my_struct = (struct stu1 **) malloc(sizeof(struct stu1 *) * dim1);

   /* Allocate <dim2> elements for each pointer */
   for (i = 0; i < dim1; i++){
      my_struct[i] = (struct stu1 *) malloc (sizeof (struct stu1) * dim2);
   }
   return (my_struct);
}

Метод № 2. (Опять же, без проверки ошибок)

struct stu1 **some_func(int dim1, int dim2)
{
   struct stu1 **my_struct;
   int  i;
   char *data;

   /* Allocate space for everything. */
   data = (char *) malloc((sizeof (struct stu1 *) * dim1) + (dim1 * dim2 * sizeof (struct stu1)));
   my_struct = (struct stu1 **) data;

   /* Initialize pointers to pointers. */
   data = (char *) &my_struct[dim1];
   for (i = 0; i < dim1; i++) {
      my_struct[i] = (struct stu1 *) data;
      data += sizeof (struct stu1) * dim2;
   }
   return (my_struct);
}

Каждый метод имеет свои преимущества и недостатки. Надеюсь, это поможет.

0 голосов
/ 23 марта 2010

Просто угадайте, хотите ли вы что-то вроде этого:


struct stu1 **some_func(struct stu1 ***my_struct) 
{ 
   *my_struct = (struct stu1 **)malloc(sizeof(struct stu1 *)*total_size); 

   for(i=0;i<20;i++){ 
      (*my_struct)[i] = (struct stu1 *)malloc(sizeof(struct stu1)); 
      printf("%s",(*my_struct)[i++]->a); 
   } 
   return *my_struct; 
} 

int main()  
{ 
   struct stu1 **my_struct; 
   struct stu2 **my_struct2; 
   struct stu3 **my_struct3; 

   my_struct = some_func(&my_struct); 
} 

Но это не имеет особого смысла. Возвращаемое значение не требуется.

...