0

I have a problem with filling a flexible array of strings (char *) inside of a simple struct (the story is, I want to store a message as a string and a list of Redis lists names to send that message to in a struct, to publish to Redis later when a certain callback is called). The array has to be flexible because the number of Redis lists can vary based on a configuration file given to the program.

I can't seem to fill my array properly, I am expecting an array of size 2 in my case and no matter how much memory I allocate, gdb tells me it is of size 1 (I can only see the element of index 0 in the CLion Debugger panel). Two things trouble me :

  • It seems like I can assign values to indexes beyond what I intended when allocating memory,
  • even worse, I can access memory through elements of the array beyond the supposed array size.

I've seen examples of Flexible Array Members in structs but couldn't find an example with FAMs of char *. Does anyone know what I'm doing wrong here ? Here is an example below.

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

typedef struct {
    const char *redis_message;
    const char *redis_lists[];
} redis_data;

int main() {
    size_t num_lists = 2;
    const char *example_redis_lists[num_lists];

    // strings with different lengths
    example_redis_lists[0] = "foo_bar";
    example_redis_lists[1] = "bar";

    // this should initialize the struct with an array of size num_lists, right ?
    redis_data *data = malloc(sizeof(redis_data) + num_lists * sizeof(char *));
    data->redis_message = "Hello World !";

    for (size_t idx = 0; idx < num_lists; idx ++) {
        const char *string = example_redis_lists[idx];
        data->redis_lists[idx] = string;
    }

    data->redis_lists[2] = "baz_foobar"; // why can I do this ?
    data->redis_lists[3] = "i am not supposed to be here";
    data->redis_lists[4] = "me neither";

    size_t idx = 0;
    while (data->redis_lists[idx]) {
        // this segfaults if I don't add at least one element past index 1
        fprintf(stderr, "index : %zu, value : %s\n", idx, data->redis_lists[idx]);
        ++idx;
    }

    return 0;
}

Edit : to clarify, in my actual program the redis lists are indeed present in the array (despite gdb not showing them), but when I iterate it with size_t i= 0; while (data->redis_lists[i]) { send(); ++i; } I get a segfault because i equals the length of the array, and it bothers me to add elements to an array which size should be fixed at runtime.

louisbzk
  • 28
  • 1
  • 4
  • The debugger won't know how long it is because it is flexible. It's like when you `malloc` a block of `int`s - the debugger doesn't know how many `int`s will fit in the block. – Ian Abbott Mar 02 '22 at 10:21
  • 1
    You might want to [read the answer to this question](https://stackoverflow.com/questions/6452959/). The C language doesn't do bounds checking for any array, flexible or otherwise. It's up to you to stay within the bounds of the array. – user3386109 Mar 02 '22 at 10:22
  • Since `redis_data` does not contain anything to indicate the length of the flexible array, you need to record that somewhere. Some options are: (1) store the length externally in some auxiliary variable; (2) add a member to `redis_data` to store the length; or (3) terminate the array contents with a null pointer element to mark the end. – Ian Abbott Mar 02 '22 at 10:30
  • Thank you for your answers, I was able to solve my problem with @IanAbbott 's approach of storing the array length in the struct which seems like the natural solution when, indeed, you can't check your array's bounds in C (thanks for the link !). – louisbzk Mar 02 '22 at 13:06

0 Answers0