Chỉ có *
, []
và ()
các nhà khai thác có bất kỳ ý nghĩa trong tờ khai (C ++ cho biết thêm &
, nhưng ta sẽ không đi vào đó ở đây).
Trong tờ khai
int *p;
những int
-ness của p
được xác định bởi các Bộ xác định kiểu int
, trong khi con trỏ-Ness của p
được xác định bởi các declarator *p
.
Các loại của p
là "con trỏ đến int
"; loại này được chỉ định đầy đủ bởi sự kết hợp của bộ xác định loại int
cộng với bộ khai báo *p
.
Trong một khai báo, người khai báo giới thiệu tên của điều được khai báo ( p
) cùng với thông tin loại bổ sung không được cung cấp bởi trình xác định loại ("con trỏ tới"):
T v; // v is a single object of type T, for any type T
T *p; // p is a pointer to T, for any type T
T a[N]; // a is an N-element array of T, for any type T
T f(); // f is a function returning T, for any type T
Điều này rất quan trọng - con trỏ-ness, mảng-ness và hàm-hàm được chỉ định như một phần của bộ khai báo, không phải là bộ xác định kiểu 1 . Nếu bạn viết
int* a, b, c;
nó sẽ được phân tích thành
int (*a), b, c;
vì vậy a
sẽ chỉ được khai báo như một con trỏ tới int
; b
và c
được khai báo là int
s thường xuyên .
Các *
, []
và ()
các nhà khai thác có thể được kết hợp để tạo ra các loại tùy tiện phức tạp:
T *a[N]; // a is an N-element array of pointers to T
T (*a)[N]; // a is a pointer to an N-element array of T
T *(*f[N])(); // f is an N-element array of pointers to functions
// returning pointer to T
T *(*(*(*f)[N])())[M] // f is a pointer to an N-element array of pointers
// to functions returning pointers to M-element
// arrays of pointers to T
Lưu ý rằng *
, []
và ()
tuân theo các quy tắc ưu tiên tương tự trong các khai báo mà chúng thực hiện trong các biểu thức. *a[N]
được phân tích cú pháp như *(a[N])
trong cả khai báo và biểu thức.
Điều thực sự quan trọng cần nhận ra ở đây là hình thức khai báo khớp với hình thức biểu thức trong mã. Quay trở lại ví dụ ban đầu của chúng tôi, chúng tôi có một con trỏ tới một số nguyên có tên p
. Nếu chúng tôi muốn truy xuất giá trị số nguyên đó, chúng tôi sử dụng *
toán tử để hủy đăng ký p
, như vậy:
x = *p;
Kiểu của biểu thức *p
là int
, theo sau từ khai báo
int *p;
Tương tự, nếu chúng ta có một mảng các con trỏ tới double
và chúng ta muốn lấy một giá trị cụ thể, chúng ta lập chỉ mục vào mảng và kết quả lại:
y = *ap[i];
Một lần nữa, loại biểu thức *ap[i]
là double
, xuất phát từ khai báo
double *ap[N];
Vậy tại sao không ++
đóng một vai trò trong một bản tuyên bố như *
, []
hoặc ()
? Hoặc bất kỳ nhà điều hành khác thích +
hoặc ->
hoặc &&
?
Vâng, về cơ bản, bởi vì định nghĩa ngôn ngữ nói như vậy. Nó chỉ dành riêng *
, []
và ()
để chơi bất kỳ vai trò trong một tuyên bố, kể từ khi bạn có để có thể để xác định con trỏ, mảng, và các loại chức năng. Không có loại "tăng-này" riêng biệt, vì vậy không cần phải ++
là một phần của tuyên bố. Không có "Bitwise-này" loại, vì vậy không cần thiết phải unary &
, |
, ^
, hoặc ~
là một phần của một bản tuyên bố một trong hai. Đối với các loại sử dụng .
toán tử chọn thành viên, chúng tôi sử dụng các thẻ struct
và union
trong khai báo. Đối với các loại sử dụng ->
toán tử, chúng tôi sử dụng các thẻ struct
và union
kết hợp với *
toán tử trong trình khai báo.
- Tất nhiên, bạn có thể tạo tên typedef cho các loại con trỏ, mảng và hàm, như
typedef int *iptr;
iptr a,b,c; // all three of a, b, and c are pointers to int
nhưng một lần nữa, đó là công cụ khai báo *iptr
chỉ định tính chất con trỏ của tên typedef.
void move(int *units) { ... }
, nó là một toán tử gián tiếp. Được coi là một phần của loại, nó cũng có thể được viếtvoid move(int* units) { ... }
, mặc dù tôi thích phong cách trước đây. Bạn đọc cả hai như "con trỏ int." Xem thêm stackoverflow.com/a/8911253