views:

422

answers:

5

How should I write my code to example a specific array index of an array that happens to be a member of a structure? The following code is giving me problems.

// main.c

void clean_buffers(void); // prototype

struct DEV_STATUS {
    unsigned char ADDR;
    unsigned char DEV_HAS_DATA;
    unsigned char ETH_HAS_DATA;
    unsigned char DATA[20];
};

struct DEV_STATUS g_cmdQueue[60] = {0};

void main(void) {

    clean_buffers();

    while (1) {
        ;// MCU tasks        
    }
}

void clean_buffers(void) {
    unsigned char theCount = 0;
    byte queIdx;
    for (queIdx = 0; queIdx < 59; queIdx++) {
        struct DEV_STATUS *p_struct;
        unsigned char *p_data;
        p_struct = &g_cmdQueue[queIdx];
        p_data = &p_struct->DATA;
        p_struct->ADDR = 0;
        p_struct->DEV_HAS_DATA = 0;
        p_struct->ETH_HAS_DATA = 0;
        theCount = 0;
        while(*(p_data+theCount) != 0) {
            *(p_data+(theCount++)) = 0;
        }
    }    
} // EOF main.c

I get a compiler error "struct/union member expected" on the following line:

p_data = &p_struct->DATA;

How should I write a pointer if I was to access, for example, the specific value of structure member DATA[3] ? I'm confused, I thought that as p_data = &p_struct->DATA; is defined, I should be able to get it by using *(pdata+3) but I guess I'm missing something.

+3  A: 

Lose the & in p_data = &p_struct->DATA;

p_struct is already a pointer. Afterwards, use p_data[] to access your array.

jldupont
Thank you, for whatever reason it never struck me to use p_data[] to access the array. I wondered if the ampersand was superfluous, thanks for the confirmation.
Nate
Johannes Schaub - litb
+2  A: 

What you should write is one of two things:

p_data = p_struct->DATA; // DATA is the address of the first element.

OR

p_data = &p_struct->DATA[0]; // taking the address of the first element.
AraK
+1  A: 

Simply remove the & at the beginning, like this:

p_data = p_struct->DATA;

That is special sintax for arrays (remember they are passed always as reference) and it is equivalent to:

p_data = &p_struct->DATA[0];

And yes, now you can use *(pdata+3)

Hope it helps.

Seth Illgard
A: 
pmg
AndreyT
+2  A: 

Are you sure you are compiling the same code you posted here?

If your compiler complains at this line

p_data = &p_struct->DATA;

with a "struct/union member expected" message, your compiler is probably broken.

Note, that &p_struct->DATA is a perfectly valid expression in C. There's absolutely no problems with this expression by itself.

The problem here is just that this is not what you need in your case. &p_struct->DATA returns a pointer to the entire array 'DATA', i.e a pointer of type unsigned char (*)[20]. You are trying to assign this value to a pointer of type unsigned char *. This is illegal in C, since the types are completely different, but traditionally C compilers responded to it with a mere "type mismatch" warning and performed an implicit conversion (which, BTW, means that your original code, albeit "dirty", should still work as intended).

Even if some compiler decides to flag this mismatch as an error (which is fine), it still should not complain about any problems of "struct/union member expected" kind. There's no such problems here.

P.S. As other already said, what you really need is p_data = &p_struct->DATA[0], but that still does not explain your compiler's strange behavior. Could it be that 'DATA' is a macro defined somewhere before the 'clean_buffers' definition?

Added 10/19/2009: Nate, in your code you access your array using an index theCount. Since you are using the index access anyway, there's really no reason to even create the pointer you are trying to create. The code will work perfectly fine without any additional pointer, just acess the DATA field directly

theCount = 0;
while (p_struct->DATA[theCount] != 0) {
  p_struct->DATA[theCount++] = 0;

(I'd probably use a for cycle here).

If you really insist on creating this pointer and still using the index access, the code should look something like the following (the others already suggested that more than once)

p_data = p_struct->DATA; /* or &p_struct->DATA[0] */
...
theCount = 0;
while (p_data[theCount] != 0) {
  p_data[theCount++] = 0;

Moreover, you can opt for a more "exotic" variant :)

unsigned char (*p_data)[20]; /* <- note: declared differently */
...
p_data = &p_struct->DATA; /* <- note: your original version */
...
theCount = 0;
while ((*p_data)[theCount] != 0) {
  (*p_data)[theCount++] = 0;

However, returning to a unsigned char *p_data version, since you create that pointer, it might make more sense to use a "sliding pointer" technique instead of using index access

unsigned char *p_data;
...
p_data = p_struct->DATA; /* or &p_struct->DATA[0] */
...
while (*p_data != 0) {
  *p_data++ = 0;

As always, it is all a matter of personal preference. Of course, nothing of this will work until you get rid of that interference from the macro.

AndreyT
Loadmaster
@Loadmaster: That's exactly what I'm saying in my post. Have you actually read it? The point of my post is to explain the original poster what his original code really means. And to point out that the error message is misleading at best. (As for what the OP wants - that's for the OP to decide and to tell.)
AndreyT
Johannes Schaub - litb
@AndreyT, this is actually the real information that I was looking for. Thank you for taking the time to explain everything. Your answer actually makes the most sense. You were actually correct, it is a macro used in a header written by a co-worker that is included in my main.c and not in another module (where it compiles correctly.) So if the implicit conversion works with my dirty code, how would I rewrite it to be 'clean' and explicit?
Nate
@Nate: Please, see what I added to my response.
AndreyT
Absolutely excellent. The "exotic" pointer example was the one that was escaping me. I appreciate you taking the time to show the many different ways to do the same task. It makes me a better programmer and allows me to comprehend the code of others. Thanks again.
Nate