M. Damian Mulligan
M. Damian Mulligan

Reputation: 873

Unable to locate source of "dereferencing pointer to incomplete type" error

As part of an assignment I'm doing for a university course, I need to write a CPU scheduling simulator in C (not C++). I'm hitting an issue when compiling with GCC where it's giving me several errors about "dereferencing pointer to incomplete type". All the errors are a result of the same code, which makes me think there's an issue with that code.

The offending code is:

//Push a record of this state change to the back of the simulation's history list
listPushBack(sim->history, (void*)newRecord(p->pid, sim->currentTime, wait, ready));

This is related to keeping track of the history of the simulation for analysis later on. A record is defined as:

//History.h

typedef struct record* Record;

//History.c

typedef struct record recordType;

struct record{
    long time;
    int pid;
    State oldState;
    State newState;
};

Record newRecord(int pid, long time, ProcessState oldState, ProcessState newState){
    Record r = (Record)malloc(sizeof(recordType));
    if(r == NULL){
        fprintf(stderr, "History.c:newRecord:Failed to allocate memory for new Record\n");
        //This is serious, abort execution
        exit(-1)
    }
    r->time = time;
    r->pid = pid;
    r->oldState = oldState;
    r->newState = newState;
    return r;
}

where ProcessState is defined as:

//Process.h

typedef enum process_state ProcessState;

enum process_state{
    arrive = 0,
    ready = 1,
    run = 2,
    wait = 3,
    done = 4
};

I played around and got the same error with this:

Process p = (Process)listGetAt(sim->waitingQueue, i);
ProcessState old = p->state;
listPushBack(sim->history, (void*)newRecord(p->pid, sim->currentTime, old, p->state));

Thankfully, this isn't due for another week, so I've got time to play around, but I'm hoping someone can point me in the right direction before I waste too much time messing with things.

EDIT: Answering questions in order of appearance in comments,

//DoubleLinkList.c

bool listPushBack(DoubleList l, void* data){
    return listInsert(l, data, -1);
}
bool listInsert(DoubleList l, void* data, int pos){
    int index = pos;
    //If value is negative, convert to a index relative to the end of the list
    if(index < 0){
        index = listSize(l) + index + 1;
    }
    //Check index bounds
    if(index > listSize(l) || index < 0){
        fprintf(stderr, "DoubleLinkList.c:listInsert:Insert index %i out of bounds\n", pos);
        //This is not serious enough to warrent an abort
        return false;
    }
    //Data is null
    if(data == NULL){
        fprintf(stderr, "DoubleLinkList.c:listInsert:Data value for doubly linked list node cannot be NULL\n");
        //This is not serious enough to warrent an abort
        return false;
    }
    Node insertNode = newNode(data);
    //Case: End of list
    if(index == listSize(l)){
        l->tail->next = insertNode;
        insertNode->prev = l->tail;
        l->tail = insertNode;
        l->size++;
        return true;
    }
    //Case: Start of list
    else if(index == 0){
        l->head->prev = insertNode;
        insertNode->next = l->head;
        l->head = insertNode;
        l->size++;
        return true;
    }
    //Case: Middle of list
    Node node = l->head;
    //Scan through list to reach index pos
    int i;
    for(i = 0; i < index; i++){
        if(node == NULL){
            fprintf(stderr, "DoubleLinkList.c:listGetPosition:NULL encoutered unexpectedly while traversing doubly linked list at index %i\n", i);
            //This is a serious problem, abort execution
            exit(-1);
        }
        node = node->next;
    }
    //Insert before Node at index pos
    insertNode->next = node;
    insertNode->prev = node->prev;
    node->prev->next = insertNode;
    node->prev = insertNode;
    l->size++;
    return true;
}

Yes, Process is:

typedef process_Struct* Process

Simulation declaration:

//Simulation.c
struct simulation{
    SimType type;
    long currentTime;
    unsigned int totalProcesses;
    DoubleList arriveQueue;
    DoubleList readyQueue;
    DoubleList waitingQueue;
    DoubleList doneQueue;
    Process running;
    DoubleList history;
};

The method that is throwing issues is runSimulation(Simulation sim) where:

typedef simulation* Simulation;

runSimulation is declared in Simulation.c

The exact error message is: source/Simulation.c:154:50: error: dereferencing pointer to incomplete type That's why this is proving so annoying, it doesn't give any more information then that, even with -verbose, -g, and some of the other debug flags.

I realize I shouldn't typdef pointers, but, stupidly enough, the professor made it a requirement of the assignment. To quote: "When possible, use typedef to define pointers to structs. This is so the TAs have an easier time reading your simulation code." I'm extremely annoyed by this because it's an awful idea and the TAs should be able to read code.

Upvotes: 3

Views: 688

Answers (3)

Doug T.
Doug T.

Reputation: 65629

You typically see this error when you have only forward-declared something then go to use it. IE If you have:

 // foo.h
 struct Process; 

 // foo.c
 #include "foo.h"
 Process* foo;
 std::cout << foo->i

You would get an error about derefencing a pointer of an incomplete type. That is likely what is happening when you are dereferencing p/sim on this line:

 listPushBack(sim->history, (void*)newRecord(p->pid, sim->currentTime, old, p->state));

The solution is to make sure that you've #include'd the full definition of Process, ie add a #include "Process.h" somewhere in the code above.

Upvotes: 2

CrazyCasta
CrazyCasta

Reputation: 28362

The problem you are having is whatever type sim is a pointer to is not defined. It is declared (which is how you can declare a pointer to it), but not defined. In other words, you've probably done something like:

struct Simulation;

void myFunc() {
    struct Simulation* sim;
    sim->history;
}

Where sim->history is the dereference of the history member of sim that's done in your listPushBack call.

Upvotes: 1

Nocturno
Nocturno

Reputation: 10027

Your comments suggest that you are defining struct record in the history.c source file. If you are using a struct record in any other source file, then you should define it in history.h, otherwise you will get this exact error when you try to use a pointer to struct record in another file.

Upvotes: 2

Related Questions