Problem with pointer to array of structures

Discussion in 'C Programming' started by Timo, Feb 17, 2004.

  1. Timo

    Timo Guest

    I am trying to pass a pointer to an array of structures to function,
    but
    I have some problems. I am using MS Visual C++ 6.0, but I think
    this is more of a C-problem than Windows programming specific. Here
    is the relevant part of my code.

    typedef struct
    {
    int iControlID;
    char controlTxt[64];
    } CONTROL_TXT;

    void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt[]);

    void MyFunc(void)
    {
    static CONTROL_TXT ctrlTxts[] =
    {
    { 1, "text 1" },
    { 2, "text 2" },
    { 3, "text 3" },
    { 0, "" } // marks end of table
    };

    <clip>

    SetControlTxts(hDlg, &ctrlTxts[0]);
    }


    void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt[])
    {
    int i, id;
    char txt[64];

    for (i = 0; &ctrlTxt->iControlID != 0; i++)
    {
    id = &ctrlTxt->iControlID;
    strcpy(txt, &ctrlTxt->controlTxt);
    //strcpy(txt, (char*)ctrlTxt->controlTxt);
    //SetDlgItemText(hDlg, ctrlTxt->iControlID,
    ctrlTxt->controlTxt);
    SetDlgItemText(hDlg, id, txt);
    }

    return;

    }

    I get some compiler warnings. Function call "SetControlTxts(hDlg,
    &ctrlTxts[0]);
    ":
    warning C4047: 'function' : 'struct CONTROL_TXT ** ' differs in levels
    of indirection from 'struct CONTROL_TXT *'
    warning C4024: 'SetControlTxts' : different types for formal and
    actual parameter 2

    "id = &ctrlTxt->iControlID;":
    warning C4047: '=' : 'int ' differs in levels of indirection from 'int
    *'

    "strcpy(txt, &ctrlTxt->controlTxt);":
    warning C4047: 'function' : 'const char *' differs in levels of
    indirection from 'char (*)[64]'
    warning C4024: 'strcpy' : different types for formal and actual
    parameter 2

    Strcpy also causes access violation in Visual C++. However, I can get
    valid value of "id", the debugger shows it correctly.

    I also tried casting to char*:
    strcpy(txt, (char*)&ctrlTxt->controlTxt);
    but it also causes access violation.

    Any info what am I doing wrong here?

    Timo
     
    Timo, Feb 17, 2004
    #1
    1. Advertising

  2. Timo

    nrk Guest

    Timo wrote:

    > I am trying to pass a pointer to an array of structures to function,
    > but
    > I have some problems. I am using MS Visual C++ 6.0, but I think
    > this is more of a C-problem than Windows programming specific. Here
    > is the relevant part of my code.
    >
    > typedef struct
    > {
    > int iControlID;
    > char controlTxt[64];
    > } CONTROL_TXT;
    >
    > void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt[]);


    The second parameter here is a pointer-to-pointer-to CONTROL_TXT. IOW, this
    prototype is equivalent to:
    void SetControlTxts(HWND hDlg, CONTROL_TXT **ctrlTxt);

    However, what you're passing is essentially a pointer-to CONTROL_TXT (Search
    the group archives for Chris Torek's "The" rule to see why this is the
    case). So what you really want is either one of:
    void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt);
    or
    void SetControlTxts(HWND hDlg, CONTROL_TXT ctrlTxt[]);

    >
    > void MyFunc(void)
    > {
    > static CONTROL_TXT ctrlTxts[] =
    > {
    > { 1, "text 1" },
    > { 2, "text 2" },
    > { 3, "text 3" },
    > { 0, "" } // marks end of table
    > };
    >


    This declares ctrlTxts to be an array of CONTROL_TXT. When passed as a
    parameter to a function, it decays into a pointer to the first element of
    the array.

    > <clip>
    >
    > SetControlTxts(hDlg, &ctrlTxts[0]);


    This is unnecessary. You can simply write:
    SetControlTxts(hDlg, ctrlTxts);
    to get the same effect.

    > }
    >
    >
    > void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt[])


    Again, change this definition to match the prototype as shown above.

    > {
    > int i, id;
    > char txt[64];
    >
    > for (i = 0; &ctrlTxt->iControlID != 0; i++)


    -> binds closer than &. So what you're doing is equivalent to:
    &(ctrlTxt->iControlID) != 0

    Unfortunately, your choice of integer constant here is such that, the
    compiler thinks this is fine, even though this is quite clearly not what
    you want.

    Why not:
    for ( i = 0; ctrlTxt.iControlID != 0; i++ )
    ?
    Similar fixes can be applied to other such mistakes.

    > {
    > id = &ctrlTxt->iControlID;

    See above. However, here your compiler has a legitimate reason to complain.
    The rhs is clearly an address and lhs is an int. Hence the noise.

    > strcpy(txt, &ctrlTxt->controlTxt);

    See above.

    > //strcpy(txt, (char*)ctrlTxt->controlTxt);
    > //SetDlgItemText(hDlg, ctrlTxt->iControlID,
    > ctrlTxt->controlTxt);
    > SetDlgItemText(hDlg, id, txt);
    > }
    >
    > return;
    >
    > }
    >
    > I get some compiler warnings. Function call "SetControlTxts(hDlg,
    > &ctrlTxts[0]);
    > ":
    > warning C4047: 'function' : 'struct CONTROL_TXT ** ' differs in levels
    > of indirection from 'struct CONTROL_TXT *'
    > warning C4024: 'SetControlTxts' : different types for formal and
    > actual parameter 2
    >
    > "id = &ctrlTxt->iControlID;":
    > warning C4047: '=' : 'int ' differs in levels of indirection from 'int
    > *'
    >
    > "strcpy(txt, &ctrlTxt->controlTxt);":
    > warning C4047: 'function' : 'const char *' differs in levels of
    > indirection from 'char (*)[64]'
    > warning C4024: 'strcpy' : different types for formal and actual
    > parameter 2
    >


    All fine and excellent warnings. It's good that you've set your compiler's
    warning levels high enough to catch these mistakes.

    > Strcpy also causes access violation in Visual C++. However, I can get
    > valid value of "id", the debugger shows it correctly.
    >
    > I also tried casting to char*:
    > strcpy(txt, (char*)&ctrlTxt->controlTxt);
    > but it also causes access violation.
    >


    This tells you that you are not yet strong enough in the language to be
    using dubious constructs such as casts. Never ever use a cast to silence
    the compiler unless you're absolutely 200% certain that you know what
    you're doing. Casts do *not* fix incorrect code, and often prevent you
    from getting useful diagnostics from the compiler.

    -nrk.

    > Any info what am I doing wrong here?
    >
    > Timo


    --
    Remove devnull for email
     
    nrk, Feb 17, 2004
    #2
    1. Advertising

  3. Timo

    pete Guest

    Timo wrote:

    > a pointer to an array of structures


    > CONTROL_TXT *ctrlTxt[]


    That's an array of pointers to structures.

    You want:
    CONTROL_TXT *ctrlTxt

    Make the call like this:
    SetControlTxts(hDlg, ctrlTxts);

    Access members like this:
    ctrlTxt.iControlID

    --
    pete
     
    pete, Feb 17, 2004
    #3
  4. Timo

    Timo Guest

    pete <> wrote in message news:<>...
    > Timo wrote:
    >
    > > a pointer to an array of structures

    >
    > > CONTROL_TXT *ctrlTxt[]

    >
    > That's an array of pointers to structures.
    >
    > You want:
    > CONTROL_TXT *ctrlTxt
    >
    > Make the call like this:
    > SetControlTxts(hDlg, ctrlTxts);
    >
    > Access members like this:
    > ctrlTxt.iControlID


    After I had posted my original article, I tried changing my codes to
    this:

    void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt)
    {

    CONTROL_TXT *ctrlTxtTmp;

    ctrlTxtTmp = ctrlTxt;

    for (; ctrlTxtTmp->iControlID != 0; ctrlTxtTmp++)
    {
    SetDlgItemText(hDlg, ctrlTxtTmp->iControlID,
    (char*)&ctrlTxtTmp->controlTxt);
    }

    return;

    }

    Works perfectly, no compiler warning. I have been writing with C
    several
    years, but usually I try to avoid complicated pointer stuff such as
    this.

    So, when passing array of structures, the function should rather take
    pointer to
    struct as parameter, not an array of pointers to structs? Seems little
    complicated, I have to try to check the rule the previous poster
    mentioned.

    Timo
     
    Timo, Feb 18, 2004
    #4
  5. Timo

    nrk Guest

    Timo wrote:

    > pete <> wrote in message
    > news:<>...
    >> Timo wrote:
    >>
    >> > a pointer to an array of structures

    >>
    >> > CONTROL_TXT *ctrlTxt[]

    >>
    >> That's an array of pointers to structures.
    >>
    >> You want:
    >> CONTROL_TXT *ctrlTxt
    >>
    >> Make the call like this:
    >> SetControlTxts(hDlg, ctrlTxts);
    >>
    >> Access members like this:
    >> ctrlTxt.iControlID

    >
    > After I had posted my original article, I tried changing my codes to
    > this:
    >
    > void SetControlTxts(HWND hDlg, CONTROL_TXT *ctrlTxt)
    > {
    >
    > CONTROL_TXT *ctrlTxtTmp;
    >
    > ctrlTxtTmp = ctrlTxt;
    >
    > for (; ctrlTxtTmp->iControlID != 0; ctrlTxtTmp++)
    > {
    > SetDlgItemText(hDlg, ctrlTxtTmp->iControlID,
    > (char*)&ctrlTxtTmp->controlTxt);
    > }
    >
    > return;
    >
    > }
    >
    > Works perfectly, no compiler warning. I have been writing with C
    > several
    > years, but usually I try to avoid complicated pointer stuff such as
    > this.
    >
    > So, when passing array of structures, the function should rather take
    > pointer to
    > struct as parameter, not an array of pointers to structs? Seems little
    > complicated, I have to try to check the rule the previous poster
    > mentioned.
    >


    Read (atleast) this section of the FAQ:
    http://www.eskimo.com/~scs/C-faq/s6.html

    Chris Torek's "The" rule is explained here:
    http://web.torek.net/torek/c/pa.html

    You might also find the rest of the FAQ useful:
    http://www.eskimo.com/~scs/C-faq/top.html

    -nrk.

    > Timo


    --
    Remove devnull for email
     
    nrk, Feb 18, 2004
    #5
  6. Timo

    pete Guest

    Timo wrote:

    > Works perfectly, no compiler warning. I have been writing with C
    > several
    > years, but usually I try to avoid complicated pointer stuff such as
    > this.
    >
    > So, when passing array of structures,
    > the function should rather take pointer to
    > struct as parameter, not an array of pointers to structs? Seems little
    > complicated, I have to try to check the rule the previous poster
    > mentioned.


    Whenever you pass *any* array name as an argument,
    the name of the array is converted
    to a pointer to it's first element.

    I prefer
    void func(int *array);
    over
    void func(int array[]);
    Even though they mean exactly the same thing,
    the true type of the parameter, is a pointer.

    --
    pete
     
    pete, Feb 18, 2004
    #6
  7. Timo

    CBFalconer Guest

    pete wrote:
    >

    .... snip ...
    >
    > Whenever you pass *any* array name as an argument, the name of
    > the array is converted to a pointer to it's first element.
    >
    > I prefer
    > void func(int *array);
    > over
    > void func(int array[]);
    >
    > Even though they mean exactly the same thing,
    > the true type of the parameter, is a pointer.


    However func may then be called with a pointer to an array[1] of
    int, or with a void*, or with the address of some individual int.
    So it makes more sense to make the requisite parameter form
    explicit. Thus I would use:

    void func(int *i); /* pointer to an individual integer */
    void func(int a[]); /* pointer to an actual array, but .. */
    void func(int a[], size_t sz); /* an actual array, safer */

    of course, arrays may have internal end markers, such as strings,
    but such markers do not indicate maximum capacity.

    The point of the above is that the user of func has an idea of its
    requirements from the prototype alone.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Feb 18, 2004
    #7
    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. Frank Münnich

    Pointer to an array of structures

    Frank Münnich, Jul 11, 2003, in forum: C Programming
    Replies:
    9
    Views:
    41,543
    prati
    Aug 2, 2012
  2. tweak
    Replies:
    14
    Views:
    2,789
    Eric Sosman
    Jun 11, 2004
  3. mrhicks
    Replies:
    1
    Views:
    708
    Eric Sosman
    Jul 16, 2004
  4. Alfonso Morra
    Replies:
    11
    Views:
    722
    Emmanuel Delahaye
    Sep 24, 2005
  5. , India

    pointer to an array vs pointer to pointer

    , India, Sep 20, 2011, in forum: C Programming
    Replies:
    5
    Views:
    458
    James Kuyper
    Sep 23, 2011
Loading...

Share This Page