简体   繁体   中英

C - reassigning pointer which is attribute of struct: dereferencing pointer to incomplete type

I'm reasonably certain that I have a horrible understanding of pointers in C (at least syntactically).

I am trying to have a struct which is a linkedlist with a bunch of data. Later, I try to add a new struct as the head of that linkedlist, pointing to the old head, which has a "prior" link to the new head.

typedef struct{
  int sequence_number;
  int file_descriptor;
  FILE *requested_file;
  int bytes_remaining;
  int quantum;
  struct RCB *next;
  struct RCB *prior;
} RCB;

   RCB *RRhead;
...


function blah(){
  RCB new_rcb = {sequence_counter, fd, fin, new_bytes_remaining, new_quantum, RRhead, NULL};
  RRhead->prior = &new_rcb;
  RRhead = &new_rcb;
  sequence_counter++;
}

And I am getting these errors:

sws.c: In function ‘admit_to_scheduler_RR’:
sws.c:317:3: warning: initialization from incompatible pointer type [enabled by default]
   RCB new_rcb = {sequence_counter, fd, fin, new_bytes_remaining, new_quantum, RRhead, NULL};
sws.c:317:3: warning: (near initialization for ‘new_rcb.next’) [enabled by default]
sws.c:318:17: warning: assignment from incompatible pointer type [enabled by default]
   RRhead->prior = &new_rcb;

RCB and struct RCB are two completely different, unrelated types. struct RCB is never defined in your code and is hence incomplete.

To make them one and the same, write

typedef struct RCB {
   ....
} RCB;

This is one part of the problem.

Don't use *RRhead when initializing new_rcb . You just want RRhead .

The struct has a pointer, ie struct RCB *prior so you must use the pointer RRhead .

firstly, RRhead is just a pointer, so when you go RRhead->prior, you will get a runtime error, because RRhead isn't pointing to anything (RRhead->prior says "get the 'prior'property of the RCB struct that RRhead is pointing to)

secondly, when you pass *RRhead as the last initializer of new_rcb: prior is an RCB pointer, and RRhead is an RCB pointer. they are the same type, so there is no need to do any referencing or dereferencing, just pass RRhead. this will make the prior property of new_rcb point to whatever RRhead is pointing to at the time (which is nothing at that moment, because RRhead hasn't been initalized to any value)

thirdly, RRhead->prior = new_rcb; is wrong because 'prior' is an RCB pointer, whereas new_rcb is not a pointer, it is a RCB. to pass the adress of new_rcb, go RRhead->prior = &new_rcb;

Finally, its unlikely you will want new_rcb to be statically allocated.

There are lots of problems here. It's not clear exactly what your real code is since you keep changing it but I'll have a crack:


First of all, in C, struct tags are in a separate "namespace" to typedef names. There is no relation between struct RCB and RCB . Particularly, in this code:

typedef struct {
  struct RCB *next;
  struct RCB *prior;
} RCB;

next does NOT point to a RCB . It points to a struct RCB which is a completely different type to RCB . This is why you get the error error: dereferencing pointer to incomplete type . You never defined what struct RCB is.

If you want a struct containing pointers to itself, you must use a struct tag, because the typedef name does not exist until the typedef is complete. For example:

struct RCB
{
    // ...
    struct RCB *next, *prior;
};

typedef struct RCB RCB;

Of course, the typedef is optional; and could be combined with the struct definition but I think it is clearer to separate the two.


The next problem is:

new_rcb = {sequence_counter, fd, fin, new_bytes_remaining, new_quantum, RRhead, NULL};

This is not allowed in C, the right-hand side of the assignment operator must be an expression. A brace-enclosed list is not an expression. The simplest way to avoid this problem is to use initialization:

RCB new_rcb = {sequence_counter, fd, fin, new_bytes_remaining, new_quantum, RRhead, NULL};

Another runtime problem is hinted at in the latest edit:

function blah(){
  RCB new_rcb = {sequence_counter, fd, fin, new_bytes_remaining,  new_quantum, RRhead, NULL};
  RRhead->prior = &new_rcb;
  RRhead = &new_rcb;
  sequence_counter++;
}

Obviously this is some sort of pseudocode. But new_rcb is a local variable to the blah function. new_rcb stops existing when blah returns. This means the list pointed to by RRhead will contain a dangling pointer.

When using pointers you need to have a very clear mental image of where pointers are pointing and what the lifetime is of the objects being pointed to.

To fix this you could either use dynamic allocation ( malloc ), or some sort of memory pool.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM