Несколько проблем.
Во-первых, у вас повсюду несовместимые типы. В строке
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);
...
}
хотя я думаю, что отдельные функции распределения - более безопасный путь.