Initialization of a const matrix implemented as pointer-to-pointer

Discussion in 'C Programming' started by Andrea Taverna (Tavs), Sep 10, 2008.

  1. Subject: Initialization of a const matrix implemented as pointer-to-pointer

    Hello everyone.

    I've got the following matrix definition in a source file

    static const char **a;

    I need it to be initialized as an array of strings, something like

    static const char **a = {"Alpha", "Beta", Charlie"};

    I know the number of strings and their maximum length, but I can't use a
    stack-allocated matrix for compatibility reasons with another piece of
    code, which simply defines a

    char** strings

    to which the matrix has to be assigned to.

    I thought I could write a static const declaration for each string

    static const str1[MAX_LENGTH] ="Alpha"

    and then declare the matrix as

    static const char* a[NUM_OF_STRINGS] = {str1,str2,...}

    would it be correct?

    thanks for your attention

    AT
    Andrea Taverna (Tavs), Sep 10, 2008
    #1
    1. Advertising

  2. On Wed, 10 Sep 2008 13:57:47 +0200, "Andrea Taverna (Tavs)"
    <> wrote:

    >Subject: Initialization of a const matrix implemented as pointer-to-pointer
    >
    >Hello everyone.
    >
    >I've got the following matrix definition in a source file
    >
    > static const char **a;


    In this case, sizeof a will probably be 4 or 8.

    >
    >I need it to be initialized as an array of strings, something like
    >
    > static const char **a = {"Alpha", "Beta", Charlie"};
    >
    >I know the number of strings and their maximum length, but I can't use a
    >stack-allocated matrix for compatibility reasons with another piece of
    >code, which simply defines a
    >
    > char** strings


    >
    > to which the matrix has to be assigned to.


    There should be no problem "assigning the array" to this pointer.

    >
    >I thought I could write a static const declaration for each string
    >
    > static const str1[MAX_LENGTH] ="Alpha"
    >
    >and then declare the matrix as
    >
    > static const char* a[NUM_OF_STRINGS] = {str1,str2,...}


    If NUM_OF_STRINGS is 3 (to be consistent with your example), sizeof a
    will probably be 12 or 24.

    >
    >would it be correct?


    It depends on how you plan to use a.

    In the first example, is a true pointer. It can appear on the left
    side of the assignment operator. In the second, a is an array which
    cannot appear there. However, in both cases, a can appear on the
    right of the assignment operator.

    If all you want is a variable name that can be subscripted to evaluate
    to different strings, then the second will work. If you delete the
    "static", it will become a "stack allocated matrix" (technically an
    automatic array of char*). When the array name "a" appears in an
    expression context other than as the operand of sizeof and &, it will
    be converted to the address of a[0] with type "pointer to type of
    a[0]". Since a is an array of char*, a[0] is the first char* in the
    array. The type "pointer to type of a[0]" is simply "pointer to
    char*" also known as char**. Therefore you can assign the array name
    "a" to the variable "strings" in the other code.

    On the other hand, if you need a true pointer that can be reassigned
    to point to different sets of strings, then something of the form:

    const astr1[] = "Alpha";
    ...
    const astrx[] = "Omega";
    const bstr1[] = "Alef";
    ...
    const bstrx[] = "Tav";
    const char* A[] = {astr1,...,astrx};
    const char* B[] = {bstr1,...,bstrx};
    const char **a = A;
    ...
    a = B;
    and anywhere in your code you can say
    strings = a;

    --
    Remove del for email
    Barry Schwarz, Sep 10, 2008
    #2
    1. Advertising

  3. Barry Schwarz ha scritto:

    > In this case, sizeof a will probably be 4 or 8.
    >
    >> I need it to be initialized as an array of strings, something like
    >>
    >> static const char **a = {"Alpha", "Beta", Charlie"};
    >>
    >> I know the number of strings and their maximum length, but I can't use a
    >> stack-allocated matrix for compatibility reasons with another piece of
    >> code, which simply defines a
    >>
    >> char** strings

    >
    >> to which the matrix has to be assigned to.

    >
    > There should be no problem "assigning the array" to this pointer.


    Actually there is. GCC warns that they're not compatible

    > On the other hand, if you need a true pointer that can be reassigned
    > to point to different sets of strings, then something of the form:
    >
    > const astr1[] = "Alpha";
    > ...
    > const astrx[] = "Omega";
    > const bstr1[] = "Alef";
    > ...
    > const bstrx[] = "Tav";
    > const char* A[] = {astr1,...,astrx};
    > const char* B[] = {bstr1,...,bstrx};
    > const char **a = A;
    > ...
    > a = B;
    > and anywhere in your code you can say
    > strings = a;
    >


    that's precisely what I'm going to do.

    Thanks

    AT
    Andrea Taverna (Tavs), Sep 10, 2008
    #3
  4. Ok, I've tried both ways, Barry's and Pete's. GCC still wars about
    compatibility, but it behaves correctly at run time, so the problem is set.

    Thank you :D

    AT
    Andrea Taverna (Tavs), Sep 10, 2008
    #4
  5. Andrea Taverna (Tavs)

    Guest

    Re: Initialization of a const matrix implemented aspointer-to-pointer

    Andrea Taverna (Tavs) wrote:
    > Barry Schwarz ha scritto:
    >
    > > In this case, sizeof a will probably be 4 or 8.
    > >
    > >> I need it to be initialized as an array of strings, something like
    > >>
    > >> static const char **a = {"Alpha", "Beta", Charlie"};
    > >>
    > >> I know the number of strings and their maximum length, but I can't use a
    > >> stack-allocated matrix for compatibility reasons with another piece of
    > >> code, which simply defines a
    > >>
    > >> char** strings

    > >
    > >> to which the matrix has to be assigned to.

    > >
    > > There should be no problem "assigning the array" to this pointer.

    >
    > Actually there is. GCC warns that they're not compatible


    That's because the second declaration should be

    const char** strings;

    If you don't have the power to change the declaration of 'strings',
    check the documentation of the other piece of code very carefully. Is
    that code going to attempt to write to those strings? If not, then it
    was a mistake on the designer's part to declare "strings" without
    using const. However, it's a mistake you can deal with by simply use a
    cast:

    strings = (char**)a;

    However, it if will be writing to the strings, then this is not an
    appropriate approach; the memory allocated for string literals is not
    necessarily writable. In that case, follow the example given below,
    but remove the word "const" wherever it appears:

    > > On the other hand, if you need a true pointer that can be reassigned
    > > to point to different sets of strings, then something of the form:
    > >
    > > const astr1[] = "Alpha";
    > > ...
    > > const astrx[] = "Omega";
    > > const bstr1[] = "Alef";
    > > ...
    > > const bstrx[] = "Tav";
    > > const char* A[] = {astr1,...,astrx};
    > > const char* B[] = {bstr1,...,bstrx};
    > > const char **a = A;
    > > ...
    > > a = B;
    > > and anywhere in your code you can say
    > > strings = a;
    , Sep 10, 2008
    #5
  6. "Andrea Taverna (Tavs)" <> writes:
    > Ok, I've tried both ways, Barry's and Pete's. GCC still wars about
    > compatibility, but it behaves correctly at run time, so the problem is
    > set.


    Don't be satisfied with code that produces warnings. Understand why
    the warning is being produced. Most of the time, you should fix the
    code so the warning goes away (note: adding a cast is rarely the right
    fix). In some cases, it makes sense to leave the code as it is and
    accept the warning, but most warnings indicate a real problem in the
    code, one that's likely to bite you later on.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Sep 10, 2008
    #6
  7. On Wed, 10 Sep 2008 16:16:23 +0200, "Andrea Taverna (Tavs)"
    <> wrote:

    >Barry Schwarz ha scritto:
    >
    >> In this case, sizeof a will probably be 4 or 8.
    >>
    >>> I need it to be initialized as an array of strings, something like
    >>>
    >>> static const char **a = {"Alpha", "Beta", Charlie"};
    >>>
    >>> I know the number of strings and their maximum length, but I can't use a
    >>> stack-allocated matrix for compatibility reasons with another piece of
    >>> code, which simply defines a
    >>>
    >>> char** strings

    >>
    >>> to which the matrix has to be assigned to.

    >>
    >> There should be no problem "assigning the array" to this pointer.

    >
    >Actually there is. GCC warns that they're not compatible


    I would be nice if you told us what the warning said. It is probably
    a complaint about loss of "const" so remove that qualifier from your
    code.

    >
    >> On the other hand, if you need a true pointer that can be reassigned
    >> to point to different sets of strings, then something of the form:
    >>
    >> const astr1[] = "Alpha";
    >> ...
    >> const astrx[] = "Omega";
    >> const bstr1[] = "Alef";
    >> ...
    >> const bstrx[] = "Tav";
    >> const char* A[] = {astr1,...,astrx};
    >> const char* B[] = {bstr1,...,bstrx};
    >> const char **a = A;
    >> ...
    >> a = B;
    >> and anywhere in your code you can say
    >> strings = a;
    >>

    >
    >that's precisely what I'm going to do.


    You will still have the const problem.

    --
    Remove del for email
    Barry Schwarz, Sep 11, 2008
    #7
  8. Initialization of const variables and C standards (Was: Initializationof a const matrix implemented as pointer-to-pointer)

    >I would be nice if you told us what the warning said. It is probably
    >a complaint about loss of "const" so remove that qualifier from your
    >code.

    Sure.
    I don't have the code at hand. More or less it says:
    "Warning: assignment between incompatible types"

    We fixed it by adjusting the declaration of the 'strings' field.
    Now they're both declared as const char**, and the problem would be solved.
    However I had to change the C standard from gnu89 (gcc's default) to
    c99, and with the following piece of code

    const char * a [] =
    {
    "alpha", "beta","charlie"
    };

    const struct my_structure my_s = (const struct my_structure)
    {
    .x = 10;
    .strings = a; // <- Error
    };

    and the latter standard it complains with the following message:
    "Error: initializer element is not constant"
    With gnu89 it compiles fine.
    Andrea Taverna (Tavs), Sep 19, 2008
    #8
  9. Re: Initialization of const variables and C standards (Was: Initialization of a const matrix implemented as pointer-to-pointer)

    On Fri, 19 Sep 2008 19:43:53 +0200, "Andrea Taverna (Tavs)"
    <> wrote:

    > >I would be nice if you told us what the warning said. It is probably
    > >a complaint about loss of "const" so remove that qualifier from your
    > >code.

    >Sure.
    >I don't have the code at hand. More or less it says:
    >"Warning: assignment between incompatible types"
    >
    >We fixed it by adjusting the declaration of the 'strings' field.
    >Now they're both declared as const char**, and the problem would be solved.
    >However I had to change the C standard from gnu89 (gcc's default) to
    >c99, and with the following piece of code
    >
    > const char * a [] =
    > {
    > "alpha", "beta","charlie"
    > };
    >
    > const struct my_structure my_s = (const struct my_structure)
    > {
    > .x = 10;
    > .strings = a; // <- Error
    > };
    >
    >and the latter standard it complains with the following message:
    >"Error: initializer element is not constant"
    >With gnu89 it compiles fine.


    If this code is outside of a function then my_s has static duration.
    Initialization of a static object must be a compile time constant
    since it occurs before any code is executed. The same restriction
    applies to compound literals outside of a function body (6.5.2.5-3).

    I can't help with gnu89 except to suggest that you specify the
    appropriate options to prohibit extensions.

    --
    Remove del for email
    Barry Schwarz, Sep 20, 2008
    #9
  10. Re: Initialization of const variables and C standards (Was: Initializationof a const matrix implemented as pointer-to-pointer)

    Barry Schwarz wrote:
    > If this code is outside of a function then my_s has static duration.
    > Initialization of a static object must be a compile time constant
    > since it occurs before any code is executed. The same restriction
    > applies to compound literals outside of a function body (6.5.2.5-3).
    >

    Uh, yes. I forgot to specify that the initialization takes place in the
    global scope (in a source file).

    Ehm, could I ask you how I should change the code to have the error
    fixed? I couldn't figure it out.


    thanks

    Andrea
    Andrea Taverna (Tavs), Sep 22, 2008
    #10
  11. Re: Initialization of const variables and C standards (Was: Initialization of a const matrix implemented as pointer-to-pointer)

    On Mon, 22 Sep 2008 13:59:22 +0200, "Andrea Taverna (Tavs)"
    <> wrote:

    >Uh, yes. I forgot to specify that the initialization takes place in the
    >global scope (in a source file).
    >
    >Ehm, could I ask you how I should change the code to have the error
    >fixed? I couldn't figure it out.


    To answer your question:

    If you can limit yourself to C99 systems, you might be able to
    use a compound literal.

    Otherwise, I think you need to cheat. Create an
    initialization function which you will call early in main. In this
    function, access the const structures using non-const pointers and
    initialize everything. Mark the structures volatile so the compiler
    doesn't optimize away any accesses thinking it knows what values are
    in the structures.

    The real question is why are the structures at file scope. If the
    answer is that they are used so frequently that you cannot afford to
    pass them (or their addresses) to all the different functions that
    need them then rethink how you access them. If you define the
    structures in main, you can create global pointers to const, assign
    values to the pointers in main, and have all the other functions
    access the structures through the pointers. Since the structures are
    no longer static, you have more flexibility in how you initialize
    them.

    --
    Remove del for email
    Barry Schwarz, Sep 23, 2008
    #11
  12. Re: Initialization of const variables and C standards

    Barry Schwarz ha scritto:

    > To answer your question:
    >
    > If you can limit yourself to C99 systems, you might be able to
    > use a compound literal.
    >


    If you mean this:
    my_s {
    .x = 10,
    .strings = {"alpha","beta","gamma"}
    }

    it doesn't work.
    it shows the same error
    "Error: initializer is not constant"
    And warns that the second assignment is between incompatible pointer
    types, I'd say that's because the braced expression in the example is
    expected to be a char [][3]...

    > The real question is why are the structures at file scope.

    The structure I have to initialize is needed as a global constant. Much
    like macro ones.
    What I want from the compiler is to have an array of strings, organized
    as an array of pointers to each string, stored in the ".rodata" segment
    of the program, together with the 'int x' field of the structure
    my_structure.
    I can't define the strings field as a matrix of chars because I may need
    to use the same structure to store a different number of string each time.
    I didn't put the initialization in main, and I'd like to keep it so, in
    order to avoid any dependency between this initialization code, which is
    used in a low-level module, and the rest of the code, which is higher-level.

    thanks for the attention

    Andrea
    Andrea Taverna (Tavs), Sep 23, 2008
    #12
  13. Re: Initialization of const variables and C standards

    "Andrea Taverna (Tavs)" <> writes:

    > Barry Schwarz ha scritto:
    >
    >> To answer your question:
    >>
    >> If you can limit yourself to C99 systems, you might be able to
    >> use a compound literal.
    >>

    >
    > If you mean this:
    > my_s {


    Did you have "my_s = {"? What you have posted look like a syntax error.

    > .x = 10,
    > .strings = {"alpha","beta","gamma"}
    > }


    No, a compound literal would look like this:

    .strings = (const char *[]){"alpha","beta","gamma"}

    (again, this is C99).

    --
    Ben.
    Ben Bacarisse, Sep 23, 2008
    #13
  14. Re: Initialization of const variables and C standards

    Ben Bacarisse ha scritto:

    >
    > Did you have "my_s = {"? What you have posted look like a syntax error.
    >

    Oh, yes, I meant

    const struct my_structure my_s = (const struct my_structure)
    {
    .x = 10;
    .strings = {"alpha","beta","gamma"}
    };


    > No, a compound literal would look like this:
    >
    > .strings = (const char *[]){"alpha","beta","gamma"}


    Gotcha. now it accept the assignment, but there's still that error:
    initializer element is not constant

    Andrea
    Andrea Taverna (Tavs), Sep 23, 2008
    #14
  15. Re: Initialization of const variables and C standards

    "Andrea Taverna (Tavs)" <> writes:

    > Ben Bacarisse ha scritto:

    <snip>
    >> No, a compound literal would look like this:
    >>
    >> .strings = (const char *[]){"alpha","beta","gamma"}

    >
    > Gotcha. now it accept the assignment, but there's still that error:
    > initializer element is not constant


    You'd better post a small example that shows the problem. On my
    system the above compiles silently. (BTW, that line is not,
    technically, an assignment -- it is part of an initialisation.)

    --
    Ben.
    Ben Bacarisse, Sep 24, 2008
    #15
  16. Re: Initialization of const variables and C standards

    Ben Bacarisse ha scritto:
    > You'd better post a small example that shows the problem. On my
    > system the above compiles silently.
    >


    struct my_structure
    {
    int x;
    const char ** strings;
    };

    const struct my_structure my_s = (const struct my_structure)
    {
    .x = 10,
    .strings = (const char *[]){"alpha","beta","charlie"}
    }; // <-error

    The compiler (gcc4.3.0-8 for Red Hat) says the error is on the last line

    > (BTW, that line is not,
    > technically, an assignment -- it is part of an initialisation.)

    Gotcha

    thanks

    Andrea
    Andrea Taverna (Tavs), Sep 24, 2008
    #16
  17. Re: Initialization of const variables and C standards

    "Andrea Taverna (Tavs)" <> writes:

    > Ben Bacarisse ha scritto:
    >> You'd better post a small example that shows the problem. On my
    >> system the above compiles silently.
    >>

    >
    > struct my_structure
    > {
    > int x;
    > const char ** strings;
    > };
    >
    > const struct my_structure my_s = (const struct my_structure)


    Just leave out this "top-level" compound literal.

    > {
    > .x = 10,
    > .strings = (const char *[]){"alpha","beta","charlie"}
    > }; // <-error


    I.e. write:

    const struct my_structure my_s = {
    .x = 10,
    .strings = (const char *[]){"alpha","beta","charlie"}
    };

    --
    Ben.
    Ben Bacarisse, Sep 24, 2008
    #17
  18. Re: Initialization of const variables and C standards

    Now it WORKS! thank you!

    Andrea
    Andrea Taverna (Tavs), Sep 24, 2008
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. coala
    Replies:
    3
    Views:
    370
    coala
    Sep 6, 2006
  2. coala
    Replies:
    1
    Views:
    587
    Victor Bazarov
    Sep 6, 2006
  3. Replies:
    5
    Views:
    1,178
  4. Javier
    Replies:
    2
    Views:
    558
    James Kanze
    Sep 4, 2007
  5. Disc Magnet
    Replies:
    1
    Views:
    623
    Ian Collins
    May 6, 2010
Loading...

Share This Page