Generically accessing members of a struct.

D

david.chanters

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.
 
E

Eric Sosman

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.
 
B

BartC

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.
 
G

gw7rib

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






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













     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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,816
Latest member
SapanaCarpetStudio

Latest Threads

Top