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;
}
You can't - that's the whole point of const.
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).
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).
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;
}
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);
}
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.
(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)
I can't believe that no one has yet suggested const_cast.. It works just as fine for constant pointers.
const_cast<POINTER *>(mypoint_head) = InitPoint(size);
Simple as that, no extra variable declaration, nothing.
Related
Say I have a const pointer to an array as a function argument like so:
int* test(const int* inputArg)
And within the function I want to assign inputArg as one of the members of a struct, like so:
typedef struct {
int * intArray;
} structSample;
structSample abc;
abc.intArray = inputArg;
How should I cast inputArg to achieve this? Right now if I compile it, error will be shown saying that
error: assigning to 'int *' from 'const int *'
Thank you
First of all, you do not have
a const pointer to an array
What you have is a pointer to constant integer. If you really wanted a constant pointer to integer as an argument, you would have to have the prototype declared as follows:
int* test(int* const inputArg)
Unless, of course, something else was in mind.
Update from comment:
So basically if you want to have a pointer to constant int stored in your function as a struct member, you can declare it just like that:
struct SampleStruct
{
const int* a;
/* whatever follows */
};
int* test(const int* inputArg)
{
struct SampleStruct ss;
ss.a = inputArg;
/* other code */
}
You must be aware, that in doing so, you must be const correct. That means, since both (argument and field) are pointers to constant integers, you must not change the values at that address(es).
abc.intArray = (int*)inputArg;
This is the C-style cast. On a side not the compiler didn't allow the const conversion by default because it's dangerous to do so. You are removing the const at your own risk.
For eg if your test is called like
const int max = 100;
//centuries later
test(&max);
and you do go ahead with the cast:
abc.intArray = (int*)inputArg;
// after another century later
*(abc.intArray) = 10; // kaboom. Undefined behavior. Debugging is a nightmare at this point
The best solution here would be changing the function to
int* test(int* inputArg)
{
/* do whatever you wish to do with inputArg itself
* why bother to create a structure and all?
* The whole purpose you wanted the const int* inputArg
* was to prevent any accidental change of data pointed to by it
* Wasn't it?
*/
}
It looks like that you are using Werror flag (this shouldn't be an error but a warning)
There is a way to lie to the compiler (using unions) without warnings:
#include <stdio.h>
int *test(const int *inputArg)
{
union {int *nonconstant; const int *constant;} fake = {.constant = inputArg};
int *p = fake.nonconstant;
return p;
}
int main(void)
{
const int x = 500;
int *p = test(&x);
*p = 100; /* Boom */
return 0;
}
As pointed out by others, don't do it :)
So I am trying to pass my struct to a function and I am also trying to assign my variable to the struct, which does not seem to work. I don't know what's wrong with it either.
This is how my code looks:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ACE 1;
#define CardSize 52
#define colors 4
struct MyCards {
int *cards;
char *color[4];
};
void count(struct MyCards record);
int main() {
struct MyCards record;
count(record);
system("pause");
return 0;
}
void count(struct MyCards record) {
int i, j, f;
// I actually want to put this variable and the values into the struct, how do i do it?
char *color[4] = { "Diamon", "Heart", "Spade", "Clubs" };
record.cards = malloc(CardSize * sizeof(int));
for (f = 0; f < 4; f++) {
for (i = 0; i < 13; i++) {
record.cards[i] = (i % 13) + 1;
printf("%d of %s\n", record.cards[i], color[f]);
}
}
}
As you might see, the thing I commented out, I also want to put that variable AND the values that I have assign to it, but I dont know how to do that, would love some help there as well.
C uses pass-by-value. record inside count is a different variable to record in main - a copy is made when you call the function.
If you want main to see the changes you either need to return the changed object (in which case you wouldn't pass it in in the first place, in this example), or use pass-by-reference which you implement by passing a pointer to the object.
Returning the object would look like:
struct MyCard count(void)
{
struct myCard record;
// ... do stuff with record ...
return record;
}
Passing by reference would look like:
void count(MyCard *p_record)
{
// ... do stuff with (*p_record)
}
Also you want record.color[f] = color[f]; as the first line of the f loop. And (as discussed last time you posted about this code) you should be using string or char const *, not char *.
You have to pass a pointer to the struct in order to edit it, or you will edit the variable only in the stack of the function, which will be deleted once the function returns. Try passing &record to your function.
Also change your prototype: you have to accept a pointer to the struct.
When you have a pointer, to resolve the struct you have to use the -> operator. Let's do an example:
records->cards[i] = ...
I have a variable that I want to initialize at runtime before the rest of the program runs. After initialization, I don't want the value of the variable to change. Is there any C language construct to go about doing this ?
Let my main C program is contained in a file Prog.c
//Contents of Prog.c
//...includes.. and variable initialization
int main(..)
{
//Initialize variables here
//.. Huge program after this where I don't want these constants to change
}
You can do it indirectly through const pointers, at least:
typedef struct {
int answer;
} state;
const state * state_init(void)
{
static state st;
st.answer = 42; /* Pretend this has to be done at run-time. */
return &st;
}
int main(void)
{
const state *st = state_init();
printf("the answer is %d, and it's constant\n"," st->answer);
}
This way, all main() has is a const pointer to some state which it cannot modify.
A constant global should work, yes?
const int val = 3; // Set before main starts
// const, so it will never change.
int main(void)
{
printf("%d\n", val); // using val in code
}
However, if the value isn't known at compile-time, you can set it at run-time this way:
const int const* g_pVal;
int main(void)
{
static const int val = initialize_value();
g_pVal = &val;
printf("%d\n", *g_pVal);
}
The only way I can think of is if you read your value as a non constant and then call a function which take a constant value and pass your variable to it. Inside the function you make all the wished operations.
C - how to protect a variable from being accidentally changed after a certain point:
For example, in a C program, I declared an integer and changed it's value several times in the first part of the program. But then after a certain point I want to keep its value from being accidentally changed, or at least get a warning when any attempt to change its value happens. How do I do that?
You can't.
A possible solution would be to move the part of the function that modifies the variable into a separate function. That function would return the value of the variable which can be used to initialize a const variable:
int determine_value_of_a()
{
int result = 0;
/* Modifications of result. */
return result;
}
void f()
{
const int a = determine_value_of_a();
}
If using preprocessor macros is acceptable, then you can do this:
{ // Function body starts here.
int x = …;
… // Change x as desired here.
const int y = x;
#define x y;
… // “x” is actually the const y here.
#undef x
}
Generally, though, I would not recommend it. If you cannot trust the body of a single function to do things correctly, then the function is too complicated and ought to be restructured, as by calling another function to provide the value of the object.
Put the variable in a opaque struct with an indication of whether it can be changed.
Access the variable, both for getting and changing the value, from a function.
If the indication for changeability if off, the function does not allow changes
#include "swinger.h"
int main(void) {
struct moodswinger *var;
var = newswinger();
setvar(var, 42);
getvar(var);
swing(var, 0);
setvar(var, -1); /* oops */
}
The file swinger.h declares the functions.
The file swinger.c defines the struct and code.
int x;
x = …; // This is okay.
{
const int y = x; // Make a copy of x.
{
const int x = y; // Make a const copy of x that hides the original.
/* The compiler should produce a diagnostic if you
attempt to modify x here.
*/
}
}
Or, if you do not want the indenting to change:
int x;
x = …;
{ const int y = x; { const int x = y;
…; // x is const here.
} }
The only way you could do that would be
(a) to use a function to initialize the variable..
int main( int argc, char** argv )
{
const int myVar = initMyVar();
...
}
or (b) pass the variable into another function that does the other work...
void myWorkerFunc( const int myVar )
{
...
}
int main( int argc, char** argv )
{
int myVar = initMyVar();
...
myWorkerFunc( myVar );
}
Set a conditional breakpoint on it in your debugger. Then you will know if it ever changes. You could also write a "watchdog" type thread that scans your var every so often and warns on change, but that won't be immediate.
Neither of these are within the realm of C directly, but would help you determine if your var was erroneously changed.
I create a type and try to change the int value in it.
But it keeps printing 240.
I don't know why, can anyone help me?
Here is my code:
typedef struct{
int i;
}MyType;
do(MyType mt, int ii){
mt.i = ii;
}
int main(int argc, char ** argv){
MyType mt;
do(mt, 5);
print("%d\n", mt.i);
}
Passing mt by value to function do(). Any changes made will be local to the function. Pass the address of mt:
void do_func(MtType* mt, int ii){
mt->i = ii;
}
MyType mt;
do_func(&mt, 5);
So first, your do function has some problems. You have failed to specify a return type, so int is assumed (pre-C99), but I see no reason to not just specify it. Second, do is a reserved keyword in C.
You are passing your struct by value, so a copy is made, passed to your do function, and that is modified. Everything is passed by value in C, period. Your mt variable declared in main is never touched.
Take a MyType* in your code if you need to modify one or more of its member variables, take a MyType** if you need to allocate memory for the structure itself (i.e., initialize a pointer).
// pass a pointer to the function to allow
// for changes to the member variables to be
// visible to callers of your code.
void init_mytype(MyType *mt, int ii){
if(mt)
mt->i = ii;
}
MyType mt;
init_mytype(&mt, 1);
// pass a pointer to pointer to initialize memory
// for the structure and return a valid pointer.
// remember, everything is passed by value (copy)
void init_mytype(MyType **mt, int ii) {
if(mt) {
*mt = malloc(sizeof(MyType));
if(*mt)
(*mt)->i = ii;
}
}
MyType *pmt;
init_mytype(&pmt, 1);