Copying a portion of C grammar for declarations:
declaration |
|
: declaration_specifiers ';' |
|
| declaration_specifiers init_declarator_list ';' |
|
; |
declaration_specifiers |
|
: storage_class_specifier |
|
| storage_class_specifier declaration_specifiers |
|
| type_specifier |
|
| type_specifier declaration_specifiers |
|
| type_qualifier |
|
| type_qualifier declaration_specifiers |
|
| function_specifier |
|
| function_specifier declaration_specifiers |
|
; |
storage_class_specifier |
|
: TYPEDEF |
|
| EXTERN |
|
| STATIC |
|
| AUTO |
|
| REGISTER |
|
; |
type_specifier |
|
: VOID |
|
| CHAR |
|
| SHORT |
|
| INT |
|
| LONG |
|
| FLOAT |
|
| DOUBLE |
|
| SIGNED |
|
| UNSIGNED |
|
| BOOL |
|
| COMPLEX |
|
| IMAGINARY |
|
| struct_or_union_specifier |
|
| enum_specifier |
|
| TYPE_NAME |
|
; |
|
type_qualifier |
|
: CONST |
|
| RESTRICT |
|
| VOLATILE |
|
; |
|
declarator |
|
: pointer direct_declarator |
|
| direct_declarator |
|
; |
|
direct_declarator |
|
: IDENTIFIER |
|
| '(' declarator ')' |
|
| direct_declarator '[' type_qualifier_list assignment_expression ']' |
|
| direct_declarator '[' type_qualifier_list ']' |
|
| direct_declarator '[' assignment_expression ']' |
|
| direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' |
|
| direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' |
|
| direct_declarator '[' type_qualifier_list '*' ']' |
|
| direct_declarator '[' '*' ']' |
|
| direct_declarator '[' ']' |
|
| direct_declarator '(' parameter_type_list ')' |
|
| direct_declarator '(' identifier_list ')' |
|
| direct_declarator '(' ')' |
|
; |
|
init_declarator_list |
|
: init_declarator |
|
| init_declarator_list ',' init_declarator |
|
;
|
init_declarator |
|
: declarator |
|
| declarator '=' initializer |
|
; |
pointer |
|
: '*' |
|
| '*' type_qualifier_list |
|
| '*' pointer |
|
| '*' type_qualifier_list pointer |
|
; |
type_qualifier_list |
|
: type_qualifier |
|
| type_qualifier_list type_qualifier |
|
; |
Full list:
So, "const" is a type qualifier and in a declaration a type qualifier can come alone or followed by declaration specifier. ( "const; " is a valid C statement as per C grammar).
Now see the "declarator". After a pointer we can have any number of type quantifiers. i.e.,
char * p, char * const p, char * const const p;
etc.
const char *p1 = "hello";
const * char p1 = "hello";
char const * p1 = "hello";
char * const p1 = "hello"
There are 4 ways we can write "const" and "char" involving a pointer. The thing to identify is whether "pointer" is constant or if it is a normal pointer to a "const char".
If pointer is "const", it cannot point to anything else and must be initialized (assigned a value along with declaration).
If pointer is to a character constant, then the location pointed to by the pointer cannot be modified. (If modified result is undefined meaning anything can happen).
So, lets see the 4 options I gave:
- Constant character pointer, p1 - yes, p1 is a pointer to a constant char.
- After "*" we cannot have a type specifier - hence invalid.
- Character constant pointer, p1 - p1 is a pointer to a character constant - same as 1.
- Constant pointer to character, p1 - p1 is a constant pointer to a character.
So, now coming to question:
p1 is a pointer to a character constant - (*p1) is READ ONLY
p2 is a constant pointer - p2 is READ ONLY.
So, statements 4 and 5 are not allowed.