Sự khác biệt giữa char * const và const char * là gì?


279

Sự khác biệt giữa:

char * const 

const char *


8
Điều đầu tiên bên trái của "const" là những gì không đổi. Nếu "const" là thứ xa nhất bên trái, thì thứ đầu tiên bên phải của nó là thứ không đổi.
Cupcake

4
Là một mẹo thân thiện, đừng bao giờ quên rằng cdecl là một thứ.
Braden hay nhất

Có một char const * khác là kiểu trả về của ngoại lệ :: what ()
Zhang

Câu trả lời:


363

Sự khác biệt là const char *một con trỏ đến a const char, trong khi char * constlà một con trỏ không đổi đến a char.

Đầu tiên, giá trị được trỏ đến không thể thay đổi nhưng con trỏ có thể. Thứ hai, giá trị được trỏ vào có thể thay đổi nhưng con trỏ không thể (tương tự như tham chiếu).

Cũng có một

const char * const

đó là một con trỏ liên tục đến một char không đổi (vì vậy không có gì có thể thay đổi).

Ghi chú:

Hai hình thức sau là tương đương:

const char *

char const *

Lý do chính xác cho điều này được mô tả trong tiêu chuẩn C ++, nhưng điều quan trọng cần lưu ý và tránh nhầm lẫn. Tôi biết một số tiêu chuẩn mã hóa thích:

char const

kết thúc

const char

(có hoặc không có con trỏ) sao cho vị trí của constphần tử giống như với con trỏ const.


6
Sẽ đáng để lưu ý điều gì xảy ra nếu nhiều biến được chỉ định trong cùng một khai báo? Tôi tin rằng const int *foo,*bar;sẽ tuyên bố cả hai foobarđược int const *, nhưng int const *foo, *barsẽ tuyên bố foolà một int const *barđược int *. Tôi nghĩ rằng typedef int * intptr; const intptr foo,bar;sẽ khai báo cả hai biến là int * const; Tôi không biết cách nào để sử dụng khai báo kết hợp để tạo hai biến loại đó mà không cần typedef.
supercat

1
@supercat I believe const int *foo,*bar; would declare both foo and bar to be int const *: Vâng. but int const *foo, *bar would declare foo to be a int const * and bar to be int *: Không! Nó sẽ giống hệt như trường hợp trước. (Xem ideone.com/RsaB7n nơi bạn gặp cùng một lỗi cho cả foo và bar). I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const: Đúng. I don't know any way to use a combined declaration to create two variables of that type without a typedef: Vâng , int *const foo, *const bar;. Cú pháp khai báo C ...
gx_

@gx_: Vì vậy, tôi đã sai - sự không chắc chắn của tôi là lý do tại sao tôi đề nghị rằng có thể hữu ích để nói các quy tắc là gì. Sẽ int const *foo, *volatile barlàm gì bar? Làm cho cả hai constvolatile? Tôi nhớ rằng việc phân tách rõ ràng các tên biến khai báo của Pascal và các kiểu của chúng (một con trỏ tới một mảng các con trỏ tới các số nguyên sẽ là var foo: ^Array[3..4] of ^Integer: `. Đó sẽ là một số dấu ngoặc đơn được lồng vào nhau trong C, tôi nghĩ vậy
supercat

3
@supercat (oh, C-chỉ, xin lỗi vì sự Copy đoạn code C ++, tôi đã đến đây từ một ++ câu hỏi C) Đó là tất cả về cú pháp khai C , với một ( "tinh khiết") loại phần tiếp theo là một declarator . Trong " int const *foo, *volatile bar" phần loại là int const(dừng trước *) và người khai báo là *foo(biểu thức *foosẽ biểu thị một int const) và *volatile bar; đọc từ phải sang trái (quy tắc tốt cho vòng loại cv ), foolà con trỏ tới const int và barlà con trỏ dễ bay hơi cho const int (chính con trỏ dễ bay hơi, int nhọn được [truy cập là] const).
gx_

@supercat Và đối với "con trỏ tới một mảng các con trỏ tới số nguyên" (Tôi không biết Pascal, không chắc chắn về [3..4]cú pháp, vì vậy hãy lấy một mảng gồm 10 phần tử) : int *(*foo)[10];. Nó phản ánh (sử dụng trong tương lai) của nó như là một biểu thức: *(*foo)[i](với imột số nguyên trong phạm vi [0, 10)tức là [0, 9]) sẽ lần đầu tiên foonhận được tại mảng, sau đó truy cập vào phần tử tại chỉ mục i(vì hậu []tố liên kết chặt chẽ hơn tiền tố *), sau đó cuối cùng là phần tử này mang lại một int(xem ideone.com/jgjIjR ). Nhưng typedeflàm cho nó dễ dàng hơn (xem ideone.com/O3wb7d ).
gx_

102

Để tránh nhầm lẫn, luôn luôn nối thêm vòng loại 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
Tại sao? "Để tránh nhầm lẫn" không giải thích được sự nhầm lẫn với tôi là gì.
Andrew Weir

14
@Andrew: Tôi đã gợi ý về tính nhất quán và do đó dễ đọc. Viết tất cả các loại vòng loại để họ sửa đổi những gì bên trái của họ, luôn luôn , là những gì tôi sử dụng.
diapir

1
Trên thực tế, đó là câu trả lời hay nhất về chủ đề tôi đã tìm thấy trong SO
Bẫy

8
Là một tiêu chuẩn mã, tôi hiếm khi gặp phong cách này và vì vậy không có khả năng áp dụng nó. Tuy nhiên, là một công cụ học tập, câu trả lời này rất hữu ích! (Vì vậy, tôi đoán quá tệ, đây không phải là phong cách phổ biến hơn.)
natevw

8
@ ALLa: pkhông liên quan đến loại : (const int *const). Cho tốt hơn hoặc tồi tệ hơn (tệ hơn nếu bạn hỏi tôi) vòng loại const, cả trong C và C ++, có nghĩa là postfix: hàm cf const thành viên void foo(int a) const;. Khả năng khai báo const intlà ngoại lệ chứ không phải là quy tắc.
diapir

44

const luôn luôn sửa đổi thứ xuất hiện trước nó (ở bên trái của nó), NGOẠI TRỪ khi đó là điều đầu tiên trong một khai báo kiểu, trong đó nó sửa đổi điều xuất hiện sau nó (bên phải của nó).

Vì vậy, hai cái này giống nhau:

int const *i1;
const int *i2;

họ định nghĩa con trỏ tới a const int. Bạn có thể thay đổi vị trí i1i2điểm, nhưng bạn không thể thay đổi giá trị mà chúng trỏ đến.

Điều này:

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

xác định một constcon trỏ tới một số nguyên và khởi tạo nó để trỏ đến vị trí bộ nhớ 12345678. Bạn có thể thay đổi intgiá trị tại địa chỉ 12345678, nhưng bạn không thể thay đổi địa chỉ i3trỏ đến.


22

const * charlà mã C không hợp lệ và là vô nghĩa. Có lẽ bạn muốn hỏi sự khác biệt giữa a const char *và a char const *, hoặc có thể là sự khác biệt giữa a const char *và a char * const?

Xem thêm:


18

const char*là một con trỏ tới một ký tự không đổi
char* constlà một con trỏ không đổi cho một ký tự
const char* constlà một con trỏ không đổi đến một ký tự không đổi


9

Nguyên tắc nhỏ: đọc định nghĩa từ phải sang trái!


const int *foo;

Có nghĩa là " foođiểm ( *) đến mức intkhông thể thay đổi ( const)".
Đối với lập trình viên, điều này có nghĩa là "Tôi sẽ không thay đổi giá trị của những gì footrỏ đến".

  • *foo = 123;hoặc foo[0] = 123;sẽ không hợp lệ.
  • foo = &bar; được cho phép.

int *const foo;

Có nghĩa là " fookhông thể thay đổi ( const) và điểm ( *) thành một int".
Để các lập trình viên phương tiện này "Tôi sẽ không thay đổi địa chỉ bộ nhớfoođề cập đến".

  • *foo = 123;hoặc foo[0] = 123;được cho phép.
  • foo = &bar; sẽ không hợp lệ

const int *const foo;

Có nghĩa là " fookhông thể thay đổi ( const) và điểm ( *) thành intkhông thể thay đổi ( const)".
Để các lập trình viên phương tiện này "Tôi sẽ không thay đổi giá trị của những gì foođiểm đến, cũng không phải tôi sẽ thay đổi địa chỉ đó foođề cập đến".

  • *foo = 123;hoặc foo[0] = 123;sẽ không hợp lệ.
  • foo = &bar; sẽ không hợp lệ

8
  1. const char * x Ở đây X về cơ bản là một con trỏ ký tự đang trỏ đến một giá trị không đổi

  2. char * const x được dùng để chỉ con trỏ ký tự không đổi, nhưng vị trí nó đang trỏ có thể thay đổi.

  3. const char * const x được kết hợp thành 1 và 2, có nghĩa là nó là một con trỏ ký tự không đổi được trỏ đến giá trị không đổi.

  4. const * char x sẽ gây ra lỗi trình biên dịch. nó không thể được tuyên bố.

  5. char const * x bằng điểm 1.

quy tắc của ngón tay cái là nếu const có tên var thì con trỏ sẽ không đổi nhưng vị trí trỏ có thể thay đổi , con trỏ khác sẽ trỏ đến một vị trí không đổi và con trỏ có thể trỏ đến một vị trí khác nhưng nội dung vị trí trỏ không thể thay đổi .


1
"char * const x được dùng để chỉ con trỏ ký tự không đổi, nhưng vị trí nó đang trỏ có thể thay đổi." Sai lầm. Giá trị tại vị trí có thể được thay đổi không phải là vị trí.
Xin hãy giúp đỡ

3

Đầu tiên là một lỗi cú pháp. Có lẽ bạn có nghĩa là sự khác biệt giữa

const char * mychar

char * const mychar

Trong trường hợp đó, cái đầu tiên là một con trỏ tới dữ liệu không thể thay đổi và cái thứ hai là một con trỏ sẽ luôn trỏ đến cùng một địa chỉ.


3

Một quy tắc ngón tay cái khác là kiểm tra const ở đâu :

  1. trước * => giá trị được lưu là không đổi
  2. sau * => chính con trỏhằng số

3

Rất nhiều câu trả lời cung cấp các kỹ thuật cụ thể, quy tắc ngón tay cái, vv để hiểu trường hợp cụ thể này của khai báo biến. Nhưng có một kỹ thuật chung để hiểu bất kỳ tuyên bố nào:

Quy tắc theo chiều kim đồng hồ / xoắn ốc

A)

const char *a;

Theo quy tắc theo chiều kim đồng hồ / xoắn ốc alà con trỏ đến ký tự không đổi. Có nghĩa là ký tự không đổi nhưng con trỏ có thể thay đổi. tức a = "other string";là ổn nhưng a[2] = 'c';sẽ không biên dịch

B)

char * const a;

Theo quy tắc, alà con trỏ const cho một ký tự. tức là bạn có thể làm a[2] = 'c';nhưng bạn không thể làma = "other string";


1
Còn được gọi là quy tắc bên trái (ít nhất đó là cách tôi đã học): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Tomas Pruzina

(Sẽ tốt hơn nhiều nếu bản chất của câu trả lời sẽ không bị ẩn đằng sau một liên kết, với văn bản ở đây thậm chí không trích dẫn, hoặc ít nhất là đề cập đến bất kỳ chi tiết cụ thể nào, ngoài một "quy tắc chung".)
Sz.

@Sz. Bạn có bất kỳ nhầm lẫn cụ thể ở đây mà tôi có thể rõ ràng? Thực sự không có gì nhiều cho nó sau khi biết quy tắc.
PnotNP

1

Tôi đoán bạn có nghĩa là const char * và char * const.

Đầu tiên, const char *, là một con trỏ tới một ký tự không đổi. Các con trỏ chính nó là có thể thay đổi.

Thứ hai, char * const là một con trỏ không đổi cho một ký tự. Con trỏ không thể thay đổi, ký tự mà nó trỏ tới có thể.

Và sau đó là const char * const nơi con trỏ và ký tự không thể thay đổi.


Hai cái đầu tiên của bạn thực sự giống nhau và cái thứ ba của bạn là lỗi trình biên dịch :)
workmad3

1

Dưới đây là một lời giải thích chi tiết với mã

/*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 Cảm ơn bạn.
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. Con trỏ không đổi: Một con trỏ không đổi chỉ có thể trỏ đến một biến duy nhất của kiểu dữ liệu tương ứng trong toàn bộ chương trình. Chúng tôi có thể thay đổi giá trị của biến được trỏ bởi con trỏ. Khởi tạo nên được thực hiện trong thời gian khai báo chính nó.

Cú pháp:

datatype *const var;

char *const đến trong trường hợp này.

/*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. Con trỏ tới một giá trị const : Trong đó, một con trỏ có thể trỏ bất kỳ số lượng biến nào của loại tương ứng nhưng chúng ta không thể thay đổi giá trị của đối tượng được trỏ bởi con trỏ tại thời điểm cụ thể đó.

Cú pháp:

const datatype *varhoặc là datatype const *var

const char* đến trong trường hợp này.

/* 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 và const char *?

  1. Chỉ vào một giá trị không đổi

const char * p; // giá trị không thể thay đổi

  1. Con trỏ liên tục đến một giá trị

char * const p; // địa chỉ không thể thay đổi

  1. Con trỏ không đổi đến một giá trị không đổi

const char * const p; // cả hai không thể thay đổi.


1

Công cụ constsửa đổi được áp dụng cho thuật ngữ ngay bên trái của nó. Ngoại lệ duy nhất này là khi không có gì ở bên trái của nó, sau đó nó áp dụng cho những gì ngay bên phải của nó.

Đây là tất cả các cách tương đương để nói "con trỏ không đổi đến hằng số char":

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

Là nó phụ thuộc trình biên dịch? gcc sản xuất cho "const char const *" và "const const char *" và "char const const *" cùng một kết quả -> con trỏ có thể trỏ đến vị trí khác.
cosinus0

1

Hai quy tắc

  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.

ví dụ

  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

Tôi muốn chỉ ra rằng việc sử dụng int const *(hoặc const int *) không phải là về một con trỏ trỏ đến một const intbiến, mà là biến này constdành cho con trỏ cụ thể này.

Ví dụ:

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

Các mã trên biên dịch hoàn toàn tốt. _pchỉ đến một constbiến, mặc dù varbản thân nó không phải là hằng số.


1

Tôi nhớ từ cuốn sách tiếng Séc về C: đọc phần khai báo rằng bạn bắt đầu với biến và rẽ trái. Vì vậy đối với

char * const a;

bạn có thể đọc là: " alà biến của kiểu con trỏ không đổi char",

char const * a;

bạn có thể đọc là: " alà một con trỏ tới biến hằng của kiểu char. Tôi hy vọng điều này có ích.

Tặng kem:

const char * const a;

Bạn sẽ đọc như alà con trỏ không đổi đến biến hằng của kiểu char.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.