Выделение памяти для другой структуры изменяет указатель членов совершенно другой структуры - PullRequest
1 голос
/ 13 февраля 2020

Выделение памяти для matrix struct с некоторыми значениями пары [row, column] для функции create_matrix изменяет значения указателя layer->values, который не имеет отношения к выделяемой структуре matrix.

Некоторые протестированы [row, column] значения:

[1, 2]
[2, 2]

вывод gdb для [2,2], т.е. create_matrix(2, 2):

(gdb) print *prev_layer
$1 = {
  nodes = 2,
  weights = 0xb6438030,
  biases = 0xb6438060,
  values = 0xb6438080
}
(gdb) n
(before allocation): 0xb6438080
50          weights = create_matrix(2, 2);
(gdb) n
51          if (!weights)
(gdb) print *prev_layer
$2 = {
  nodes = 2,
  weights = 0xb6438030,
  biases = 0xb64380b0, <- this changes
  values = 0xb64380c0 <- this changes
}
(gdb)

Сверху кажется, что он назначает два последних указателя, связанных с памятью распределение для двух последних членов структуры. Иногда даже NULL указатель

Вывод программы для [2,2]:

Values of prev_layer->values
(before allocation): 0xb6438080
(after allocation): 0xb64380c0

Используемый код:

#include <stdlib.h>
#include <stdio.h>


typedef struct matrix {
    int rows;
    int cols;
    double **m;
} matrix;

typedef struct layer {
    int nodes;
    matrix *weights;
    matrix *biases;
    matrix *values;
} layer;

matrix *create_matrix(int rows, int cols) {
    matrix *ret = malloc(sizeof(matrix));
    if (!ret)
        return NULL;
    double **m = malloc(rows * sizeof(double *));
    if (!m)
        return NULL;

    for (int c = 0; c < rows; c++) {
        m[c] = calloc(cols, sizeof(double));
        if (!m[c]) {
            return NULL;
        }
    }

    ret->rows = rows;
    ret->cols = cols;
    ret->m = m;

    return ret;
}

layer *create_layer(int nodes, const layer *prev_layer) {

    matrix *weights, *biases;
    /* Just after allocation it changes pointer of
     * prev_layer->bias and prev_layer->values
     * to last to matrix row allocations
     * bug works with values in ordered pair [row, col] => [1,2], [2,2],
     * doesn't with when used values like [5,3]
     * */
    if (prev_layer)
        printf("(before allocation): %p\n", prev_layer->values);

    weights = create_matrix(1,2);
    if (!weights)
        return NULL;

    if (prev_layer)
        printf("(after allocation): %p\n", prev_layer->values);

    biases = create_matrix(1, nodes);
    if (!biases)
        return NULL;

    matrix *values = create_matrix(1, nodes);
    if (!values)
        return NULL;

    layer *ret = malloc(sizeof(layer *));
    if (!ret)
        return NULL;

    ret->nodes = nodes;
    ret->weights = weights;
    ret->biases = biases;
    ret->values = values;
    return ret;
}

int main() {
    int nodes[] = {2, 2};
    layer *p1 = create_layer(2, NULL);
    layer *p2 = create_layer(2, p1);
    return 0;
}

Компилятор: clang 9.0 0,0

Ответы [ 2 ]

2 голосов
/ 13 февраля 2020

Тип, используемый для вычисления размера выделения, неверен в:

layer *ret = malloc(sizeof(layer *));  // should be sizeof(layer)

Вы указываете размер указателя вместо размера структуры.

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

layer *ret = malloc(sizeof(*ret));

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

#define ALLOC(t)           ((t *)calloc(1, sizeof(t)))
#define ALLOC_ARRAY(t, n)  ((t *)calloc(n, sizeof(t)))

layer *ret = ALLOC(layer);
1 голос
/ 13 февраля 2020

Строка с ret malloc должна занимать достаточно места для целого layer, однако вы запросили достаточно места для layer*.

Итак

layer *ret = malloc(sizeof(layer *));

должно быть

layer *ret = malloc(sizeof(layer));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...