Home > front end >  Compound literal for two-dimensional array of strings
Compound literal for two-dimensional array of strings

Time:10-27

I have a two-dimensional array of strings inside a struct, and I'd like to be able to initialize it at compile time, with a compound literal, rather than dynamically with malloc().

The meaning of this array of strings is that it's an array of items, with each item having three strings (one for the name of the item, another for a description, and another for a URL).

Yes, I know I could use three arrays instead, but I'd prefer to pack it in a two-dimensional array.

I tried to write it this way (NOTE that I'm initializing just the name of the item, but not the description nor the URL... this is on purpose, as I assume the pointers to the description and the URL will be automatically initialized to NULL according to the designated initializers behaviour --when you don't initialize a field, it becomes zero)

My attempt:

enum labelkind {
    L_NAME,
    L_DESCRIPTION,
    L_URL,
    L_NUMKINDS};
    
struct labeltype{
    int someval;
    size_t  nlabels;
    char    **labels[L_NUMKINDS];
    };
    
static struct labeltype mylabel = {
    .someval=10,
    .nlabels=3,
    .labels=(char *[][L_NUMKINDS]){
        [0][L_NAME]="First name",
        [1][L_NAME]="Second name",
        [2][L_NAME]="Third name"
        }
    };

Compiling it with clang, I get these warnings:

main.c:266:10: warning: incompatible pointer types initializing 'char **' with an expression of type 'char *[3][3]'
      [-Wincompatible-pointer-types]
        .labels=(char *[][L_NUMKINDS]){
                ^~~~~~~~~~~~~~~~~~~~~~~
main.c:266:10: warning: suggest braces around initialization of subobject [-Wmissing-braces]
        .labels=(char *[][L_NUMKINDS]){
                ^~~~~~~~~~~~~~~~~~~~~~~
                {

So, from these warnings, I guess I'm doing something wrong.

What would be the correct syntax for doing this?

CodePudding user response:

The structure definition is incorrect: as defined, labels is an array of L_NUMKINDS pointers to pointers to char. You probably want labels to point to an array of nlabels arrays of L_NUMKINDS pointers to char. The definition should be char *(*labels)[L_NUMKINDS]; or better const char *(*labels)[L_NUMKINDS]; since you want to use string constants as initializers.

Here is a modified version with a test program:

#include <stdio.h>

enum labelkind {
    L_NAME,
    L_DESCRIPTION,
    L_URL,
    L_NUMKINDS
};

struct labeltype {
    int someval;
    size_t nlabels;
    const char *(*labels)[L_NUMKINDS];
};

static struct labeltype mylabel = {
    .someval = 10,
    .nlabels = 4,
    .labels = (const char *[][L_NUMKINDS]) {
        [0][L_NAME] = "First name",
        [1][L_NAME] = "Second name",
        [2][L_NAME] = "Third name",
        [3][L_NAME] = "Fourth name",
    }
};

static void pstr(const char *name, const char *s) {
    printf("%s: ", name);
    if (s)
        printf("\"%s\"", s);
    else
        printf("null");
}

static void print_labels(const struct labeltype *lp) {
    for (size_t i = 0; i < lp->nlabels; i  ) {
        printf("{ ");
        pstr("name", lp->labels[i][L_NAME]);
        printf(", ");
        pstr("description", lp->labels[i][L_DESCRIPTION]);
        printf(", ");
        pstr("url", lp->labels[i][L_URL]);
        printf(" }\n");
    }
}

int main() {
    print_labels(&mylabel);
    return 0;
}

Output:

{ name: "First name", description: null, url: null }
{ name: "Second name", description: null, url: null }
{ name: "Third name", description: null, url: null }
{ name: "Fourth name", description: null, url: null }
  • Related