0

I want to initialize a structure with an array of string without doing dynamic allocation. Is it possible? I had thought of something like this but it doesn't work:

struct st_request {
int GRID;
char NAME[15];
char (*PARAM)[15];
};
typedef struct st_request request;

request myrequest = {
 .GRID=1,
 .NAME="GLOB",
 .PARAM={"RR1","RR3"}
}

An idea? Thanks for your solutions.

3
  • 3
    PARAM is not an array. It is a pointer. Commented Jun 15, 2021 at 13:03
  • Try [] instead of [15] Commented Jun 15, 2021 at 13:10
  • 2
    @Ole To achieve what, to get a compiler error? Commented Jun 15, 2021 at 13:14

3 Answers 3

2

There are several variants possible, here two of them:

struct s
{
    char params1[32][64]; // 32 strings each with maximum length of 64 characters

///////////////////////////////////////////////////

    char buffer[1024]; // byte buffer for individual strings
    char* params2[32]; // 32 pointers you can let point
                       // to arbitrary positions into buffer
};

If you don't always use all parameters you might want to add size_t numparams; to any of both of above solutions.

When copying, first variant is just fine, with second variant you will have to re-adjust the pointers:

dest.params2[n] = dest.buffer + (source.params2[n] - source.buffer);

With second variant, don't forget to leave space for terminating null pointers. A struct with data might then look like this:

buffer     == "hello world\0hola mundo\0salut monde\0\0\0 ...";
// first parameter  c a n  be implicit: buffer
params2[0] == buffer + 12;
params2[1] == buffer + 23;
numParams  == 3; // including the implicit parameter

Alternatively first parameter might always point to buffer's begin, then you can access all parameters consistently without any special handling like p = n == 0 ? buffer : params[n-1].

Initialisation can look like this:

struct s g_s =
{
        .params1 =
        {
                "hello world",
                "hola mundo",
                "salut monde",
        },

        .buffer = "hello world\0hola mundo\0salut monde",
        .params2 =
        {
                g_s.buffer + 12,
                g_s.buffer + 23,
        },

        .numParams = 3,

};

Unfortunately you need to count the offsets for second variant on your own (you might write a helper script doing that for you...).

Sign up to request clarification or add additional context in comments.

2 Comments

I wonder if you can get the array length with sizeof(g_s.params2) / sizeof(g_s.params2[0] ?
@user2030243 Sure you can, as with any array – as long as it hasn't decayed to pointer yet, of course (e. g. sizeof(g_s.params1)/sizeof(*g_s.params1) for the other array or sizeof(*g_s.params1)/sizeof(**g_s.params1) for the sub-arrays). However if you wanted to replace the numParams member that way you are out of luck unless all of those parameters are always in use (the sizeof-trick gives you the total available capacity, numParams the number of slots actually in use).
1

The line

char (*PARAM)[15];

declares a single pointer PARAM which points to an array of type char[15], i.e. to an array of 15 elements, in which each element has the type char.

You probably want to write

char *PARAM[15];

which declares an array of 15 pointers, in which each pointer has the type char*. In contrast to the pointer mentioned earlier, which points to an entire array, these 15 pointers only point to a single character.

In C, when handling strings, it is normal to use pointers to the first character of a null-terminated character sequence. Pointers to entire arrays are normally only used in the context of multi-dimensional arrays, because the size information of the referenced object is needed to calculate the offset in a multi-dimensional array.

Note that it is not normal to write the names of variables in upper-case. This is normally reserved for constants.

Also, there is a ; missing in the last line of your code.

7 Comments

char *PARAM[15] would indeed be compatible with the initializer the OP presented, but I am not so sure that it is what they are really after. I take the fact that the OP's NAME and *PARAMS are both declared with length 15 to be likely significant -- that is, that although they wrote "array of strings" they really meant "array of char arrays". If not, however, then declaring const char *PARAM[15] would be better if they intend to use it as shown.
char * PARAM[15] works (with const too). Thanks.
I wonder if you can get the array length with sizeof(myRequest.PARAM) / sizeof(myRequest.PARAM[0] ?
@user2030243: I don't think that sizeof(myRequest.PARAM) is what you want, as that will give you the size of the array PARAM, i.e. the size of 15 pointers, which is 120 bytes, assuming 8 bytes (64 bits) per pointer. I don't think that sizeof(myRequest.PARAM[0]) is what you want, either, as that will always give you the size of a single pointer (8 bytes). If you want the actual length of the string, you must use strlen. If you want the actual size of the array that is being pointed to, i.e. the maximum number of characters that can be stored, then you must remember that by other means.
Ok I guess i have to store the number of strings stored during init elsewhere (ie two: RR1 and RR3)
|
0

You could try the following:

#define PARAM_SIZE 20;

struct st_request {
int GRID;
char NAME[15];
char PARAM[15*PARAM_SIZE];
};

request myrequest = {
 .GRID=1,
 .NAME="GLOB"
}

strcpy (&myrequest.PARAM[0*PARAM_SIZE], "RR1");
strcpy (&myrequest.PARAM[1*PARAM_SIZE], "RR3");

Comments

Your Answer

By clicking “Post Your Answer”, 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.