Первое, что слева от «const» - это то, что постоянно. Если «const» - это самое дальнее слева, то первое, что справа от него, является постоянным.
Кекс
4
Как дружеский совет, никогда не забывайте, что cdecl - вещь.
Брэден Бест
Существует еще один символ const *, который является возвращаемым типом исключения :: what ()
Чжан
Ответы:
364
Разница в том, что const char *указатель на a const char, а char * constпостоянный указатель на a char.
Во-первых, указанное значение не может быть изменено, но указатель может быть. Во-вторых, значение, на которое указывает указатель, может измениться, но указатель не может (аналогично ссылке).
Также есть
constchar*const
который является постоянным указателем на постоянный символ (поэтому ничего нельзя изменить).
Примечание:
Следующие две формы эквивалентны:
constchar*
и
charconst*
Точная причина этого описана в стандарте C ++, но важно помнить и избегать путаницы. Я знаю несколько стандартов кодирования, которые предпочитают:
charconst
над
constchar
(с указателем или без него), чтобы размещение constэлемента было таким же, как и с указателем const.
Стоит ли отмечать, что происходит, если в одной и той же декларации указано несколько переменных? Я считаю , что const int *foo,*bar;было бы объявить как fooи barбыть int const *, но int const *foo, *barбыло бы объявить , fooчтобы быть int const *и barбыть int *. Я думаю, typedef int * intptr; const intptr foo,bar;что объявил бы обе переменные int * const; Я не знаю, как использовать комбинированное объявление для создания двух переменных этого типа без typedef.
суперкат
1
@supercat I believe const int *foo,*bar; would declare both foo and bar to be int const *: Да. but int const *foo, *bar would declare foo to be a int const * and bar to be int *: Нет! Это было бы точно так же, как и в предыдущем случае. (См. Ideone.com/RsaB7n, где вы получаете одинаковую ошибку как для foo, так и для bar). I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const: Да. I don't know any way to use a combined declaration to create two variables of that type without a typedef: Ну int *const foo, *const bar;. Синтаксис объявления C ...
gx_
@gx_: Так что я ошибся - моя неуверенность заключалась в том, что я предположил, что было бы полезно сказать, каковы правила. Что бы int const *foo, *volatile barсделать bar? Сделай и то constи другое volatile? Я скучаю по чистому разделению Паскаля имен объявленных переменных и их типов (указатель на массив указателей на целые числа был бы var foo: ^Array[3..4] of ^Integer; `. Я думаю, это было бы забавной вложенной скобкой в C
суперкат
3
@supercat (о, только для C, извините за ссылку на код C ++, я получил здесь вопрос C ++) Все дело в синтаксисе объявления C , с («чистым») типом, за которым следует декларатор . В " int const *foo, *volatile bar" часть типа - это int const(останавливается перед *), а деклараторы *foo(выражение *fooбудет обозначать int const) и *volatile bar; чтение справа налево (хорошее правило для cv-квалификаторов ), fooявляется указателем на const int и barявляется энергозависимым указателем на const int (сам указатель является энергозависимым, на указанный int [обращаются как] const).
gx_
@supercat А что касается «указатель на массив указателей на целые» (я не знаю , Паскаль, не уверен в [3..4]синтаксисе, поэтому давайте рассмотрим массив из 10 элементов): int *(*foo)[10];. Он отражает его (будущее) использование в качестве выражения: *(*foo)[i](с iцелым числом в диапазоне, [0, 10)т. [0, 9]Е.) Будет сначала разыменовываться, fooчтобы получить массив, затем обращаться к элементу по индексу i(потому что postfix []связывается более сильно, чем префикс *), затем разыменовывается этот элемент, наконец, получая int(см. ideone.com/jgjIjR ). Но typedefделает это проще (см. Ideone.com/O3wb7d ).
gx_
102
Чтобы избежать путаницы, всегда добавляйте const квалификатор.
Зачем? «Чтобы избежать путаницы» не объясняет, что такое путаница для меня.
Эндрю Вейр
14
@ Андрей: я намекал на последовательность и, следовательно, удобочитаемость. Писать все классификаторы типов, чтобы они модифицировали то, что слева, всегда то , что я использую.
диапир
1
На самом деле это лучший ответ по теме, которую я нашел в SO
Trap
8
В качестве стандарта кода я редко сталкивался с этим стилем, и поэтому вряд ли приму его. Однако, как инструмент обучения, этот ответ был очень полезным! (Так что, я думаю, слишком плохо, это не более распространенный стиль.)
natevw
8
@Alla: pне относится к типу: (const int *const). К счастью или к худшему (хуже, если вы спросите меня), квалификатор const, как в C, так и в C ++, должен быть постфиксом: cf const функция-член void foo(int a) const;. Возможность объявить const intявляется скорее исключением, чем правилом.
диапир
44
const всегда изменяет то, что стоит перед ним (слева от него), ЗА ИСКЛЮЧЕНИЕМ, когда это первое в объявлении типа, где оно изменяет то, что следует за ним (справа от него).
Итак, эти два одинаковы:
intconst*i1;constint*i2;
они определяют указатели на const int. Вы можете изменить место i1и i2точки, но вы не можете изменить значение, на которое они указывают.
Это:
int*const i3 =(int*)0x12345678;
определяет constуказатель на целое число и инициализирует его, чтобы он указывал на ячейку памяти 12345678. Вы можете изменить intзначение по адресу 12345678, но вы не можете изменить адрес, на который i3указывает.
const * charявляется недействительным кодом C и не имеет смысла. Возможно, вы хотели спросить разницу между a const char *и a char const *, или, возможно, разницу между a const char *и a char * const?
const char*является указателем на постоянный символ char* constявляется постоянным указателем на символ const char* constявляется постоянным указателем на постоянный символ
Правило большого пальца: прочитайте определение справа налево!
const int *foo;
Означает « fooуказывает ( *) на то, intчто не может изменить ( const)».
Для программиста это означает: «Я не буду менять значение того, на что fooуказывает».
Означает " fooне может изменить ( const) и указывает ( *) на int".
Для программиста это означает: «Я не буду менять адрес памяти, который fooотносится к».
*foo = 123;или foo[0] = 123;разрешено.
foo = &bar; будет недействительным.
const int *const foo;
Означает « fooне может изменить ( const) и указывает ( *) на intчто не может изменить ( const)».
Для программиста это означает: «Я не буду менять значение того, на что fooуказывает, и я не буду менять адрес, который fooссылается».
const char * x Здесь X в основном символьный указатель, который указывает на постоянное значение
char * const x относится к символьному указателю, который является постоянным, но местоположение, на которое он указывает, может быть изменено.
const char * const x является комбинацией 1 и 2, означает, что это постоянный символьный указатель, который указывает на постоянное значение.
const * char x вызовет ошибку компилятора. это не может быть объявлено.
символ const * x равен точке 1.
Эмпирическое правило: если const с именем переменной, тогда указатель будет постоянным, но местоположение указателя может быть изменено , иначе указатель будет указывать на постоянное местоположение, а указатель может указывать на другое местоположение, но содержимое указательного места не может быть изменено .
«char * const x относится к символьному указателю, который является постоянным, но местоположение, на которое он указывает, может быть изменено». Неправильно. Значение в местоположении может быть изменено не само местоположение.
PleaseHelp
3
Первый - это синтаксическая ошибка. Может быть, вы имели в виду разницу между
constchar* mychar
и
char*const mychar
В этом случае первый - это указатель на данные, которые не могут быть изменены, а второй - это указатель, который всегда будет указывать на один и тот же адрес.
Множество ответов предоставляют конкретные приемы, практическое правило и т. Д., Чтобы понять этот конкретный случай объявления переменной. Но есть общая методика понимания любой декларации:
Согласно правилу по часовой стрелке / спирали aуказатель на символ является постоянным. Это означает, что символ является постоянным, но указатель может измениться. то a = "other string";есть нормально, но a[2] = 'c';не скомпилируется
B)
char*const a;
Согласно правилу, aэто постоянный указатель на символ. то есть вы можете делать, a[2] = 'c';но не можетеa = "other string";
(Было бы намного лучше, если бы суть ответа не была бы спрятана за ссылкой, причем текст здесь даже не ссылается на какую-либо его специфику или, по крайней мере, не ссылается на какую-либо ее специфику, за исключением общего «согласно правилу».)
Sz.
@Sz. У вас есть какая-то конкретная путаница, которую я могу прояснить? Там действительно не так много, после того, как вы знаете правила.
PnotNP
1
Я предполагаю, что вы имеете в виду const char * и char * const.
Первый, const char *, является указателем на постоянный символ. Сам указатель является изменяемым.
Второе, char * const - это постоянный указатель на символ. Указатель не может измениться, символ, на который он указывает, может.
И затем есть const char * const, где указатель и символ не могут измениться.
Ваши первые два на самом деле одинаковы, а третий - ошибка компилятора :)
workmad3
1
Вот подробное объяснение с кодом
/*const char * p;
char * const p;
const char * const p;*/// these are the three conditions,// const char *p;const char * const p; pointer value cannot be changed// char * const p; pointer address cannot be changed// const char * const p; both cannot be changed.#include<stdio.h>/*int main()
{
const char * p; // value cannot be changed
char z;
//*p = 'c'; // this will not work
p = &z;
printf(" %c\n",*p);
return 0;
}*//*int main()
{
char * const p; // address cannot be changed
char z;
*p = 'c';
//p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*//*int main()
{
const char * const p; // both address and value cannot be changed
char z;
*p = 'c'; // this will not work
p = &z; // this will not work
printf(" %c\n",*p);
return 0;
}*/
// Some more complex constant variable/pointer declaration.// Observing cases when we get error and warning would help// understanding it better.int main(void){char ca1[10]="aaaa";// char array 1char ca2[10]="bbbb";// char array 2char*pca1= ca1;char*pca2= ca2;charconst*ccs= pca1;char*const csc= pca2;
ccs[1]='m';// Bad - error: assignment of read-only location ‘*(ccs + 1u)’
ccs= csc;// Good
csc[1]='n';// Good
csc= ccs;// Bad - error: assignment of read-only variable ‘csc’charconst**ccss=&ccs;// Goodcharconst**ccss1=&csc;// Bad - warning: initialization from incompatible pointer typechar*const*cscs=&csc;// Goodchar*const*cscs1=&ccs;// Bad - warning: initialization from incompatible pointer typechar**const cssc=&pca1;// Goodchar**const cssc1=&ccs;// Bad - warning: initialization from incompatible pointer typechar**const cssc2=&csc;// Bad - warning: initialization discards ‘const’// qualifier from pointer target type*ccss[1]='x';// Bad - error: assignment of read-only location ‘**(ccss + 8u)’*ccss= ccs;// Good*ccss= csc;// Good
ccss= ccss1;// Good
ccss= cscs;// Bad - warning: assignment from incompatible pointer type*cscs[1]='y';// Good*cscs= ccs;// Bad - error: assignment of read-only location ‘*cscs’*cscs= csc;// Bad - error: assignment of read-only location ‘*cscs’
cscs= cscs1;// Good
cscs= cssc;// Good*cssc[1]='z';// Good*cssc= ccs;// Bad - warning: assignment discards ‘const’// qualifier from pointer target type*cssc= csc;// Good*cssc= pca2;// Good
cssc= ccss;// Bad - error: assignment of read-only variable ‘cssc’
cssc= cscs;// Bad - error: assignment of read-only variable ‘cssc’
cssc= cssc1;// Bad - error: assignment of read-only variable ‘cssc’}
Постоянный указатель : постоянный указатель может указывать только на одну переменную соответствующего типа данных в течение всей программы. Мы можем изменить значение переменной, указанной указателем. Инициализация должна быть сделана во время самого объявления.
Синтаксис:
datatype *const var;
char *const подпадает под этот случай.
/*program to illustrate the behaviour of constant pointer */#include<stdio.h>int main(){int a=10;int*const ptr=&a;*ptr=100;/* we can change the value of object but we cannot point it to another variable.suppose another variable int b=20; and ptr=&b; gives you error*/
printf("%d",*ptr);return0;}
Указатель на постоянное значение : в этом указатель может указывать любое количество переменных соответствующего типа, но мы не можем изменить значение объекта, на который указывает указатель в это конкретное время.
Синтаксис:
const datatype *varили datatype const *var
const char* подпадает под этот случай.
/* program to illustrate the behavior of pointer to a constant*/#include<stdio.h>int main(){int a=10,b=20;intconst*ptr=&a;
printf("%d\n",*ptr);/* *ptr=100 is not possible i.e we cannot change the value of the object pointed by the pointer*/
ptr=&b;
printf("%d",*ptr);/*we can point it to another object*/return0;}
constМодификатор применяется к термину сразу слева от нее . Единственное исключение - когда слева ничего нет, тогда это относится к тому, что находится справа справа.
Это все эквивалентные способы сказать «постоянный указатель на постоянную char»:
Это зависит от компилятора? gcc производит для "const char const *" и "const const char *" и "char const const *" один и тот же результат -> указатель может указывать на другое местоположение.
cosinus0
1
Два правила
If const is between char and *, it will affect the left one.
If const is not between char and *, it will affect the nearest one.
например
char const *. This is a pointer points to a constant char.
char * const. This is a constant pointer points to a char.
Я хотел бы отметить, что использование int const *(или const int *) не о указателе, указывающем на const intпеременную, а о том, что эта переменная предназначена constдля этого конкретного указателя.
Например:
int var =10;intconst* _p =&var;
Код выше компилируется отлично. _pуказывает на constпеременную, хотя varсама не является постоянной.
Ответы:
Разница в том, что
const char *
указатель на aconst char
, аchar * const
постоянный указатель на achar
.Во-первых, указанное значение не может быть изменено, но указатель может быть. Во-вторых, значение, на которое указывает указатель, может измениться, но указатель не может (аналогично ссылке).
Также есть
который является постоянным указателем на постоянный символ (поэтому ничего нельзя изменить).
Примечание:
Следующие две формы эквивалентны:
и
Точная причина этого описана в стандарте C ++, но важно помнить и избегать путаницы. Я знаю несколько стандартов кодирования, которые предпочитают:
над
(с указателем или без него), чтобы размещение
const
элемента было таким же, как и с указателемconst
.источник
const int *foo,*bar;
было бы объявить какfoo
иbar
бытьint const *
, ноint const *foo, *bar
было бы объявить ,foo
чтобы бытьint const *
иbar
бытьint *
. Я думаю,typedef int * intptr; const intptr foo,bar;
что объявил бы обе переменныеint * const
; Я не знаю, как использовать комбинированное объявление для создания двух переменных этого типа без typedef.I believe const int *foo,*bar; would declare both foo and bar to be int const *
: Да.but int const *foo, *bar would declare foo to be a int const * and bar to be int *
: Нет! Это было бы точно так же, как и в предыдущем случае. (См. Ideone.com/RsaB7n, где вы получаете одинаковую ошибку как для foo, так и для bar).I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const
: Да.I don't know any way to use a combined declaration to create two variables of that type without a typedef
: Нуint *const foo, *const bar;
. Синтаксис объявления C ...int const *foo, *volatile bar
сделатьbar
? Сделай и тоconst
и другоеvolatile
? Я скучаю по чистому разделению Паскаля имен объявленных переменных и их типов (указатель на массив указателей на целые числа был быvar foo: ^Array[3..4] of ^Integer
; `. Я думаю, это было бы забавной вложенной скобкой в Cint const *foo, *volatile bar
" часть типа - этоint const
(останавливается перед*
), а деклараторы*foo
(выражение*foo
будет обозначатьint const
) и*volatile bar
; чтение справа налево (хорошее правило для cv-квалификаторов ),foo
является указателем на const int иbar
является энергозависимым указателем на const int (сам указатель является энергозависимым, на указанный int [обращаются как] const).[3..4]
синтаксисе, поэтому давайте рассмотрим массив из 10 элементов):int *(*foo)[10];
. Он отражает его (будущее) использование в качестве выражения:*(*foo)[i]
(сi
целым числом в диапазоне,[0, 10)
т.[0, 9]
Е.) Будет сначала разыменовываться,foo
чтобы получить массив, затем обращаться к элементу по индексуi
(потому что postfix[]
связывается более сильно, чем префикс*
), затем разыменовывается этот элемент, наконец, получаяint
(см. ideone.com/jgjIjR ). Ноtypedef
делает это проще (см. Ideone.com/O3wb7d ).Чтобы избежать путаницы, всегда добавляйте const квалификатор.
источник
p
не относится к типу:(const int *const)
. К счастью или к худшему (хуже, если вы спросите меня), квалификатор const, как в C, так и в C ++, должен быть постфиксом: cf const функция-членvoid foo(int a) const;
. Возможность объявитьconst int
является скорее исключением, чем правилом.const
всегда изменяет то, что стоит перед ним (слева от него), ЗА ИСКЛЮЧЕНИЕМ, когда это первое в объявлении типа, где оно изменяет то, что следует за ним (справа от него).Итак, эти два одинаковы:
они определяют указатели на
const int
. Вы можете изменить местоi1
иi2
точки, но вы не можете изменить значение, на которое они указывают.Это:
определяет
const
указатель на целое число и инициализирует его, чтобы он указывал на ячейку памяти 12345678. Вы можете изменитьint
значение по адресу 12345678, но вы не можете изменить адрес, на которыйi3
указывает.источник
const * char
является недействительным кодом C и не имеет смысла. Возможно, вы хотели спросить разницу между aconst char *
и achar const *
, или, возможно, разницу между aconst char *
и achar * const
?Смотрите также:
источник
const char*
является указателем на постоянный символchar* const
является постоянным указателем на символconst char* const
является постоянным указателем на постоянный символисточник
Правило большого пальца: прочитайте определение справа налево!
const int *foo;
Означает «
foo
указывает (*
) на то,int
что не может изменить (const
)».Для программиста это означает: «Я не буду менять значение того, на что
foo
указывает».*foo = 123;
илиfoo[0] = 123;
будет недействительным.foo = &bar;
позволено.int *const foo;
Означает "
foo
не может изменить (const
) и указывает (*
) наint
".Для программиста это означает: «Я не буду менять адрес памяти, который
foo
относится к».*foo = 123;
илиfoo[0] = 123;
разрешено.foo = &bar;
будет недействительным.const int *const foo;
Означает «
foo
не может изменить (const
) и указывает (*
) наint
что не может изменить (const
)».Для программиста это означает: «Я не буду менять значение того, на что
foo
указывает, и я не буду менять адрес, которыйfoo
ссылается».*foo = 123;
илиfoo[0] = 123;
будет недействительным.foo = &bar;
будет недействительным.источник
const char * x Здесь X в основном символьный указатель, который указывает на постоянное значение
char * const x относится к символьному указателю, который является постоянным, но местоположение, на которое он указывает, может быть изменено.
const char * const x является комбинацией 1 и 2, означает, что это постоянный символьный указатель, который указывает на постоянное значение.
const * char x вызовет ошибку компилятора. это не может быть объявлено.
символ const * x равен точке 1.
Эмпирическое правило: если const с именем переменной, тогда указатель будет постоянным, но местоположение указателя может быть изменено , иначе указатель будет указывать на постоянное местоположение, а указатель может указывать на другое местоположение, но содержимое указательного места не может быть изменено .
источник
Первый - это синтаксическая ошибка. Может быть, вы имели в виду разницу между
и
В этом случае первый - это указатель на данные, которые не могут быть изменены, а второй - это указатель, который всегда будет указывать на один и тот же адрес.
источник
Другое правило большого пальца - проверить, где находится const :
источник
Множество ответов предоставляют конкретные приемы, практическое правило и т. Д., Чтобы понять этот конкретный случай объявления переменной. Но есть общая методика понимания любой декларации:
A)
Согласно правилу по часовой стрелке / спирали
a
указатель на символ является постоянным. Это означает, что символ является постоянным, но указатель может измениться. тоa = "other string";
есть нормально, ноa[2] = 'c';
не скомпилируетсяB)
Согласно правилу,
a
это постоянный указатель на символ. то есть вы можете делать,a[2] = 'c';
но не можетеa = "other string";
источник
Я предполагаю, что вы имеете в виду const char * и char * const.
Первый, const char *, является указателем на постоянный символ. Сам указатель является изменяемым.
Второе, char * const - это постоянный указатель на символ. Указатель не может измениться, символ, на который он указывает, может.
И затем есть const char * const, где указатель и символ не могут измениться.
источник
Вот подробное объяснение с кодом
источник
источник
Синтаксис:
char *const
подпадает под этот случай.Синтаксис:
const datatype *var
илиdatatype const *var
const char*
подпадает под этот случай.источник
char * const и const char *?
const char * p;
// значение не может быть измененоchar * const p;
// адрес не может быть измененconst char * const p;
// оба не могут быть изменены.источник
const
Модификатор применяется к термину сразу слева от нее . Единственное исключение - когда слева ничего нет, тогда это относится к тому, что находится справа справа.Это все эквивалентные способы сказать «постоянный указатель на постоянную
char
»:const char * const
const char const *
char const * const
char const const *
источник
Два правила
If const is between char and *, it will affect the left one.
If const is not between char and *, it will affect the nearest one.
например
char const *. This is a pointer points to a constant char.
char * const. This is a constant pointer points to a char.
источник
Я хотел бы отметить, что использование
int const *
(илиconst int *
) не о указателе, указывающем наconst int
переменную, а о том, что эта переменная предназначенаconst
для этого конкретного указателя.Например:
Код выше компилируется отлично.
_p
указывает наconst
переменную, хотяvar
сама не является постоянной.источник
Я помню из чешской книги о C: прочитайте декларацию, что вы начинаете с переменной и идете налево. Таким образом, для
Вы можете читать как: «
a
переменная типа указатель на постояннуюchar
»,Вы можете читать как: "
a
это указатель на постоянную переменную типа char. Надеюсь, это поможет.Бонус:
Вы будете читать как
a
постоянный указатель на постоянную переменную типа char.источник