1

In my project, I am asked to store my 2D array of words in a dynamic data structure, then use them in other functions for other purposes, but I am confused how should I do this. I do understand, how to name them separately like:

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

typedef struct Names {
    char *name[5];
} Names;

void func(Names y) {
    printf("%s\n%s", y.name[0], y.name[1]);
}

int main()
{
    Names y;
    y.name[0] = "John";
    y.name[1] = "Luke";
    func(y);

    return 0;
}

But what if I wanted to do this as a 2d array. So normally I would do char names[][10] = {"John", "Luke", etc..}; but how do I store that in a struct? I mean if I did

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

typedef struct Names {
    char *name[5][10];
} Names;

void func(Names y) {
    printf("%s\n%s", y.name[0], y.name[1]);
}

int main()
{
    Names y;
    y.name[][10] = {"John", "Luke"};
    func(y);

    return 0;
}

That would just give errors and make no sense.

Wolf
  • 9,679
  • 7
  • 62
  • 108
Aldomond
  • 171
  • 6
  • hard to see from your question, look at this answer https://stackoverflow.com/a/1095006/2932052 – Wolf Jan 26 '21 at 16:22

2 Answers2

2

This is the official way to do it (see Nested initialization in: Struct and union initialization):

#include <stdio.h>

typedef struct Names {
    const char *name[2][2];
} Names;

void func(Names* y) {
    printf("%s, %s\n", y->name[0][0], y->name[0][1]);
    printf("%s, %s\n", y->name[1][0], y->name[1][1]);
}

int main()
{
    Names y = { .name={{"John", "Luke"}, {"Jack", "Jim"}}};
    func(&y);

    return 0;
}

Also the following works for backwords-compatibility reasons:

#include <stdio.h>

typedef struct Names {
    const char *name[2][2];
} Names;

void func(Names* y) {
    printf("%s, %s\n", y->name[0][0], y->name[0][1]);
    printf("%s, %s\n", y->name[1][0], y->name[1][1]);
}

int main()
{
    Names y = {"John", "Luke", "Jack", "Jim"};
    func(&y);

    return 0;
}

The above is managing string constants stored in const char pointers, for variable strings of up to 9 chars lentgh with a trailing zero-terminator, something like the following will be possible (I made compile-time constants for 5 and 9):

#include <stdio.h>

enum {
    NAME_COUNT = 5,
    NAME_LENGTH = 9
};
typedef struct Names {
    char name[NAME_COUNT][NAME_LENGTH+1];
} Names;

void func(Names* y) {
    for (int i=0; i<NAME_COUNT; ++i) {
        printf("%s\n", y->name[i]);
    }
}

int main()
{
    Names y = { .name={"John", "Olivia", "Luke", "Mary", "Jane" }};
    func(&y);

    return 0;
}
Wolf
  • 9,679
  • 7
  • 62
  • 108
  • Thank you a lot :) – Aldomond Jan 26 '21 at 16:14
  • And what if I have another function ```void func2(something);```. In my ```void func(Names *y);``` I would like to call that func2 function like this ```func2(y->name[0][0]);``` Just pass that name to another function, what should that ```func2(something);``` accept instead of that ```something``` ? – Aldomond Jan 26 '21 at 16:34
  • @Norbertas You mean how to access the address of one of the embedded strings members of the struct? – Wolf Jan 26 '21 at 16:35
  • Yes, for instance (talking about the first code sample of yours) I want to pass "John" in ```func``` to ```func2```, how should the ```func2``` be declared? Like ```func2(char name[0][5])``` ? So it contains one word of 5 characters? – Aldomond Jan 26 '21 at 16:38
  • @Norbertas Accessing the `i`th name within the structure is done by `&y->name[i]`. – Wolf Jan 26 '21 at 16:42
1

I think what you may be missing is the fact that char *name[5]; is not really a 2d array of words, it's an array of 5 pointers to char, you then make the two first pointers of that array point to two string literals. In the second expression you have a 5 by 10 2d array of pointers to char, each one of these pointer can also point to its own string literal, so naturally the expression:

y.name[][10] = {"John", "Luke"};

Is not correct for several reasons, the compiler needs to know both dimensions of the array to know to which pointer you want to assign the string literal, knowing this you'll note that the assigned expression makes little sense.

Example:

y.name[1][1] = "John"; 

Here you would assign the string literal "John" to the pointer located in the index [1][1] of the array of pointers.

Now, if you want an array of 5 words each one containing 10 characters, including the null byte you would simply use:

char name [5][10]

Note that in this configuration you can't simply assign the strings, you'll need to copy them using somenthing like strcpy.

strcpy(y.name[0], "John");
anastaciu
  • 23,467
  • 7
  • 28
  • 53