Thread: compiler error: left of ' ' must have struct/union type

  1. #1
    Registered User
    Join Date
    Nov 2015
    Posts
    72

    compiler error: left of ' ' must have struct/union type

    I've been experimenting with different types of "queues" of fixed size which I have shown in a previous thread. Now however, I want to design a proper queue of unspecified length that allocates and deallocates memory as members are pushed into the queue at the end or popped out of the queue at the start of it.


    So inside each member of the pixelQueue I put a struct named Pixel that contains the all the data I need for that member and a pointer that is pointing to the next member of the queue.


    The code that handles this part of the program looks like so:


    Code:
    ...
    
    
    bool **queuedArray;
    int nRows, nCols;
    char *inputRow;
    
    
    typedef struct Pixel {
        int x;
        int y;
    } Pixel;
    
    
    ...
    
    
    typedef struct pixelQueue {
        Pixel element;
        struct pixelQueue *nextMember;
    } pixelQueue;
    int queueLength;
    pixelQueue *firstMember = NULL, *lastMember = NULL;
    
    
    int queueLength;
    void pushQueue(Pixel element);
    Pixel popQueue();
    
    
    ...
    
    
    int main(int argc, const char * argv[]) {
        if(scanf("%d%d", &nRows, &nCols) == 2) {
            allocateMemory();
    
    
            ...
        ...
        
        free(queuedArray[0]);
        ...
        free(queuedArray);
    
    
        return 0;
    }
    
    
    void allocateMemory() {
        int NROWS = nRows + 2, NCOLS = nCols + 2;
        
        ...
        
        queuedArray = malloc(NROWS * sizeof *queuedArray);
        queuedArray[0] = calloc(NROWS * NCOLS, sizeof **queuedArray);
        
        for(int i = 1; i < NROWS; ++i) {
            ...
            queuedArray[i] = queuedArray[i - 1] + NCOLS;
        }
    }
    
    
    ...
    ...
    ...
    
    
    void pushQueue(element) {
       if(queuedArray[element.x][element.y])
           return;
       if(firstMember == NULL) {
          firstMember = malloc(sizeof *firstMember);
          lastMember = firstMember;
          queueLength = 0;
       } else {
          lastMember->nextMember = malloc(sizeof *firstMember);
          lastMember = lastMember->nextMember;
       }
       lastMember->element.x = element.x;
       lastMember->element.y = element.y;
       lastMember->nextMember = NULL;
       ++queueLength;
    }
    
    
    Pixel popQueue() {
       Pixel element;
       if(firstMember == NULL) {
          printf("Empty queue, popQueue() abuse!\n");
          element.x = -1;
          element.y = -1;
          return element;
       }
       element.x = *firstMember.element.x;
       element.y = *firstMember.element.y;
       if(firstMember == lastMember) {
          free(firstMember);
          firstMember = NULL;
          queueLength = 0;
       } else {
          pixelQueue *interimCell;
          interimCell = firstMember.nextMember;
          free(firstMember);
          firstMember = interimCell;
          --queueLength;
       }
       return element;
    }
    
    
    ...

    The problem however is that I get the errors


    Code:
    traceCoastLine2c.c(...) : error C2224: left of '.x' must have struct/union type
    traceCoastLine2c.c(...) : error C2224: left of '.y' must have struct/union type

    at line 72,82 and 83. What's even stranger is that in the previous version of the program before I attempted implementing a dynamic queue the compiler never complained about line 72.


    So what is wrong and what is the correct way of managing this?

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    In pushQueue, you haven't given a type for element. If it compiles like that, then it will default to an int, which is causing the problem. Presumably it's a Pixel, which then shouldn't give a problem.
    Code:
    //In popQueue, these:
       element.x = *firstMember.element.x;
       element.y = *firstMember.element.y;
    //should be
       element.x = firstMember->element.x;
       element.y = firstMember->element.y;
    
    //And this:
         interimCell = firstMember.nextMember;
    //should be
         interimCell = firstMember->nextMember;
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Nov 2015
    Posts
    72
    I really feel like an idiot now, thank you, it works!

    So changing from
    Code:
    void pushQueue(element) {
    ...
    }
    to
    Code:
    void pushQueue(Pixel element) {
    ...
    }
    did the trick. Something else that I've been unsure about is the safety of passing around whole structs:

    Code:
    element = firstMember->coordinate;
    That way only the struct as a whole will be passed I figured and not the values of the members of the struct which is why I instead did:
    Code:
    element.x = firstMember->coordinate.x;
    element.y = firstMember->coordinate.y;
    But it turns out that both ways work equally fine. I don't know whether this is to be taken for granted in every developer environment though.

    However, switching from fixed size queues to dynamic queues dropped the performance from 0.06s to 0.08s, so this was a terrible move on my side.

    Perhaps using fixed size array may improve performance further. If I know that the maximum size is 1000 x 1000 elements, then I could allocate a worldArray[1002][1002] at the beginning instead of doing dynamic mallocs.

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Quote Originally Posted by bot View Post
    I really feel like an idiot now, thank you, it works!
    Full warnings on gcc may have helped. Full warnings require -Wall -W -pedantic (-W is a synonym for -Wextra)

    Quote Originally Posted by bot View Post
    switching from fixed size queues to dynamic queues dropped the performance from 0.06s to 0.08s, so this was a terrible move on my side.
    It's a tradeoff. Dynamic allocation is probably always slower, but allows input of any size (up to available memory). You can pretty much get the best of both worlds by making your queue grow in chunks instead of for every element.
    Code:
    typedef struct Queue {
        int size, used;
        int front, back;
        Pixel *a;
    } Queue;
    
    Queue q;
    
    void initQueue(int initial_size) {
        q.a = malloc(initial_size * sizeof *q.a);
        if (!q.a) {perror("initQueue"); exit(EXIT_FAILURE);}
        q.size = initial_size;
        q.used = q.front = q.back = 0;
    }
    
    void pushQueue(Pixel elem) {
        if (q.used == q.size) {
            q.size *= 2; // double array size (or whatever)
            q.a = realloc(q.a, q.size * sizeof *q.a);
            if (!q.a) {perror("Queue overflow"); exit(EXIT_FAILURE);}
        }
        q.a[q.back] = elem;
        q.back = (q.back + 1) % q.size;
        q.used++;
    }
    
    Pixel popQueue() {
        if (q.used == 0) {
            fprintf(stderr, "Queue underflow\n");
            exit(EXIT_FAILURE);
        }
        int i = q.front;
        q.front = (q.front + 1) % q.size;
        q.used--;
        return q.a[i];
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Nov 2015
    Posts
    72
    Interesting, so it isn't that the dynamically allocated memory itself is slower than "statically" allocated memory at the beginning of the program, but the calls to malloc(), calloc() and realloc() that lowers performance it appears.

    I didn't know about realloc(), perhaps it is better to use malloc and have separate blocks that each can keep a specified number of queue members after all. Because I cannot see how you partially deallocate parts of a whole block (that is incrementally increased by the realloc() function) once those parts are no longer needed. I see no call to free() in the popQueue() function.

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Unless the program is meant to operate over a long period of time (like days), then it's often not useful to free the memory. The program will be done soon anyway, so the queue will grow to the required size and stay there until the program terminates. You could of course add a "free" to popQueue, but chances are that if the queue grew to a certain size in this program, then it may grow back to that size again, so you'll just realloc it again.

    If allocated memory is not being used, it doesn't really take up space in ram anyway. It will just sit in the swap partition. And "freeing" memory often doesn't actually return it to the OS anyway, unless it's a particularly large amount of memory. The system often leaves the memory allocated to your process so that it can be more quickly reused later. (There are essentially at least two layers of allocated memory, that which the OS considers to be allocated to you and that which the malloc system considers to be allocated to you.)

    It would be much more complicated to malloc a bunch of separate blocks, although that strategy is certainly used in more sophisticated data structures.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #7
    Registered User
    Join Date
    Nov 2015
    Posts
    72
    But if the program doesn't clean up after itself, won't the allocated memory stay allocated even after the program terminates? I have a (biological) memory that memory that wasn't freed will remain allocated until next reboot if it isn't taken care of correctly in the binary. Perhaps this is a quirk in Windows while being a non issue in *x environments.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. error: invalid use of undefined type ‘struct tms’
    By DevZero in forum C Programming
    Replies: 1
    Last Post: 07-16-2017, 07:17 PM
  2. C compiler reads from right to left or left to right?
    By ajishgopalr in forum C Programming
    Replies: 12
    Last Post: 07-16-2011, 08:12 PM
  3. Replies: 10
    Last Post: 03-08-2010, 12:20 AM
  4. vector - left of .push_back must have class/struct/union type
    By patricio2626 in forum C++ Programming
    Replies: 5
    Last Post: 11-18-2006, 04:37 PM
  5. Replies: 0
    Last Post: 11-29-2002, 10:24 PM

Tags for this Thread