views:

110

answers:

7

I have a variable which is the head to a linked list. I want to make it const because it should never be changed, the variable is used throughout the program, so I thought I should make it a global const. The problem is that I couldn't initialize it after I declared it const.

How can I get around this problem?

typedef struct PT {
 int x;
 int y;
 struct PT *next;
} POINT;

//globals
POINT * const mypoint_head;

int main(int argc, char *argv[])
{
    int size = 100;
    mypoint_head= InitPoint(size);   // error C2166: l-value specifies const object
    //rest of code

}


POINT* InitPoint(int size)
{
   POINT *tmp;
   POINT *orig;
   int a = 10;
   int b = 1000;
   orig = (POINT*) malloc (sizeof(POINT) * size);
   if(orig == NULL)
      return NULL;

   tmp = orig;
   for (i = 0; i < size; i++)
   {
      tmp->x = a++;
      tmp->y = b++;
      if (i == size -1) {
            tmp->next = NULL:
      }
      else {
            tmp->next = tmp+1; 
      }
      tmp++;
   }
   return orig;
} 
+3  A: 

You can't - that's the whole point of const.

Carl Norum
A: 

You have to use an initializer in the declaration:

static POINT mypoint_data[100];
POINT * const mypoint_head = &mypoint_head;

Then change your InitPoint function to take a pointer to the dataspace instead of calling malloc and pass it mypoint_data

You can also stick extern POINT * const mypoint_head; in a header file so its accessable in other compilation units.

Chris Dodd
A: 

Remove the const qualifier from the global declaration and declare rest_of_code as a function that takes the const-qualified version of the pointer.

//globals
POINT * mypoint_head;

void rest_of_code(POINT* const mypoint_head)
{
    mypoint_head = NULL;    // this errors out now
}
int main(int argc, char *argv[])
{
    int size = 100;
    mypoint_head= InitPoint(size);   // no longer errors out
    //rest of code
    rest_of_code(mypoint_head);
}

ninjalj
@ninjalj why would I want to have functions taking a global parameter? isn't that defeating the purpose of being global? On the other hand, I could just not make it a global and use your strategy... what is the best way to handle "heads" to linked list so they are not modified by accident, and memory lost?
emge
Err, maybe instead of marking the head as const you should provide functions for list manipulation and only access the list via those functions.
ninjalj
@emge- If you are worried about losing the head to a list and leaking memory, then statically declare the head node and declare the rest of the list dynamically. That way, the head node can't be "lost".
bta
A: 

(assumes c) const have to be initialized when they are declared and they cannot be evaluated . Maybe you could use a const pointer and make it point to your head and expose it to the rest of the code. If i have to achieve may be i will expose the variable by a getListHead() function and give it some obscure name :)

Wonders what the use case is though. I would make my list work even if its head pointer changes. (if i have a const head, if i have to delete the head node i will have to shift the elements like in an array)

neal aise
+1  A: 

You are correct in that the variable declared const can never be changed. Unfortunately, your mypoint_head= InitPoint(size); line counts as trying to change the variable. You have to initialize the const variable with a value when it is declared.

Try something like this instead:

//globals
static POINT head_of_list;
POINT* const mypoint_head = &head_of_list;

Now, you can initialize the list using:

mypoint_head->next= InitPoint(size-1);

The head-of-list object was declared statically, so it always exists and you eill need to adjust your InitPoint parameters appropriately. You can also have an extern reference to the pointer in another file without having to make the object it points to directly accessible (for what it's worth).

bta
thanks bta... I really like your solution, but I chose another implementation for two reasonsA) I didn't want to mix static and dynamic elementsB) I didn't want to have to change the arguments to InitPoint
emge
The `static` part is purely optional; it will work either way.
bta
+1  A: 

Nobody has suggested this yet:

int main(int argc, char *argv[])
{
    int size = 100;

    // cast address of mypoint_head to a non-const pointer:
    POINT ** nc_pmh = (POINT **)&mypoint_head;
    // use the address to set mypoint_head:
    (*nc_pmh) = InitPoint(size);
    //rest of code
}

This may not work in C++, where it may not really supply space for const objects.

BTW: This is not generally good practice. In this case, however, it works out well.

BTW: you'll want to check the return from InitPoint(), and act accordingly (call exit(), probably).

Tim Schaeffer
thanks Tim, I appreciate your clever solution.
emge
A: 

don't have a global const pointer as your interface to everything else.

use a function :-

static POINT * mypoint_head;

POINT* point_head()
{
    return mypoint_head;
}
Keith Nicholas