Cách khai báo biến con trỏ đúng trong C / C ++ [đóng]


91

Tôi nhận thấy một số người sử dụng ký hiệu sau để khai báo các biến con trỏ.

(a) char* p;

thay vì

(b) char *p;

Tôi sử dụng (b). Hợp lý đằng sau ký hiệu (a) là gì? Ký hiệu (b) có ý nghĩa hơn đối với tôi vì bản thân con trỏ ký tự không phải là một kiểu. Thay vào đó, kiểu là ký tự và biến có thể là một con trỏ đến ký tự.

char* c;

Điều này có vẻ như có một kiểu char * và biến c thuộc kiểu đó. Nhưng thực tế kiểu là char và * c (vị trí bộ nhớ được trỏ bởi c) là kiểu đó (char). Nếu bạn khai báo nhiều biến cùng một lúc thì sự phân biệt này trở nên rõ ràng.

char* c, *d;

Điều này trông kỳ lạ. Cả c và d đều là cùng một loại con trỏ trỏ đến một ký tự. Trong này vì cái tiếp theo trông tự nhiên hơn.

char *c, *d;

Cảm ơn.


7
Ý bạn là gì con trỏ char không phải là một loại? Bạn đang nói rằng một con trỏ không phải là một loại?
Benjamin Lindley

1
Tôi tin rằng đó là một vấn đề ưu tiên trừ khi bạn đang xem một hướng dẫn phong cách cụ thể (nghĩa là công ty của bạn có thể có một tiêu chuẩn mã hóa nhất định mà bạn phải tuân theo). Tôi có xu hướng kết hợp nó giữa lựa chọn b và một số ở giữa. Đôi khi tôi cảm thấy không char *tphù hợp, vì vậy tôi có thể làm char * t;thay thế. Tuy nhiên, tôi cũng thường xuyên nhìn thấy char* t;.
RageD

1
Ngoài ra, lập luận của bạn "kiểu là char và * c (vị trí bộ nhớ được trỏ bởi c) thuộc kiểu đó (char)" dường như chỉ ra rằng có một char đang được khai báo, trong khi thực tế thì không. Nếu nó được đối xử như vậy, như đôi khi đối với những người mới bắt đầu, nó chắc chắn sẽ dẫn đến vi phạm truy cập bộ nhớ.
Benjamin Lindley

1
Cả hai đều vẫn đủ mô tả, (b) chương trình * p là loại charvà (a) cho thấy p là mộtpointer to a char
Một người

1
Với hơn một thập kỷ kinh nghiệm trong ngành, hôm nay là lần đầu tiên điều này được đưa ra và chỉ khi đọc các bài báo từ các chuyên gia trong ngành khác. Rõ ràng, sau đó, tôi chưa bao giờ có bất kỳ cuộc trò chuyện tôn giáo nào về những điều này như tôi đã từng có với tab v dấu cách, nhận xét bằng def hoặc dec, hoặc bất kỳ chủ đề nào khác "thật tốt khi không có gì quan trọng hơn để tranh luận về" . Đó là quan điểm của tôi, tôi đã thích, rất muộn trong trò chơi của sự nghiệp, đi với "char * p" thường xuyên hơn là không. Có, khoảng trắng trước, khoảng trắng sau. Phần lớn theo tôi thấy nó làm giảm lỗi, vì nó làm cho con trỏ rõ ràng hơn.
Kit10

Câu trả lời:


102

Bjarne Stroustrup nói:

Sự lựa chọn giữa "int * p;" và "int * p;" không phải về đúng sai, mà là về phong cách và điểm nhấn. C nhấn mạnh biểu thức; tuyên bố thường được coi là ít hơn một điều xấu xa cần thiết. Mặt khác, C ++ chú trọng nhiều đến kiểu.

Một "lập trình viên C điển hình" viết "int * p;" và giải thích nó "* p là cú pháp nhấn mạnh int" là gì và có thể trỏ đến ngữ pháp khai báo C (và C ++) để tranh luận về tính đúng đắn của kiểu. Thật vậy, dấu * liên kết với tên p trong ngữ pháp.

Một "lập trình viên C ++ điển hình" viết "int * p;" và giải thích nó "p là một con trỏ tới kiểu nhấn mạnh int". Thật vậy kiểu của p là int *. Tôi rõ ràng thích sự nhấn mạnh đó và xem nó là quan trọng để sử dụng tốt các phần nâng cao hơn của C ++.

Nguồn: http://www.stroustrup.com/bs_faq2.html#whitespace

Tôi khuyên bạn nên sử dụng kiểu thứ hai bởi vì trong trường hợp bạn khai báo nhiều con trỏ trong một dòng (ví dụ thứ 4 của bạn), việc có dấu hoa thị với biến sẽ là điều bạn đã quen.


34
Những người khác khuyến nghị không bao giờ khai báo nhiều đối tượng trong cùng một khai báo. :-)
Bo Persson

5
Tôi nhấn mạnh logic đằng sau cú pháp, do đó tôi thích : int *p, nghĩa là: khi nào pđược tham chiếu, tôi nhận được một int. Sau đó, nhiều khai báo được phân tách bằng cách ,có ý nghĩa: int *p, *q, r(khi nào phoặc qđược tham chiếu thì tôi nhận được một int, khi nào rđược tham chiếu tôi nhận được một int). Ngoài ra, cú pháp con trỏ hàm có ý nghĩa: int (*f)()(khi nào fđược tham chiếu đến và được gọi là tôi nhận được một int). Và điều này có ý nghĩa: int *p, (*f)().
Druesukker

2
Điều này đã giúp tôi nhận ra có giá trị đối với mặt khác của lập luận. Tôi nhấn mạnh đến phần lớn là một lập trình viên cấp cao; và thích hơn int*. Đối với tôi, int *p, (*f)()không có ý nghĩa gì nhiều, nhưng tôi có thể thấy nó sẽ như thế nào đối với một số người trong một số tình huống.
Assimilater

1
@Druesukker, tôi nghĩ câu nói của bạn có ý nghĩa hơn bất kỳ câu nào ở trên.
Muntashir Akon

1
@Druesukker Nhưng logic không hoạt động chính xác void*(và hoàn toàn không hoạt động đối với các tham chiếu C ++).
jamesdlin

57

Cá nhân tôi thích đặt *phần còn lại của loại

char* p;  // p is a pointer to a char.

Mọi người sẽ tranh luận "nhưng sau đó char* p, q;trở nên sai lệch", mà tôi nói, "vì vậy đừng làm như vậy".


Đối số rất tốt cho char * p; Lựa chọn :) Tôi không bận tâm đến bất kỳ điều gì trong số họ miễn là nó không trở nên khó đọc như ví dụ bạn đã cho thấy trong trường hợp họ không nên làm điều đó.
Jesus Ramos

1
Và khi nào bạn muốn xuất giá trị? Bạn làm cout << *p;. Vậy tại sao không đặt ngôi sao trước khi p khai báo : *p? Theo tôi, nó sẽ ít khó hiểu hơn.
user1170330,

13
@ user1170330, Bởi vì ở một vị trí, nó là một phần của định nghĩa kiểu, và nó là một toán tử tham chiếu ở nơi khác. Không có mối quan hệ. Nếu có gì thì tốt là chúng trông khác nhau, vì những thứ khác nhau sẽ trông khác.
ikegami

32

Không có sự khác biệt về cách viết. Nhưng nếu bạn muốn khai báo hai hoặc nhiều con trỏ trong một dòng thì tốt hơn nên sử dụng biến thể (b), vì nó rõ ràng bạn muốn gì. Xem bên dưới:

int *a;
int* b;      // All is OK. `a` is pointer to int ant `b` is pointer to int
char *c, *d; // We declare two pointers to char. And we clearly see it.
char* e, f;  // We declare pointer `e` and variable `f` of char type.
             // Maybe here it is mistake, maybe not. 
// Better way of course is use typedef:
typedef char* PCHAR;
PCHAR g, h;  // Now `g` and `h` both are pointers.
// If we used define construction for PCHAR we'd get into problem too.

5
typedefkhông phải là cách tốt hơn "tất nhiên". Một số người có thể thích nó, nhưng sẽ có vấn đề nếu có nhiều người làm việc với mã của bạn. Nếu tôi không quen PCHAR, tôi có thể viết một cái gì đó như PCHAR *p;, đó sẽ là một char**và không phải những gì tôi dự định. Nói chung, nếu bạn muốn một char**, bạn phải viết PCHAR*hoặc xác định một kiểu mới, và sau đó nó bắt đầu trở nên ngu ngốc.
BlackJack

3
Nếu một người cần một số loại con trỏ phức tạp như con trỏ để hoạt động, bạn nên tạo typedefs. Họ làm cho mã đơn giản hơn nhiều trong trường hợp này. Mặt khác, sử dụng PCHAR là một ví dụ tổng hợp hơn là thực hành hàng ngày. Nhưng nó rõ ràng làm cho những gì bạn muốn. và sau đó nó chỉ bắt đầu trở thành ngu ngốc Xin gửi trực tiếp tất cả các khiếu nại để Stroustrup :-)
George Gaal

Nếu bạn viết PCHAR * p để xác định một con trỏ tới char thì rõ ràng là bạn không biết mình đang làm gì và không đọc kiểu def. Câu trả lời là theo ý kiến ​​của anh ấy. Có một lợi ích khác cho typedef; trong C đó là những cách dễ dàng để làm cho mọi thứ trở nên mờ đục. công khai có ký hiệu được định nghĩa là VOID ptr, riêng tư loại def là một cái gì đó khác .... Tôi muốn điều chỉnh typedef một lần sau đó điều chỉnh mọi thứ trong suốt mã khi chúng tôi thay đổi điều gì đó về một trong các loại ... nhưng C ++ 11 giải quyết phần lớn vấn đề đó bằng auto's
UpAndAdam 29/05

Đối với một số người chỉ muốn quay lại trò chơi với C ++ năm năm sau đại học, đây là một trong những câu trả lời tốt nhất.
Panzercrisis

10

Thỏa hiệp là

char * p;

K&R sử dụng

char *p;

Điều đó tùy thuộc vào bạn trừ khi bạn đang tuân theo một tiêu chuẩn mã hóa - trong trường hợp đó, bạn nên tuân theo những gì mọi người khác làm.


4
Tôi đã học một cách khó khăn rằng char * x, y không có nghĩa là y là char *. Bây giờ tôi có thể hiểu tại sao K&R lại đi theo phong cách đã nói.
Rahul Kadukar

K&R là gì và tại sao nó lại quan trọng với những gì một nguồn mã sử dụng? Tôi sử dụng char* p;. đó là vấn đề của phong cách, không phải quy ước hay quy tắc. đối với tôi, nó có ý nghĩa hơn rằng p là loại char*, vì vậy rõ ràng là * phải ở cùng với loại.
FalcoGer

@FalcoGer Tôi đã thêm một liên kết cho K&R. Không quan trọng một nguồn mã sử dụng. Nhóm của bạn có thể khó chịu với bạn nếu bạn không tuân theo tiêu chuẩn của họ vì bạn đang khiến họ làm việc nhiều hơn để hiểu mã của bạn. Những ngày này, tôi hy vọng rằng các đội vẫn đang sử dụng clang-format.
jnnnnn

2

Tất cả đều là vấn đề ưu tiên, cá nhân đối với các dự án mà tôi thấy ký tự *, tôi có xu hướng khai báo nhiều con trỏ trên các dòng riêng biệt. Không có cách nào thực sự "đúng" để làm điều này và tất cả đều phụ thuộc vào sở thích. Một số người nói rằng nó dễ đọc hơn (a) trong khi những người khác nói rằng (b) dễ dàng hơn để khai báo nhiều biến cùng loại trên cùng một dòng.

Tôi thấy (b) phổ biến hơn, và trong một số trường hợp, tôi đã thấy

char * a;

hoặc thứ gì đó giống thế này. Một lần nữa ưu tiên. Bất cứ điều gì bạn cảm thấy thoải mái hoặc bất kỳ dự án nào tôi đang làm, tôi sẽ sử dụng (trừ khi tôi tự viết nó trong trường hợp đó tôi sử dụng (a))

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.