Чим відрізняється char * const від const char *?


279

Яка різниця між:

char * const 

і

const char *


8
Перше, що ліворуч від "const" - це те, що є постійним. Якщо "const" - це річ, яка знаходиться найдаліше зліва, то перше, що праворуч від неї, - це те, що є постійним.
Кекс

4
Як дружня порада, ніколи не забувайте, що cdecl - річ.
Бреден Кращий

Є ще один con const *, який є типом повернення виключення :: what ()
Чжан

Відповіді:


363

Різниця полягає в тому, що const char *це вказівник на a const char, а char * constпостійний покажчик на a char.

По-перше, значення, на яке вказують, неможливо змінити, але вказівник може бути. По-друге, значення, на яке вказують, може змінюватися, але вказівник не може (подібно до посилання).

Також є

const char * const

що є постійним вказівником на постійний знак (тому нічого про це не можна змінити).

Примітка:

Наступні дві форми є рівнозначними:

const char *

і

char const *

Точна причина цього описана в стандарті C ++, але важливо зазначити і уникати плутанини. Я знаю кілька стандартів кодування, які віддають перевагу:

char const

над

const char

(з вказівником або без нього), щоб розміщення constелемента було таким же, як і вказівником const.


6
Чи варто зазначити, що відбувається, якщо в одній декларації вказано кілька змінних? Я вважаю, 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.
supercat

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, я думаю
Supercat

3
@supercat (о, лише для С, вибачте за кодове посилання 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(оскільки постфікс []пов'язується жорсткіше за префікс *), потім дереференція цього елемента, нарешті виходить int(див. ideone.com/jgjIjR ). Але typedefце спрощує (див. Ideone.com/O3wb7d ).
gx_

102

Щоб уникнути плутанини, завжди додайте класифікатор const.

int       *      mutable_pointer_to_mutable_int;
int const *      mutable_pointer_to_constant_int;
int       *const constant_pointer_to_mutable_int;
int const *const constant_pointer_to_constant_int;

10
Чому? "Щоб уникнути плутанини" не пояснює, що для мене плутанина.
Ендрю Вейр

14
@Andrew: Я натякав на послідовність і таким чином читабельність. Написання всіх відбіркових типу так вони змінюють то , що на їх зліва, завжди , що я використовую.
діапір

1
Насправді це найкраща відповідь на тему, яку я знайшов у SO
Trap

8
Як стандарт коду, я рідко стикався з цим стилем, і тому, швидше за все, його не прийняв. Однак, як інструмент навчання, ця відповідь була дуже корисною! (Тож я думаю, що занадто погано, це не більш поширений стиль.)
natevw

8
@Alla: pне відноситься до типу: (const int *const). Для кращого або гіршого (гіршого, якщо ви запитаєте мене) класифікатора const, як в C, так і в C ++, має бути postfix: cf const member member function void foo(int a) const;. Можливість декларації const int- це швидше виняток, ніж правило.
діапір

44

const завжди модифікує те, що знаходиться перед ним (ліворуч від нього), ПРИ ВКЛЮЧЕННЯ, коли це перше, що відбувається в оголошенні типу, де воно змінює річ, що йде після неї (праворуч від неї).

Отже, це двоє:

int const *i1;
const int *i2;

вони визначають покажчики на a const int. Ви можете змінити куди i1та i2точки, але не можете змінити значення, на яке вони вказують.

Це:

int *const i3 = (int*) 0x12345678;

визначає constвказівник на ціле число і ініціалізує його, щоб вказати на місце пам'яті 12345678. intЗначення можна змінити за адресою 12345678, але ви не можете змінити адресу, на яку i3вказує.


22

const * charнедійсний код C і не має сенсу. Можливо, ви мали на меті запитати різницю між a const char *і a char const *, чи, можливо, різницю між a const char *і a char * const?

Дивитися також:


18

const char*є вказівник на постійний символ
char* constпостійний вказівник на символ
const char* constє постійним вказівником на постійний символ


9

Правило великого пальця: прочитайте визначення справа наліво!


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; було б недійсним.

8
  1. const char * x Тут X - це в основному покажчик символів, який вказує на постійне значення

  2. char * const x посилається на символьний покажчик, який є постійним, але місце, на яке він вказує, може бути змінено.

  3. const char * const x - комбінація до 1 і 2, означає, що це постійний вказівник символів, який вказує на постійне значення.

  4. const * char x призведе до помилки компілятора. її не можна оголосити.

  5. char const * x дорівнює точці 1.

правило: якщо const є з ім'ям var, то вказівник буде постійним, але розташування вказівника може бути змінено , інакше вказівник буде вказувати на постійне місце розташування і вказівник може вказувати на інше місце, але вміст місця вказівки не може бути змінений .


1
"char * const x - це покажчик символів, який є постійним, але місце, на яке він вказує, може бути змінено." Неправильно. Значення в розташуванні можна змінити не саме розташування.
Будь ласка, довідка

3

Перша - синтаксична помилка. Можливо, ви мали на увазі різницю між

const char * mychar

і

char * const mychar

У цьому випадку перший - вказівник на дані, які не можуть змінити, а другий - вказівник, який завжди вказуватиме на ту саму адресу.


3

Ще одне правило великого пальця - перевірити, де const :

  1. до * => збережене значення є постійним
  2. після * => сам покажчик є постійним

3

Багато відповідей містять конкретні прийоми, правило великих пальців тощо для розуміння цього конкретного примірника змінної декларації. Але є загальна техніка розуміння будь-якої декларації:

За годинниковою стрілкою / Правило спіралі

А)

const char *a;

Згідно з правилом за годинниковою стрілкою / спіраллю aє вказівник на характер, який є постійним. Що означає, що символ є постійним, але вказівник може змінюватися. тобто a = "other string";добре, але a[2] = 'c';не вдасться компілювати

Б)

char * const a;

Як правило, aце const вказівник на персонаж. тобто ви можете робити, a[2] = 'c';але не можетеa = "other string";


1
Також відоме як праве-ліве правило (принаймні, так я це дізнався): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Томаш Прузіна,

(Було б набагато краще, якби суть відповіді не була б прихована за посиланням, при цьому текст тут навіть не цитується, або принаймні посилається на будь-яку його специфіку, поза загальним «як за правилом».)
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;
}*/

@reese moore Дякую
Меґарадж

1
// 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 1
  char ca2[10]= "bbbb"; // char array 2

  char *pca1= ca1;
  char *pca2= ca2;

  char const *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’

  char const **ccss= &ccs;     // Good
  char const **ccss1= &csc;    // Bad - warning: initialization from incompatible pointer type

  char * const *cscs= &csc;    // Good
  char * const *cscs1= &ccs;   // Bad - warning: initialization from incompatible pointer type

  char ** const cssc=   &pca1; // Good
  char ** const cssc1=  &ccs;  // Bad - warning: initialization from incompatible pointer type
  char ** 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’
}

1
  1. Постійний покажчик : Постійний покажчик може вказувати лише на одну змінну відповідного типу даних протягом усієї програми. Ми можемо змінити значення змінної, вказаної вказівником. Ініціалізація повинна здійснюватися під час самої декларації.

Синтаксис:

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);
  return 0;
}
  1. Вказівник на значення const : У цьому вказівник може вказувати будь-яку кількість змінних відповідного типу, але ми не можемо змінити значення об'єкта, вказаного вказівником у цей конкретний час.

Синтаксис:

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;
       int const *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*/
       return 0;
    }

1

char * const та const char *?

  1. Вказує на постійне значення

const char * p; // значення не можна змінити

  1. Постійний покажчик на значення

char * const p; // адресу не можна змінити

  1. Постійний покажчик на постійне значення

const char * const p; // обидва не можуть бути змінені.


1

constМодифікатор застосовується до терміну відразу зліва від неї . Єдиний виняток з цього - коли зліва немає нічого, то це стосується того, що знаходиться праворуч від нього.

Це всі рівнозначні способи сказати "постійний вказівник на константу char":

  • const char * const
  • const char const *
  • char const * const
  • char const const *

Чи залежить від компілятора? gcc produce for "const char const *" та "const const char *" та "char const const *" той же результат -> покажчик може вказувати на інше місцеположення.
cosinus0

1

Два правила

  1. If const is between char and *, it will affect the left one.
  2. If const is not between char and *, it will affect the nearest one.

напр

  1. char const *. This is a pointer points to a constant char.
  2. char * const. This is a constant pointer points to a char.

1

Я хотів би зазначити, що використання int const *(або const int *) не стосується вказівника, який вказує на const intзмінну, а що ця змінна призначена саме constдля цього конкретного вказівника.

Наприклад:

int var = 10;
int const * _p = &var;

Код, наведений вище, складається прекрасно. _pвказує на constзмінну, хоча varсама по собі не є постійною.


1

Я пам’ятаю з чеської книги про С: прочитайте декларацію, що ви починаєте зі змінної, та йдіть вліво. Так для

char * const a;

ви можете прочитати як: " aє змінною постійного вказівника типу на char",

char const * a;

Ви можете прочитати як: " a- вказівник на постійну змінну типу char. Сподіваюся, це допоможе.

Бонус:

const char * const a;

Ви прочитаєте як aпостійний вказівник на постійну змінну типу char.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.