tags:

views:

434

answers:

7
void main()
{
const int * a;
*a = 5;
}

gcc error : assignment of read only location.

so, how to assign to *a, without using another variable? and what could be a use of a declaration like above?

A: 

Isnt the point with const that you cant assign to it? Although, I dont recall in the case of const pointers if its the value it points to that cant be altered, or the adress of the pointer. Or both. My guess is that neither can be changed.

It can also be a general warning (or error, depending on compiler settings) that you try to write to uninitialized memory.

Correct would be (I assume):

void main()
{
   const int* a = new int(5);
}
mizipzor
gcc refuses to recognize "new". So, I have to use C++?
dta
No, just use malloc() instead of new.
bortzmeyer
A: 

The problem is that you've created a pointer, but it doesnt actually point to anything, so when you dereference it (or try to write to its referenced loaction), you get an error.

Visage
No, that's not the only problem: reread the original message, it was a *compilation* error.
bortzmeyer
Yes - most modern compilers are able to detect such obvious problems at compile time, rather than runtime, especially in a simple case such as the one cited - you dont need to run the programn to see that there will be an error.
Visage
Again, the problem is NOT the lack of dynamic allocation in the OP question. That's a bug, yes, but even if you fix it, the main problem indicated by the OP will still be there.
bortzmeyer
+9  A: 
const int * a;

Read the declaration from right to left.[See note] What do you get? a is a * i.e. a pointer to int i.e. an integer const i.e. a constant. In short, the variable a points to an integer whose value you cannot change. At least, not through a. Whether the pointee really is immutable or not is a different question. But fact remains, you cannot use a to modify *a;

const is a promise you make to yourself: I will never ever try to modify the pointee using a pointer to a const. The compiler only gives you support.

If you really want to write to the pointee, you need a non-const pointer something like:

int *a;
*a = 42; /* this is fine */

And a very nice comment from bortzmeyer: (I thought I'd skip this to keep it simple :)

You can also put the const after the * (as you said, declarations should be read from right to left).

What he means is this:

const int *a;

is no different from

int const *a;

(Remember, the right to left reading rule?) But is very different from:

int * const p;

Read it and we get: p is a const(-ant) *(pointer) to int(-eger). Translated: once you set p to point to an integer, you cannot reseat it (i.e. write to it to make it point to another integer -- the point of making p constant), but you can write to the pointee very much (the pointee is not constant).

Note: For the pedantically inclined here is 'The Rule' from Darron:

"declarations should be read from right to left" is a simplification -- if there are parentheses they should be read from inside out. Unless the parentheses indicate a function call. The real rule is "treat it like an expresion; if I apply these operators I'll eventually get this simple type".

This answer really would have had much less meat but for bortzmeyer and Darron - thank you!

PPS: (I promise this is going to be the last edit. Well, hopefully!)

void main() is not a standard signature for main in C or C++. Don't use it until you know you or (more importantly) your code will never have to make a voyage to the another universe.

dirkgently
You got there before me - ya bad Holistic hoor :). I was going to give examples of {int *i;} through to {const int * const i;} and how to read them, but life is too feckin short as it is.
Binary Worrier
You can also put the const after the * (as you said, declarations should be read from right to left).
bortzmeyer
@Binary Worrier: Not to worry, what goes around, comes around :) For me it's mostly goes around though
dirkgently
"const is a promise you make to yourself" - this is a great summary of what const is for. Nice one.
Tom Smith
"declarations should be read from right to left" is a simplification -- if there are parentheses they should be read from inside out. Unless the parentheses indicate a function call. The real rule is "treat it like an expresion; if I apply these operators I'll eventually get this simple type".
Darron
@Darron: I told myself, this is going to be long enough, let's keep it short and simple. But anyway thanks!
dirkgently
+1  A: 

you mean int * const, not const int *. In one case the pointer is const, the other the stuff it points to is const. You can also do const int * const. No harm to read some articles about const_cast, they should cover this ground well.

Ruben Bartelink
+2  A: 

An example illustrating Ruben Bartelink's excellent explanation:

#include <stdlib.h>

int main()
{
  int * const a = malloc(sizeof(int));
  if (a == NULL) 
    return 1;
  *a = 3;
  free(a);
  return 0;
}

Here, a is constant (and therefore must be initialized) but not *a (probably what the OP wanted).

bortzmeyer
Please change void main.
dirkgently
NOw compliant with gcc -Wall and splint :-)
bortzmeyer
A: 

Not answering the "how to assign to *a, without using another variable?" but only "what could be a use of a declaration like above?".

It is a promise not to modify the value pointed to. As discussed in the comment, if you make restrictions on the way you allow yourself to use the construct you can arrive at the conclusion that it is not useful. But if you allow yourself the whole C language then you can find uses. Think of the prototype of strcmp and such.

kmkaplan
+2  A: 

Let me put your question into simple English.

  • If I promise the compiler that I won't write to the value pointed to by the variable a, how do I write to the value pointed to by the variable a?

The answer: change the promise, at least locally.

int main()
{
    const int * a;
    *((int *) a) = 5;
}

Hopefully the wording above makes it plain that this is usually a bad idea.

Darron
+1 for you comments in my post. Please change `void main()` -- that's non-standard (read awful).
dirkgently
That's what happens when you start by cutting from the question. :-)
Darron
According to the C/C++ ANSI/ISO standard, casting the l-value is illegal! Some compilers support it as a non-standard extension though, the usage of which is discouraged.
Josh
You can get past the casting limitation with a temporary variable. Having to do this should make it even plainer that you're doing something less than ideal.
Darron