Как назначить массив структур - PullRequest
1 голос
/ 05 января 2020

У меня есть функция create (), которая возвращает указатель на структуру с именем ann, как показано ниже

typedef struct ann {
    int inputs;                 /* Number of input neurones      */
    int hidden_layers;          /* Number of hidden layers       */
    int hidden;                 /* Number of hidden neurones     */
    int outputs;                /* Number of output neurons.     */
    int weights;                /* Total nof weigths(chromosomes)*/
    int neurons;                /* Total Number of neurones      */
    double *weight;             /* The weights(genotype)         */
    double *output;             /* Output                        */
    double fitness;              /* Total fitness of the network    */
    double *delta;
    actfun activation_hidden;   /* Hidden layer activation func  */
    actfun activation_output;   /* Output layer activation func  */
} ann;

прототип функции create ()

ann *create(int inputs, int hidden_layers, int hidden, int outputs);

мне нужно массив ann s, поэтому у меня есть следующее

int population_size = 10;
ann *population = malloc ( population_size * sizeof(ann));

    for( i = 0; i < population_size; i++ ){
        population[i] = create( trainset->num_inputs, 1 , hidden, trainset->num_outputs);
    }

, но я получаю следующую ошибку

error: incompatible types when assigning to type ‘ann {aka struct ann}’ from type ‘ann * {aka struct ann *}’

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

. Здесь запрашивается полный код функции create ()

ann *create   ( int inputs, int hidden_layers, int hidden, int outputs ) {

    if (hidden_layers < 0) return 0;
    if (inputs < 1) return 0;
    if (outputs < 1) return 0;
    if (hidden_layers > 0 && hidden < 1) return 0;


    const int hidden_weights = hidden_layers ? (inputs+1) * hidden + (hidden_layers-1) * (hidden+1) * hidden : 0;
    const int output_weights = (hidden_layers ? (hidden+1) : (inputs+1)) * outputs;
    const int total_weights = (hidden_weights + output_weights);

    const int total_neurons = (inputs + hidden * hidden_layers + outputs);

    /* Allocate extra size for weights, outputs, and deltas. */
    const int size = sizeof(ann) + sizeof(double) * (total_weights + total_neurons + (total_neurons - inputs));
    ann *ret = malloc(size);
    if (!ret) return 0;

    ret->inputs = inputs;
    ret->hidden_layers = hidden_layers;
    ret->hidden = hidden;
    ret->outputs = outputs;

    ret->weights = total_weights;
    ret->neurons = total_neurons;

    /* Set pointers. */
    ret->weight = (double*)((char*)ret + sizeof(ann));
    ret->output = ret->weight + ret->weights;
    ret->delta = ret->output + ret->neurons;

    ann_randomize(ret);

    ret->activation_hidden = ann_act_sigmoid_cached;
    ret->activation_output = ann_act_sigmoid_cached;

    ann_init_sigmoid_lookup(ret);

    return ret;
}

Ответы [ 4 ]

3 голосов
/ 06 января 2020

Ошибка

error: incompatible types when assigning to type ‘ann {aka struct ann}’ from type ‘ann * {aka struct ann *}

возникает из-за того, что population[i] является struct ann, а не указателем на него. Различные типы!

Что нужно сделать, как уже было сказано в ответе Стефана Лехнера, это либо изменить массив снаружи (сделать его массивом указателей), либо вернуть тип функции create (), сделав ее вернуть саму структуру.

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

В функции вызова, где определяется массив указателей на ann:

ann *population[10] = { 0 };

for( i = 0; i < 10; i++ ){
    if ( create( &population[i], trainset->num_inputs, 1 , hidden, trainset->num_outputs) < 0 ){
        printf ("Issues during creation of ann #%d\n", i);
        break;
    }
} 

// Remember to free the pointers!

Нет выделения! Он перемещается внутрь create(), что будет иметь два изменения интерфейса:

  1. Выходной указатель передается как параметр (первый, в моем примере)
  2. Возвращает код ошибки (0 при успехе, <0 при ошибке) </li>
int create(ann **outstruct, int inputs, int hidden_layers, int hidden, int outputs){
    int ret = 0;

    ann *tmp = malloc( sizeof(ann));

    // ...
    //do whatever you need to initialize the newly allocated struct

    // set ret to a negative value if anything goes wrong
    // ... but in this case free tmp before returning!
    //...

    outstruct = tmp;

    return ret;
}

В моем примере указатель ann ** должен был быть передан в create(), потому что он внутренне выделил память.

Достаточно простого указателя, если структуры размещаются снаружи, а create() играет только роль для его заполнения.

2 голосов
/ 06 января 2020

Вы можете либо разыменовать указатель перед назначением типа

population[i] = *create(...);

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

ann create(int inputs, int hidden_layers, int hidden, int outputs);

Однако, вероятно, наилучшим способом было бы - как предложил Barmar - использовать массив указателей вместо массива объектов struct. Полный образец, который не должен сочетаться с решениями, представленными выше, может выглядеть следующим образом:

ann *create(int inputs, int hidden_layers, int hidden, int outputs) {
   ann* result = malloc (sizeof(ann));
   ..
   return result;
}

...

int population_size = 10;
ann **population = malloc ( population_size * sizeof(ann*));

for( i = 0; i < population_size; i++ ){
    population[i] = create( trainset->num_inputs, 1 , hidden, trainset->num_outputs);
} 
1 голос
/ 06 января 2020

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

ann **population = malloc (sizeof (ann *) * population_size);

for (i = 0; i < population_size; i++) {
    population[i] = malloc (sizeof (ann));
    create (population[i], trainset->num_inputs, 1 , hidden, trainset->num_outputs);
}

Затем внутри функции вы можете просто присвоить значения указателю.

void create (ann *element, int inputs, int hidden_layers, int hidden, int outputs) {
     element->inputs = inputs;
     ...
}

Наконец, не забудьте освободить неиспользуемое пространство памяти перед завершением программы.

for (i = 0; i < population_size; i++) {
     free (population[i]);
}
free (population);
0 голосов
/ 06 января 2020

Абстрагируясь от программы logi c, вам просто нужно разыменовать результат создания, а также сохранить его возвращаемое значение для функции free, чтобы предотвратить утечку памяти

ann *create(int inputs, int hidden_layers, int hidden, int outputs);

void foo()
{
int population_size = 10;
ann *population = malloc ( population_size * sizeof(ann));

    for( int i = 0; i < population_size; i++ )
    {
        ann *tempptr;
        population[i] = (tempptr = create( 1, 1 , 1, 1)) ? *tempptr : (ann){0,};
        free(tempptr);
    }
}  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...