Generically accessing members of a struct.

Discussion in 'C Programming' started by david.chanters@googlemail.com, May 23, 2009.

  1. Guest

    Hello all,

    I am curious to know some best practise techniques when traversing/
    accessing struct members. At the moment I have the following
    declarations:

    typedef struct PayInfo
    {
    char *name;
    char *address;
    int employeeNum;
    int internalId;
    PayInfo *pinfo;
    } PayInfo;

    // Initialise an instance of PayInfo here...

    Which acts as a linked list, that's fine. I then, have several
    functions which look like this:

    char *GetEmpname(int number)
    {
    PayInfo pi;
    pi = MyInitializedPayInfo->next;

    while(pi != NULL && pi->employeeNum != number)
    pi = pi->next;

    if (pi != NULL)
    return pi->name;

    return NULL;
    }

    That's just one example, I also have:

    char *GetAddress(int number);
    int GetInternalId(int number);

    Which do the exact same thing as GetEmpname() but returns different
    data.

    My thinking is that this is inefficient, especially if/when the struct
    has more members added to it. My thoughts are to have a enum which is
    passed around, so I could say something like:

    GetGenericMember(PayInfo *pi, enum flags)

    Where this enum would list which attribute I want returned. Is this a
    good idea? Are there some other way of doing this I am not thinking
    about, or am I just missing the point, and instead should just have
    one function per data member I want returned?

    Suggestions welcome, and thanks in advance.

    David.
    , May 23, 2009
    #1
    1. Advertising

  2. Eric Sosman Guest

    wrote:
    > Hello all,
    >
    > I am curious to know some best practise techniques when traversing/
    > accessing struct members. At the moment I have the following
    > declarations:
    >
    > typedef struct PayInfo
    > {
    > char *name;
    > char *address;
    > int employeeNum;
    > int internalId;
    > PayInfo *pinfo;


    This looks bogus. Did you mean `struct PayInfo *next;'?

    > } PayInfo;
    >
    > // Initialise an instance of PayInfo here...
    >
    > Which acts as a linked list, that's fine. I then, have several
    > functions which look like this:
    >
    > char *GetEmpname(int number)
    > {
    > PayInfo pi;
    > pi = MyInitializedPayInfo->next;
    >
    > while(pi != NULL && pi->employeeNum != number)
    > pi = pi->next;


    No `next' field in the struct as you've shown it ...

    > if (pi != NULL)
    > return pi->name;
    >
    > return NULL;
    > }
    >
    > That's just one example, I also have:
    >
    > char *GetAddress(int number);
    > int GetInternalId(int number);
    >
    > Which do the exact same thing as GetEmpname() but returns different
    > data.
    >
    > My thinking is that this is inefficient, especially if/when the struct
    > has more members added to it. My thoughts are to have a enum which is
    > passed around, so I could say something like:
    >
    > GetGenericMember(PayInfo *pi, enum flags)
    >
    > Where this enum would list which attribute I want returned. Is this a
    > good idea? Are there some other way of doing this I am not thinking
    > about, or am I just missing the point, and instead should just have
    > one function per data member I want returned?


    You should probably write a function that locates
    the whole struct rather than just one field:

    PayInfo *GetEmpPayInfo(int number) {
    PayInfo *pi;
    pi = MyInitializedPayInfo->next;
    for ( ; pi != NULL; pi = pi->next) {
    if (pi->employeeNum == number)
    break;
    }
    return pi;
    }

    Now you can write all the "get attribute" functions as
    simple wrappers:

    char *GetEmpName(int number) {
    PayInfo pi = GetEmpPayInfo(number);
    return pi == NULL ? NULL : pi->name;
    }

    .... or if you prefer you can call GetEmpPayInfo() directly
    from your main-line code.

    The enum approach can be viable, but one difficulty
    it runs into is that a C function can return only one data
    type. You can't have a function that sometimes returns an
    `int' and sometimes returns a `char*'. You could return a
    union that can hold any of these types, but then the caller
    would have to know which of the union's members to look at.
    It *does* know that, of course (if it asked for the name,
    it's not going to expect to get a `double' back), but it
    seems to me a trifle safer and certainly more straightforward
    to use other means: Call GetEmpName(), or call GetEmpPayInfo()
    and refer to the element of interest.

    --
    Eric Sosman
    lid
    Eric Sosman, May 23, 2009
    #2
    1. Advertising

  3. BartC Guest

    <> wrote in message
    news:...
    > Hello all,
    >
    > I am curious to know some best practise techniques when traversing/
    > accessing struct members. At the moment I have the following
    > declarations:
    >
    > typedef struct PayInfo
    > {

    ....
    > } PayInfo;


    > char *GetEmpname(int number)
    > {
    > PayInfo pi;
    > pi = MyInitializedPayInfo->next;
    >
    > while(pi != NULL && pi->employeeNum != number)
    > pi = pi->next;
    > if (pi != NULL)
    > return pi->name;
    > return NULL;
    > }
    >
    > That's just one example, I also have:
    >
    > char *GetAddress(int number);
    > int GetInternalId(int number);
    >
    > Which do the exact same thing as GetEmpname() but returns different
    > data.
    >
    > My thinking is that this is inefficient, especially if/when the struct
    > has more members added to it. My thoughts are to have a enum which is
    > passed around, so I could say something like:
    >
    > GetGenericMember(PayInfo *pi, enum flags)
    >
    > Where this enum would list which attribute I want returned. Is this a
    > good idea? Are there some other way of doing this I am not thinking
    > about, or am I just missing the point, and instead should just have
    > one function per data member I want returned?


    Somehow creating a separate function to access a field, or to select a field
    using an index, doesn't sound right.

    Normally you'd use "." or "->" to select fields, so you really need a
    function to select the /entry/ using the employee number or whichever key
    you wish to use:

    x = Findempnum(1199)->name;
    Findempnum(1200)->address = ".....";

    This allows you to read or write any field. And to select on another key
    just use a different function to Findempnum(). Also adding/removing fields
    requires less maintenance.

    --
    Bart
    BartC, May 23, 2009
    #3
  4. Guest

    On 23 May, 20:05, Eric Sosman <> wrote:
    > wrote:
    > > Hello all,

    >
    > > I am curious to know some best practise techniques when traversing/
    > > accessing struct members.  At the moment I have the following
    > > declarations:

    >
    > > typedef struct PayInfo
    > > {
    > >     char *name;
    > >     char *address;
    > >     int employeeNum;
    > >     int internalId;
    > >     PayInfo *pinfo;

    >
    >      This looks bogus.  Did you mean `struct PayInfo *next;'?
    >
    > > } PayInfo;

    >
    > > // Initialise an instance of PayInfo here...

    >
    > > Which acts as a linked list, that's fine.  I then, have several
    > > functions which look like this:

    >
    > > char *GetEmpname(int number)
    > > {
    > >     PayInfo pi;
    > >     pi = MyInitializedPayInfo->next;

    >
    > >     while(pi != NULL && pi->employeeNum != number)
    > >         pi = pi->next;

    >
    >      No `next' field in the struct as you've shown it ...
    >
    >
    >
    >
    >
    > >     if (pi != NULL)
    > >         return pi->name;

    >
    > >     return NULL;
    > > }

    >
    > > That's just one example, I also have:

    >
    > > char *GetAddress(int number);
    > > int GetInternalId(int number);

    >
    > > Which do the exact same thing as GetEmpname() but returns different
    > > data.

    >
    > > My thinking is that this is inefficient, especially if/when the struct
    > > has more members added to it.  My thoughts are to have a enum which is
    > > passed around, so I could say something like:

    >
    > > GetGenericMember(PayInfo *pi, enum flags)

    >
    > > Where this enum would list which attribute I want returned.  Is this a
    > > good idea?  Are there some other way of doing this I am not thinking
    > > about, or am I just missing the point, and instead should just have
    > > one function per data member I want returned?

    >
    >      You should probably write a function that locates
    > the whole struct rather than just one field:
    >
    >         PayInfo *GetEmpPayInfo(int number) {
    >             PayInfo *pi;
    >             pi = MyInitializedPayInfo->next;
    >             for (  ;  pi != NULL;  pi = pi->next) {
    >                 if (pi->employeeNum == number)
    >                     break;
    >             }
    >             return pi;
    >         }
    >
    > Now you can write all the "get attribute" functions as
    > simple wrappers:
    >
    >         char *GetEmpName(int number) {
    >             PayInfo pi = GetEmpPayInfo(number);
    >             return pi == NULL ? NULL : pi->name;
    >         }
    >
    > ... or if you prefer you can call GetEmpPayInfo() directly
    > from your main-line code.
    >
    >      The enum approach can be viable, but one difficulty
    > it runs into is that a C function can return only one data
    > type.  You can't have a function that sometimes returns an
    > `int' and sometimes returns a `char*'.  You could return a
    > union that can hold any of these types, but then the caller
    > would have to know which of the union's members to look at.
    > It *does* know that, of course (if it asked for the name,
    > it's not going to expect to get a `double' back), but it
    > seems to me a trifle safer and certainly more straightforward
    > to use other means: Call GetEmpName(), or call GetEmpPayInfo()
    > and refer to the element of interest.


    I'd endorse what Eric says. It seems a bit too abstract to be trying
    to access each member by the same function - particularly as you are
    not going to be doing the same sort of things with, say, name, as you
    are going to be doing with employeeNum.

    It's good that you are able to think abstractly and that you are
    considering this sort of issue. But I think in this particular case
    your solution is more abstract than is justified.

    Paul.
    , May 24, 2009
    #4
    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. SN
    Replies:
    4
    Views:
    386
    Tony Dahlman
    Nov 13, 2003
  2. VisionSet

    generics - overriding generically

    VisionSet, Jan 8, 2006, in forum: Java
    Replies:
    14
    Views:
    750
    Oliver Wong
    Jan 9, 2006
  3. Replies:
    0
    Views:
    510
  4. call_me_anything
    Replies:
    4
    Views:
    459
    Pete Becker
    Sep 30, 2007
  5. John Reye
    Replies:
    28
    Views:
    1,361
    Tim Rentsch
    May 8, 2012
Loading...

Share This Page