Выделите память для динамического массива структур внутри структуры с двойным указателем ** - PullRequest
0 голосов
/ 04 июня 2019

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

array[0]->X;
array[1]->X;

Я перепробовал все, что мог, но во всех случаях у меня была ошибка Сегментации. Что я делаю не так?

Пожалуйста, посмотрите на блоки между #if 0 # endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    double X;
    double Y;

} ArrayOfStructures;

typedef struct
{
    uint_fast64_t length;

    ArrayOfStructures **array;

} Points;

typedef struct
{
    Points *points;

} Config;

void add_new_array(Config *conf)
{
    printf("conf=%p\n",conf);
    printf("conf->points=%p\n",conf->points);
    printf("conf->points->length=%zu\n",conf->points->length);
    printf("conf->points->array=%p\n",conf->points->array);
    #if 0
    ArrayOfStructures *temp = (ArrayOfStructures*)calloc(conf->points->length,sizeof(ArrayOfStructures));
    printf("temp=%p\n",temp);
    // Segmentation fault
    *conf->points->array = temp;
    #else
    conf->points->array  = (ArrayOfStructures **)calloc(conf->points->length,sizeof(ArrayOfStructures *));
    #endif
    printf("conf->points->array=%p\n",conf->points->array);
}

void another_function(Config *conf)
{
    conf->points->length = 1;

    add_new_array(conf);

    conf->points->array[0]->X = 0.1;
    conf->points->array[0]->Y = 0.2;

    printf("The result: X=%.12f, Y=%.12f, length=%zu\n",conf->points->array[0]->X,conf->points->array[0]->Y,conf->points->length);
}

void some_function(Config * conf)
{
    // To pass the structure to another function
    another_function(conf);
}

int main(void)
{
    // Stack's allocated memory
    Config conf_;
    Config *conf = &conf_;
    memset(conf,0x0,sizeof(Config));

    // Stack's allocated memory
    Points points;
    memset(&points,0x0,sizeof(Points));
    conf->points = &points;

    some_function(conf);

    return(EXIT_SUCCESS);
}

Скомпилировано с использованием:

gcc -D_SVID_SOURCE -g -ggdb -ggdb1 -ggdb2 -ggdb3 -O0 -DDEBUG -std=c11 -Wall --pedantic arryay.c -o array

Я пытался найти ответы для обработки двойного указателя, но все очень запутанно.

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Вы достаточно близки к тому, что вы хотите, согласно вашему комментарию .

Использование массива структур

Вот адаптация вашего кода. Основным изменением является использование ArrayOfStructs *array вместо использования указателя на указатель. Кроме того, поскольку вы решили использовать uint_fast64_t для типа данных, вы должны использовать PRIuFAST64 из <inttypes.h>, чтобы получить правильную строку формата. Было бы лучше изменить это на size_t; вы не заметите разницу в производительности на какой-либо разумной системе (но код использует формат PRIuFAST64).

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    double X;
    double Y;
} ArrayOfStructures;

typedef struct
{
    uint_fast64_t length;
    ArrayOfStructures *array;
} Points;

typedef struct
{
    Points *points;
} Config;

static
void add_new_array(Config *conf)
{
    printf("conf=%p\n", conf);
    printf("conf->points=%p\n", conf->points);
    printf("conf->points->length=%" PRIuFAST64 "\n", conf->points->length);
    printf("conf->points->array=%p\n", conf->points->array);

    ArrayOfStructures *temp = calloc(conf->points->length, sizeof(ArrayOfStructures));
    printf("temp=%p\n", temp);
    conf->points->array = temp;
    printf("conf->points->array=%p\n", conf->points->array);
}

static
void another_function(Config *conf)
{
    conf->points->length = 1;

    add_new_array(conf);

    conf->points->array[0].X = 0.1;
    conf->points->array[0].Y = 0.2;

    printf("The result: X=%.12f, Y=%.12f, length=%" PRIuFAST64 "\n",
           conf->points->array[0].X, conf->points->array[0].Y, conf->points->length);
}

static
void some_function(Config *conf)
{
    // To pass the structure to another function
    another_function(conf);
}

int main(void)
{
    // Stack's allocated memory
    Config conf_;
    Config *conf = &conf_;
    memset(conf, 0x0, sizeof(Config));

    // Stack's allocated memory
    Points points;
    memset(&points, 0x0, sizeof(Points));
    conf->points = &points;

    some_function(conf);

    return(EXIT_SUCCESS);
}

При запуске это выдает:

conf=0x7ffeed6883f8
conf->points=0x7ffeed688400
conf->points->length=1
conf->points->array=0x0
temp=0x7fef13c02a80
conf->points->array=0x7fef13c02a80
The result: X=0.100000000000, Y=0.200000000000, length=1

Он не падает. Я не запускал его под Valgrind . Он сообщит об утечках для выделенной памяти.

Ваше имя типа ArrayOfStructures для типа, в котором нет массива, кажется крайне неуместным. Я ожидал, что ему дадут имя, например Point. Я предполагаю, что ваша структура Config была минимизирована для этого вопроса (если так, спасибо). Если нет, то структура, содержащая один указатель на другую структуру, не дает никакой выгоды. Это просто замедляет ваш доступ к данным - значительно перевешивает любую выгоду от использования uint_fast64_t вместо size_t. Вы должны быть осторожны с распределением памяти для структуры Config; Вы не можете просто освободить все внутри Config и его дочерних структур в данный момент.

Использование массива указателей на структуры

Это очень похоже на последний код, но вам нужен дополнительный набор памяти. Я сделал это в цикле, так как единственная причина использования этого дизайна - позволить вам выделять указанные структуры отдельно. Иначе это просто излишне сложно. Я сделал несколько небольших уборок; возможны и другие улучшения. Я добавил функцию дампа структуры dump_points(), которую я могу использовать для печати значений в разных точках.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    double X;
    double Y;
} ArrayOfStructures;

typedef struct
{
    size_t length;
    ArrayOfStructures **array;
} Points;

typedef struct
{
    Points *points;
} Config;

static void dump_points(const char *tag, const Points *points)
{
    printf("%s (%zu, %p)\n", tag, points->length, (void *)points);
    for (size_t i = 0; i < points->length; i++)
        printf("%zu: (%.12f, %.12f) %p\n", i, points->array[i]->X, points->array[i]->Y,
               (void *)points->array[i]);
}

static
void add_new_array(Config *conf)
{
    printf("conf=%p\n", (void *)conf);
    printf("conf->points=%p\n", (void *)conf->points);
    printf("conf->points->length=%zu\n", conf->points->length);
    printf("conf->points->array=%p\n", (void *)conf->points->array);

    conf->points->array = calloc(conf->points->length, sizeof(conf->points->array[0]));
    for (size_t i = 0; i < conf->points->length; i++)
        conf->points->array[i] = calloc(1, sizeof(conf->points->array[i][0]));
    printf("conf->points->array=%p\n", (void *)conf->points->array);
    printf("conf->points->array[0]=%p\n", (void *)conf->points->array[0]);
    dump_points("Inside add new array", conf->points);
}

static
void another_function(Config *conf)
{
    conf->points->length = 3;

    add_new_array(conf);

    conf->points->array[0]->X = 0.1;
    conf->points->array[0]->Y = 0.2;
    conf->points->array[1]->X = 1.1;
    conf->points->array[1]->Y = 1.2;
    conf->points->array[2]->X = 2.1;
    conf->points->array[2]->Y = 2.2;

    dump_points("Inside another function", conf->points);
}

static
void some_function(Config *conf)
{
    // To pass the structure to another function
    another_function(conf);
    dump_points("Inside some function", conf->points);
}

int main(void)
{
    // Stack's allocated memory
    Config conf_;
    Config *conf = &conf_;
    memset(conf, 0x0, sizeof(Config));

    // Stack's allocated memory
    Points points;
    memset(&points, 0x0, sizeof(Points));
    conf->points = &points;

    some_function(conf);
    dump_points("Inside main", conf->points);

    return(EXIT_SUCCESS);
}

Пример вывода (macOS 10.14.5 Mojave; GCC 9.1.0):

conf=0x7ffee6f6b408
conf->points=0x7ffee6f6b410
conf->points->length=3
conf->points->array=0x0
conf->points->array=0x7f9c0a402a70
conf->points->array[0]=0x7f9c0a402a90
Inside add new array (3, 0x7ffee6f6b410)
0: (0.000000000000, 0.000000000000) 0x7f9c0a402a90
1: (0.000000000000, 0.000000000000) 0x7f9c0a402aa0
2: (0.000000000000, 0.000000000000) 0x7f9c0a402ab0
Inside another function (3, 0x7ffee6f6b410)
0: (0.100000000000, 0.200000000000) 0x7f9c0a402a90
1: (1.100000000000, 1.200000000000) 0x7f9c0a402aa0
2: (2.100000000000, 2.200000000000) 0x7f9c0a402ab0
Inside some function (3, 0x7ffee6f6b410)
0: (0.100000000000, 0.200000000000) 0x7f9c0a402a90
1: (1.100000000000, 1.200000000000) 0x7f9c0a402aa0
2: (2.100000000000, 2.200000000000) 0x7f9c0a402ab0
Inside main (3, 0x7ffee6f6b410)
0: (0.100000000000, 0.200000000000) 0x7f9c0a402a90
1: (1.100000000000, 1.200000000000) 0x7f9c0a402aa0
2: (2.100000000000, 2.200000000000) 0x7f9c0a402ab0

Обнадеживает то, что данные не повреждены, поскольку они передаются обратно в цепочку функций.

1 голос
/ 04 июня 2019

Вы, похоже, не инициализируете length значащим значением. Поэтому вы фактически не выделяете память, так как вы вызываете calloc() с первым аргументом, равным нулю.

(Отказ от ответственности: я не тестировал код, но, похоже, это неправильно.)

...