I'm trying to have an array of structure.

The sprite_s struct:

typedef struct sprites_s {
    bool *initialized;
    sfSprite *duck;
} sprites_t;

Can I, with memset, fill the array with data so I can be sure of what I've initiated or not ?

I'm doing this right now:

int create_sprite(sprites_t **sprites)
{
    *sprites = malloc(sizeof(sprites_t) * MAX_SPRITE_DISPLAYED);
    memset(*sprites, NULL, sizeof(sprites_t));
    *sprites[MAX_SPRITE_DISPLAYED - 1] = (sprites_t) {
        false,
        NULL
    };
}

Isn't NULL made to track end only ?

4 Replies 4

First, bool *initialized; is a pointer to a bool, but not a bool. So you can't assign value false.

Then use calloc(MAX_SPRITE_DISPLAYED,sizeof(sprites_t)) instead of malloc(sizeof(sprites_t) * MAX_SPRITE_DISPLAYED);. to get a zeroed list.

memset(*sprites, NULL, sizeof(sprites_t)); will only zero the first element.

To mark the last element of a list, you must have an unique identification. NULL for a pointer can be used, but only if all other pointers are not NULL.

@Wiimm: false can assigned to or used to initialize a pointer. Per C 2024 6.4.5.6, false is a constant of type bool with value 0. Per 6.2.5, bool is an unsigned integer type. Per 6.6, an integer constant forms an integer constant expression. Per 6.3.3.3, an integer constant expression with value 0 is a null pointer constant. Also per 6.3.3.3, converting a null pointer constant to a pointer type produces a null pointer. Per 6.7.11, the constraints and semantics for assignment apply to initialization of a scalar. Per 6.5.17.2, assigning a pointer from a null pointer constant satisfies the constraints. Also per 6.5.17.2, the assignment converts the right operand to the type of the left operand. (I do not speak to whether it is good practice, but it is strictly conforming C code.) In contrast, the method you have recommended, using calloc, is not guaranteed to initialize the object with a null pointer, as the C standard does not require that bytes of value in zero to be a representation of a null pointer.

I think you mean to use a sentinel value on your struct, instead of using a length property, right?

Take a look on my attempt to fix it:

typedef struct sprites_s {
    bool  initialized; // removed pointer
    sfSprite *duck;
} sprites_t;

int create_sprite(sprites_t **sprites) {
    size_t memoryNeeded = sizeof(sprites_t) * MAX_SPRITE_DISPLAYED;
    sprites_t *arr = malloc(memoryNeeded);

    // Never forget to check if malloc returns NULL.
    if (arr == NULL) {
        return 0;
    }

    // Instead of:
    // memset(*sprites, NULL, sizeof(sprites_t));
    //
    // or
    // memset(arr, NULL, sizeof(sprites_t));
    // 
    // Do this:
    sprites_t template;
    template.initialized = true;
    template.duck = NULL;
    for (size_t i = 0; i < MAX_SPRITE_DISPLAYED-1; ++i) {
        memcpy(&(arr[i]), &template, sizeof(sprites_t));
    }

    // And then, for the last one to mark as a sentinel value:
    //
    // You could do it like this:
    // *sprites[MAX_SPRITE_DISPLAYED - 1] = (sprites_t) {
    //     false,
    //     NULL
    // };
    //
    // But I think this is better:
    template.initialized = false;
    memcpy(&(arr[MAX_SPRITE_DISPLAYED-1]), &template, sizeof(sprites_t));

    // Then, everything went as expected, you can return both values
    *sprites = arr;
    return 1;
}

Note: I didn't compiled the code. If there're typos, my bad.

memset(*sprites, NULL, sizeof(sprites_t)); is wrong, 2nd parameter of memset requires an int, not a pointer. Also the size is wrong, if you intend to initialize the whole array of structs.

You should just use calloc instead, it is guaranteed to set all pointers to zero, which will work on all non-exotic systems.

The C standard is confused here saying "296) Note that this need not be the same as the representation of floating-point zero or a null pointer constant." Who cares, we want to initialize our pointers to a null pointer, not to a null pointer constant. Initialization with calloc is not as per assignment, so conversion from null pointer constant to null pointer as per C23 6.3.3.3 does not apply.

Sentinel values should be avoided when possible, they are cumbersome.

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.