简体   繁体   中英

Allocate memory for dynamic array of structures inside a structure with double pointer**

When I use this code I would like to turn to every element of array of structures like this:

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

I tried everything I could, but in all cases I've had Segmentation fault. What am I doing wrong?

Please look at blocks between #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);
}

Compiled using:

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

I tried to find answers for handling a double pointer, but everything is very confusing.

You don't seem to initialize length to a meaningful value. Therefore you don't actually allocate memory, since you call calloc() with the first argument being zero.

(Disclaimer: I haven't tested the code, but that seems to be wrong.)

You're fairly close to what you want according to your comment .

Using array of structures

Here's an adaptation of your code. The primary change is use ArrayOfStructs *array instead of using a pointer-to-pointer. Also, because you've decided to use uint_fast64_t for a data type, you have to use PRIuFAST64 from <inttypes.h> to get the correct format string. It would be better to change that to size_t ; you aren't going to spot the performance difference on any reasonable system (but the code uses the format 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);
}

When run, this produces:

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

It doesn't crash. I've not run it under Valgrind . It will report leaks for the allocated memory.

Your type name ArrayOfStructures for a type that has no array in it seems wildly inappropriate. I'd've expected that to be given a name such as Point . I assume your Config structure has been minimized for this question (if so, thank you). If not, then the structure holding a single pointer to another structure is not giving you any benefit. It is just slowing down your access to the data — vastly outweighing any benefit from using uint_fast64_t instead of size_t . You'll need to be careful about your allocation of memory for the Config structure; you can't simply free everything inside the Config and its child structures at the moment.

Using array of pointers to structures

This is very similar to the last code, but you need an extra set of memory allocations. I've made that into a loop since the only reason for using this design is to allow you to allocate the pointed at structures separately. Otherwise, it is just needlessly complex. I've made a few minor cleanups; there are more improvements possible. I've added a structure dumper function, dump_points() , which I can and do use to print values at different 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);
}

Sample output (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

It's reassuring to see that the data is not corrupted as it is passed back up the chain of functions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM