ข้อแตกต่างระหว่าง char * const และ const char * คืออะไร


279

ความแตกต่างระหว่าง:

char * const 

และ

const char *

1
สำเนาที่เป็น
emlai

8
สิ่งแรกทางซ้ายของ "const" คือค่าคงที่ ถ้า "const" เป็นสิ่งที่อยู่ไกลไปทางซ้ายที่สุดสิ่งแรกที่อยู่ทางขวาของมันคือค่าคงที่
Cupcake

4
เป็นเคล็ดลับที่เป็นมิตรอย่าลืมว่าcdeclเป็นสิ่ง
Braden ที่ดีที่สุด

ยังมีอีกกลุ่มถ่าน * ซึ่งเป็นประเภทข้อยกเว้น :: what ()
Zhang

คำตอบ:


363

แตกต่างก็คือconst char *เป็นตัวชี้ไปที่const charในขณะที่เป็นตัวชี้คงที่ไปยังchar * constchar

ประการแรกค่าที่ชี้ไปไม่สามารถเปลี่ยนแปลงได้ แต่ตัวชี้สามารถเป็นได้ ประการที่สองค่าที่ชี้ไปสามารถเปลี่ยนได้ แต่ตัวชี้ไม่สามารถ (คล้ายกับข้อมูลอ้างอิง)

นอกจากนี้ยังมี

const char * const

ซึ่งเป็นตัวชี้ค่าคงที่เป็นค่าคงที่ (ดังนั้นจึงไม่มีสิ่งใดเปลี่ยนแปลงได้)

บันทึก:

สองรูปแบบต่อไปนี้เทียบเท่า:

const char *

และ

char const *

เหตุผลที่แน่นอนสำหรับสิ่งนี้มีการอธิบายไว้ในมาตรฐาน C ++ แต่สิ่งสำคัญคือต้องทราบและหลีกเลี่ยงความสับสน ฉันรู้มาตรฐานการเข้ารหัสที่ต้องการ:

char const

เกิน

const char

(มีหรือไม่มีตัวชี้) เพื่อให้ตำแหน่งขององค์ประกอบที่เป็นเช่นเดียวกับตัวชี้constconst


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; ฉันไม่ทราบวิธีการใช้การประกาศรวมกันเพื่อสร้างตัวแปรสองประเภทโดยไม่มีการพิมพ์
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 ++ คำถาม) มันคือทั้งหมดที่เกี่ยวกับไวยากรณ์ C ประกาศด้วย ( "บริสุทธิ์") ประเภทส่วนหนึ่งตามด้วยdeclarator ใน " int const *foo, *volatile bar" ส่วนประเภทคือint const(หยุดก่อน*) และผู้ประกาศคือ*foo(นิพจน์*fooจะแสดงถึงint const) และ*volatile bar; การอ่านจากขวาไปซ้าย (กฎที่ดีสำหรับcv-qualifiers ) fooเป็นตัวชี้ไปยังconst int และbarเป็นตัวชี้ที่ระเหยไปที่const int (ตัวชี้คือความผันผวนตัวชี้ int คือ [เข้าถึงเป็น] const)
gx_

@supercat และเป็น "ตัวชี้ไปยังอาร์เรย์ของตัวชี้ไปยังจำนวนเต็ม" (ผมไม่ทราบว่าปาสกาลไม่แน่ใจเกี่ยวกับ[3..4]ไวยากรณ์จึงขอใช้อาร์เรย์ของ 10 int *(*foo)[10];องค์ประกอบเป็นพิเศษ): มันสะท้อน (ในอนาคต) ใช้เป็นนิพจน์: *(*foo)[i](ด้วยiจำนวนเต็มในช่วง[0, 10)ie [0, 9]) จะfooพิจารณาถึงอาร์เรย์เป็นอันดับแรกจากนั้นเข้าถึงองค์ประกอบที่ดัชนีi(เนื่องจาก postfix []ผูกแน่นกว่าคำนำหน้า*) จากนั้นจึงยกเลิกองค์ประกอบนี้ในที่สุด ให้ผลint(ดูideone.com/jgjIjR ) แต่typedefทำให้ง่ายขึ้น (ดูideone.com/O3wb7d )
gx_

102

เพื่อหลีกเลี่ยงความสับสนให้ผนวก const qualifier เสมอ

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
ทำไม? "เพื่อหลีกเลี่ยงความสับสน" ไม่ได้อธิบายว่าความสับสนสำหรับฉันคืออะไร
Andrew Weir

14
@ แอนดรูว์: ฉันพูดเป็นนัยเรื่องความมั่นคงและอ่านง่าย การเขียนตัวระบุประเภททั้งหมดเพื่อให้พวกเขาแก้ไขสิ่งที่อยู่ทางซ้ายเสมอคือสิ่งที่ฉันใช้
diapir

1
จริงๆแล้วมันเป็นคำตอบที่ดีที่สุดในเรื่องที่ฉันพบใน SO
กับดัก

8
ในฐานะที่เป็นมาตรฐานรหัสฉันไม่ค่อยพบสไตล์นี้และดังนั้นจึงไม่น่าจะนำมาใช้ อย่างไรก็ตามเป็นเครื่องมือการเรียนรู้คำตอบนี้มีประโยชน์มาก! (ดังนั้นฉันจึงคิดว่าแย่เกินไปนี่ไม่ใช่สไตล์ที่ธรรมดากว่า)
natevw

8
@Alla: ไม่เกี่ยวข้องกับประเภท:p (const int *const)สำหรับ postfix ดีขึ้นหรือแย่ (ที่เลวร้ายยิ่งถ้าคุณถามฉัน) รอบคัดเลือก const ทั้งใน C และ C ++ จะหมายถึงการเป็น: CF void foo(int a) const;ฟังก์ชันสมาชิก ความเป็นไปได้ที่จะประกาศconst intเป็นข้อยกเว้นมากกว่ากฎ
diapir

44

const ปรับเปลี่ยนสิ่งที่อยู่ข้างหน้ามันเสมอ (ทางด้านซ้ายของมัน) ยกเว้นเมื่อเป็นสิ่งแรกในการประกาศประเภทซึ่งจะแก้ไขสิ่งที่เกิดขึ้นหลังจากนั้น (ทางด้านขวาของมัน)

ดังนั้นทั้งสองจึงเหมือนกัน:

int const *i1;
const int *i2;

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

Rule of thumb:อ่านคำนิยามจากขวาไปซ้าย!


const int *foo;

หมายถึง " foopoints ( *) ถึง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. ถ่าน * const xหมายถึงตัวชี้อักขระซึ่งเป็นค่าคงที่ แต่ตำแหน่งที่ชี้สามารถเปลี่ยนแปลงได้

  3. const char * const xเป็นการรวมกันของ 1 และ 2 หมายความว่ามันเป็นตัวชี้อักขระคงที่ซึ่งชี้ไปที่ค่าคงที่

  4. const * char xจะทำให้เกิดข้อผิดพลาดของคอมไพเลอร์ ไม่สามารถประกาศได้

  5. ถ่าน const * xเท่ากับจุด 1

กฎของหัวแม่มือคือถ้าconstเป็นชื่อ var แล้วตัวชี้จะคงที่ แต่ตำแหน่งชี้สามารถเปลี่ยนแปลงได้ตัวชี้อื่นจะชี้ไปที่ตำแหน่งคงที่และตัวชี้สามารถชี้ไปที่ตำแหน่งอื่น แต่เนื้อหาตำแหน่งของจุดเปลี่ยนไม่สามารถเปลี่ยนแปลงได้


1
"char * const x อ้างถึงตัวชี้อักขระซึ่งเป็นค่าคงที่ แต่ตำแหน่งที่ชี้อยู่สามารถเปลี่ยนแปลงได้" ไม่ถูกต้อง. ค่าที่ตั้งสามารถเปลี่ยนแปลงได้ไม่ใช่ที่ตั้งเอง
PleaseHelp

3

ข้อแรกคือข้อผิดพลาดทางไวยากรณ์ บางทีคุณอาจหมายถึงความแตกต่างระหว่าง

const char * mychar

และ

char * const mychar

ในกรณีนั้นตัวแรกคือตัวชี้ไปยังข้อมูลที่ไม่สามารถเปลี่ยนแปลงได้และตัวที่สองคือตัวชี้ที่จะชี้ไปยังที่อยู่เดียวกันเสมอ


3

กฎง่ายๆอีกข้อหนึ่งคือการตรวจสอบว่าconst คือ :

  1. before * => ค่าที่เก็บไว้เป็นค่าคงที่
  2. หลังจาก * => ตัวชี้ตัวเองเป็นค่าคงที่

3

คำตอบมากมายให้เทคนิคที่เฉพาะเจาะจงกฎของหัวแม่มือและอื่น ๆ เพื่อทำความเข้าใจกับอินสแตนซ์เฉพาะของการประกาศตัวแปร แต่มีเทคนิคทั่วไปในการทำความเข้าใจการประกาศใด ๆ :

กฎตามเข็มนาฬิกา / เกลียว

A)

const char *a;

ตามกฎตามเข็มนาฬิกา / เกลียวaเป็นตัวชี้ไปยังตัวละครที่มีค่าคงที่ ซึ่งหมายความว่าตัวละครมีค่าคงที่ แต่ตัวชี้สามารถเปลี่ยนได้ ie a = "other string";คือดี แต่a[2] = 'c';จะล้มเหลวในการรวบรวม

B)

char * const a;

ตามกฎแล้วaตัวชี้ const จะเป็นตัวอักษร เช่นคุณสามารถทำได้a[2] = 'c';แต่คุณไม่สามารถทำได้a = "other string";


1
หรือที่เรียกว่ากฎซ้ายขวา (อย่างน้อยนั่นก็เป็นวิธีที่ฉันเรียนรู้): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Tomas Pruzina

(จะดีกว่ามากถ้าสาระสำคัญของคำตอบจะไม่ถูกซ่อนอยู่หลังลิงก์พร้อมกับข้อความที่นี่ไม่ได้อ้างถึงหรืออย่างน้อยก็อ้างอิงถึงข้อมูลเฉพาะใด ๆ ของมันนอกเหนือจากทั่วไป "ตามกฎ")
ของแท้

@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 มัวร์ขอบคุณ
Megharaj

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

ถ่าน * const และ const ถ่าน *?

  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 สร้างสำหรับ "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

ฉันจำได้จากหนังสือภาษาเช็กเกี่ยวกับ C: อ่านคำประกาศที่คุณเริ่มต้นด้วยตัวแปรแล้วไปทางซ้าย ดังนั้นสำหรับ

char * const a;

คุณสามารถอ่านเป็น: " aเป็นตัวแปรของตัวชี้คงที่ประเภทถึงchar",

char const * a;

คุณสามารถอ่านเป็น: " aเป็นตัวชี้ไปยังตัวแปรประเภท char ฉันหวังว่านี่จะช่วยได้

โบนัส:

const char * const a;

คุณจะอ่านตามที่aเป็นตัวชี้คงที่ตัวแปรคงที่ของประเภทถ่าน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.