Jasmine
Jasmine

Reputation: 323

Common C issue I cannot figure out: request for member in something not a structure or union

So I've made a struct to hold information about a Client. I get the compiler error stated as above in the title. I'm still learning pointers so bear with me if I state anything incorrect. From what I'm aware, my typedef has a pointer to an instance of Client. Which means I would need to use -> instead of . for fields of Client. But that didn't work either, I would get the error of dereferencing to incomplete type. Any guidance or help would be great!

Client.h

#ifndef CLIENT_H
#define CLIENT_H

typedef struct client_tag *Client;

#endif

Client.c

#include "client.h"


struct client_tag {
    char id[5];
    char name[30];
    char email[30];
    char phoneNum[15];
};

The following file reads client information from a file and assigns them to variables:

#include "client.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    Client client1 = malloc(sizeof(Client));
    FILE *fp;
    ListType clientList;

    fp = fopen("clients.txt", "r");

    int lineSize = 200;
    char* line = malloc(lineSize);
    char* line2 = malloc(lineSize);
    char* line3 = malloc(lineSize);
    char* line4 = malloc(lineSize); 


    while (fgets(line, lineSize, fp) != NULL) { 
        strcpy(client1.id, line);
        strcpy(client1.name, fgets(line2, lineSize, fp));
        strcpy(client1.email, fgets(line3, lineSize, fp));
        strcpy(client1.phoneNum, fgets(line4, lineSize, fp));

        push(clientList, (void*)&client1);

        printf("ID: %s", line);
        printf("Name: %s", line2);
        printf("Email: %s", line3);
        printf("Phone Number: %s\n", line4);

        free(line);
        free(line2);
        free(line3);
        free(line4);

        line = malloc(lineSize);
        line2 = malloc(lineSize);
        line3 = malloc(lineSize);
        line4 = malloc(lineSize);

    }

}

Here is the error I get:

    clientDriver.c: In function ‘main’:
clientDriver.c:23:17: error: request for member ‘id’ in something not a structure or union
   strcpy(client1.id, line);
                ^
clientDriver.c:24:17: error: request for member ‘name’ in something not a structure or union
   strcpy(client1.name, fgets(line2, lineSize, fp));
                ^
clientDriver.c:25:17: error: request for member ‘email’ in something not a structure or union
   strcpy(client1.email, fgets(line3, lineSize, fp));
                ^
clientDriver.c:26:17: error: request for member ‘phoneNum’ in something not a structure or union
   strcpy(client1.phoneNum, fgets(line4, lineSize, fp));

Upvotes: 0

Views: 76

Answers (2)

Mobius
Mobius

Reputation: 2896

I believe the problem is that you can't used fields on a client_tag or client_tag * if you don't have the declaration for client_tag in your header file.

My recommendation would be to move the struct declaration for client_tag from client.c to client.h

Based on the above instructions, The following code compiles and runs

client.h

#ifndef CLIENT_H
#define CLIENT_H

struct client_tag {
    char id[5];
    char name[30];
    char email[30];
    char phoneNum[15];
};

typedef struct client_tag *Client;

#endif

main.c

#include "client.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Minimal list implementation
 * Based on functions in your program
 */
typedef struct {
  unsigned length;
  size_t allocated_size;
  void ** items; 
} ListType;

/* Push implemented based on the usage in your code */
int push(ListType l, void* item){
  // check if we need to allocate memory
  if (l.length >= l.allocated_size){
    size_t next_size = (l.allocated_size > 0) ? l.allocated_size * 2 : sizeof(void*);
    l.items = (void **) realloc(l.items, next_size);
    if (l.items == NULL){
      return -1; // error
    }

    l.allocated_size = next_size;
  }

  // push the item;
  l.items[l.length++] = item;
  return l.length;
}

int main() {
    Client client1 = malloc(sizeof(Client));
    FILE *fp;
    ListType clientList;

    fp = fopen("clients.txt", "r");

    int lineSize = 200;
    char* line = malloc(lineSize);
    char* line2 = malloc(lineSize);
    char* line3 = malloc(lineSize);
    char* line4 = malloc(lineSize); 


    while (fgets(line, lineSize, fp) != NULL) { 
        strcpy(client1->id, line);
        strcpy(client1->name, fgets(line2, lineSize, fp));
        strcpy(client1->email, fgets(line3, lineSize, fp));
        strcpy(client1->phoneNum, fgets(line4, lineSize, fp));

        push(clientList, (void*)&client1);

        printf("ID: %s", line);
        printf("Name: %s", line2);
        printf("Email: %s", line3);
        printf("Phone Number: %s\n", line4);

        free(line);
        free(line2);
        free(line3);
        free(line4);

        line = malloc(lineSize);
        line2 = malloc(lineSize);
        line3 = malloc(lineSize);
        line4 = malloc(lineSize);

    }

}

clients.txt

1
John Doe
[email protected]
1-555-456-7890

Upvotes: 1

KingRadical
KingRadical

Reputation: 1312

The idiomatic answer depends on whether or not you want consumers to treat your custom type as opaque or not. If it does not need to be opaque, use Mobius' advice, and move the full definition to the header.

Otherwise, you'll need to provide functions that return those members, e.g.:

char * client_tag_get_name(client_tag *t) {
    return t->name;
}

and put the declaration for that in your header.

Upvotes: 1

Related Questions