วิธีที่ถูกต้องในการประกาศตัวแปรตัวชี้ใน C / C ++ [ปิด]


92

ฉันสังเกตเห็นบางคนใช้สัญกรณ์ต่อไปนี้ในการประกาศตัวแปรตัวชี้

(a) char* p;

แทน

(b) char *p;

ฉันใช้ (b) อะไรคือเหตุผลที่อยู่เบื้องหลังสัญกรณ์ (ก)? สัญกรณ์ (b) มีความหมายสำหรับฉันมากขึ้นเนื่องจากตัวชี้อักขระไม่ใช่ประเภทเอง แทนที่จะเป็นประเภทอักขระและตัวแปรอาจเป็นตัวชี้ไปยังอักขระ

char* c;

ดูเหมือนว่ามีประเภท char * และตัวแปร c เป็นประเภทนั้น แต่ในความเป็นจริงประเภทคือถ่านและ * c (ตำแหน่งหน่วยความจำที่ชี้โดย c) เป็นประเภทนั้น (ถ่าน) หากคุณประกาศตัวแปรหลายตัวพร้อมกันความแตกต่างนี้จะชัดเจน

char* c, *d;

มันดูแปลก ๆ ทั้ง c และ d เป็นพอยน์เตอร์ชนิดเดียวกันที่ชี้ไปที่อักขระ ในสิ่งนี้ตั้งแต่ครั้งต่อไปดูเป็นธรรมชาติมากขึ้น

char *c, *d;

ขอบคุณ.


7
คุณหมายถึงอะไรตัวชี้ถ่านไม่ใช่ประเภท? คุณกำลังบอกว่าตัวชี้ไม่ใช่ประเภท?
Benjamin Lindley

1
ฉันเชื่อว่ามันเป็นเรื่องของความชอบเว้นแต่คุณจะดูคู่มือรูปแบบเฉพาะ (เช่น บริษัท ของคุณอาจมีมาตรฐานการเข้ารหัสที่คุณต้องปฏิบัติตาม) ฉันมักจะผสมระหว่างตัวเลือก b กับบางตัวที่อยู่ตรงกลาง บางครั้งฉันรู้สึกว่าchar *tดูไม่เหมาะสมดังนั้นฉันอาจทำchar * t;แทน อย่างไรก็ตามฉันได้เห็นบ่อยchar* t;เช่นกัน
RageD

1
นอกจากนี้การให้เหตุผลของคุณ"ประเภทคือถ่านและ * c (ตำแหน่งหน่วยความจำที่ชี้โดย c) เป็นประเภทนั้น (ถ่าน)"ดูเหมือนจะบ่งบอกว่ามีการประกาศถ่าน แต่ในความเป็นจริงไม่มี หากได้รับการปฏิบัติเช่นนี้เนื่องจากบางครั้งเป็นโดยผู้เริ่มต้นจะนำไปสู่การละเมิดการเข้าถึงหน่วยความจำอย่างแน่นอน
Benjamin Lindley

1
ทั้งสองยังคงเป็นคำอธิบายที่เพียงพอ (b) แสดง * p เป็นประเภทcharและ (a) แสดง p คือ apointer to a char
บุคคล

1
ด้วยประสบการณ์ในอุตสาหกรรมกว่าทศวรรษวันนี้เป็นครั้งแรกที่เกิดขึ้นและเฉพาะในการอ่านบทความจากผู้เชี่ยวชาญในอุตสาหกรรมอื่น ๆ เห็นได้ชัดว่าฉันไม่เคยมีการสนทนาทางศาสนาเกี่ยวกับเรื่องเหล่านี้เหมือนที่ฉันเคยมีด้วยแท็บ v ช่องว่างความคิดเห็นโดย def หรือ dec หรืออื่น ๆ "เป็นการดีที่ไม่มีอะไรสำคัญกว่าที่จะโต้แย้งเกี่ยวกับ" หัวข้อ . นั่นเป็นมุมมองของฉันฉันชอบมากในช่วงท้ายเกมอาชีพของฉันไปกับ "char * p" บ่อยกว่าไม่ ใช่เว้นวรรคก่อนเว้นวรรคหลัง ส่วนใหญ่ที่ฉันพบว่ามันช่วยลดจุดบกพร่องได้เนื่องจากทำให้ตัวชี้มีความชัดเจนมากขึ้น
Kit10

คำตอบ:


102

Bjarne Stroustrup กล่าวว่า:

ทางเลือกระหว่าง "int * p;" และ "int * p;" ไม่ใช่เรื่องถูกและผิด แต่เกี่ยวกับรูปแบบและการเน้น C เน้นนิพจน์; การประกาศมักถูกมองว่าเป็นสิ่งชั่วร้ายเกินความจำเป็นเพียงเล็กน้อย ในทางกลับกัน C ++ มีความสำคัญอย่างมากกับประเภท

"โปรแกรมเมอร์ C ทั่วไป" เขียน "int * p;" และอธิบายว่า "* p คืออะไร int" เน้นไวยากรณ์และอาจชี้ไปที่ไวยากรณ์การประกาศ C (และ C ++) เพื่อโต้แย้งความถูกต้องของรูปแบบ อันที่จริงเครื่องหมาย * ผูกกับชื่อ p ในไวยากรณ์

"โปรแกรมเมอร์ C ++ ทั่วไป" เขียน "int * p;" และอธิบายว่า "p คือตัวชี้ไปยังประเภทการเน้น int" ประเภทของ p คือ int * ฉันชอบการเน้นนั้นอย่างชัดเจนและเห็นว่าสำคัญสำหรับการใช้ส่วนขั้นสูงของ C ++ ให้ดี

ที่มา: http://www.stroustrup.com/bs_faq2.html#whitespace

ฉันขอแนะนำรูปแบบหลังเพราะในสถานการณ์ที่คุณประกาศพอยน์เตอร์หลายตัวในบรรทัดเดียว (ตัวอย่างที่ 4 ของคุณ) การมีเครื่องหมายดอกจันกับตัวแปรจะเป็นสิ่งที่คุณคุ้นเคย


34
คนอื่นแนะนำว่าอย่าประกาศหลายวัตถุในการประกาศเดียวกัน :-)
Bo Persson

5
ฉันเน้นตรรกะที่อยู่เบื้องหลังไวยากรณ์ดังนั้นฉันจึงชอบ: int *p, หมายถึง: เมื่อpถูกยกเลิกการอ้างอิงฉันจะได้รับintไฟล์. จากนั้นการประกาศหลายรายการที่คั่นด้วยมี,เหตุผล: int *p, *q, r(เมื่อpหรือqถูกยกเลิกการอ้างอิงฉันได้รับการอ้างอิงintเมื่อrใดฉันจะได้รับint) นอกจากนี้ไวยากรณ์ของตัวชี้ฟังก์ชันก็มีเหตุผล: int (*f)()(เมื่อfถูกยกเลิกการอ้างอิงและเรียกว่าฉันได้รับint) และนี่ก็สมเหตุสมผล: int *p, (*f)().
Druesukker

2
สิ่งนี้ช่วยให้ฉันรู้ว่าอีกด้านหนึ่งของข้อโต้แย้งมีความถูกต้อง โดยส่วนใหญ่เป็นโปรแกรมเมอร์ระดับสูงฉันเน้นประเภท int*และชอบ สำหรับฉันint *p, (*f)()มันไม่สมเหตุสมผลสักเท่าไหร่ แต่ฉันก็พอจะเห็นว่ามันจะเป็นอย่างไรสำหรับบางคนในบางสถานการณ์
Assimilater

1
@Druesukker คำพูดของคุณสมเหตุสมผลกว่าข้อใด ๆ ข้างต้นฉันคิดว่า
Muntashir Akon

1
@Druesukker แต่ตรรกะไม่ได้ผลอย่างแน่นอนvoid*(และไม่ได้ผลเลยสำหรับการอ้างอิง C ++)
jamesdlin

58

โดยส่วนตัวแล้วฉันชอบวางประเภท*ที่เหลือมากกว่า

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

ผู้คนจะโต้เถียง "แต่แล้วก็char* p, q;กลายเป็นการเข้าใจผิด" ซึ่งฉันบอกว่า "อย่าทำอย่างนั้น"


ข้อโต้แย้งที่ดีมากสำหรับถ่าน * p; choice :) ฉันไม่สนใจพวกเขาตราบเท่าที่มันไม่ยากที่จะอ่านเหมือนตัวอย่างที่คุณแสดงซึ่งในกรณีนี้พวกเขาไม่ควรทำเช่นนั้น
Jesus Ramos

1
และเมื่อคุณต้องการส่งออกค่า? cout << *p;ที่คุณทำ ทำไมไม่วางดาวไว้ก่อน pระหว่างการประกาศ: *p? ในความคิดของฉันมันจะสับสนน้อยกว่า
user1170330

13
@ user1170330 เพราะครั้งหนึ่งมันเป็นส่วนหนึ่งของนิยามประเภทและเป็นตัวดำเนินการ dereference ในอีกตัวหนึ่ง ไม่มีความสัมพันธ์ ถ้ามีอะไรก็เป็นเรื่องดีที่พวกเขาจะดูแตกต่างกันเพราะสิ่งที่แตกต่างกันควรมีลักษณะที่แตกต่าง
ikegami

33

มีวิธีการเขียนไม่แตกต่างกัน แต่ถ้าคุณต้องการประกาศตัวชี้สองตัวขึ้นไปในบรรทัดเดียวควรใช้ตัวแปร (b) เพราะมันชัดเจนว่าคุณต้องการอะไร ดูด้านล่าง:

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
typedefไม่ใช่วิธีที่ดีกว่า "แน่นอน". บางคนอาจชอบ แต่จะเป็นปัญหาหากมีหลายคนที่ทำงานกับโค้ดของคุณ ถ้าฉันไม่คุ้นเคยPCHARฉันอาจจะเขียนอะไรแบบPCHAR *p;นี้ซึ่งจะเป็นchar**และไม่ใช่สิ่งที่ฉันตั้งใจ โดยทั่วไปถ้าคุณต้องการ a char**คุณจะต้องเขียนPCHAR*หรือกำหนดประเภทใหม่จากนั้นมันก็เริ่มโง่
BlackJack

3
หากต้องการตัวชี้ที่ซับซ้อนบางประเภทเช่นตัวชี้เพื่อทำงานก็เป็นความคิดที่ดีมากที่จะสร้าง typedefs ทำให้โค้ดง่ายขึ้นมากในกรณีนี้ ในทางกลับกันการใช้ PCHAR เป็นตัวอย่างที่สังเคราะห์ได้ง่ายกว่าการปฏิบัติในชีวิตประจำวัน แต่มันทำให้สิ่งที่คุณต้องการอย่างชัดเจน แล้วมันก็เริ่มโง่โปรดส่งข้อร้องเรียนทั้งหมดไปยัง Stroustrup :-)
George Gaál

หากคุณเขียน PCHAR * p เพื่อกำหนดตัวชี้ไปยังถ่านจะเห็นได้ชัดว่าคุณไม่รู้ว่าคุณกำลังทำอะไรและไม่ได้อ่านประเภท def คำตอบอยู่ในความคิดของเขา มีประโยชน์อีกอย่างสำหรับ typedef; ใน C เป็นวิธีง่ายๆในการทำให้สิ่งทึบแสง สาธารณะมีสัญลักษณ์ที่กำหนดเป็น VOID ptr โดยส่วนตัวประเภท def เป็นอย่างอื่น .... ฉันควรปรับ typedef นาน ๆ ครั้งจากนั้นปรับทุกอย่างตลอดรหัสเมื่อเราเปลี่ยนบางสิ่งเกี่ยวกับประเภทใดประเภทหนึ่ง ... แต่ C ++ 11 กล่าวถึงส่วนใหญ่ด้วยรถยนต์
UpAndAdam

สำหรับใครบางคนที่เพิ่งลองกลับมาเล่นกับ C ++ ห้าปีหลังเลิกเรียนนี่คือหนึ่งในคำตอบที่ดีที่สุด
Panzercrisis

10

การประนีประนอมคือ

char * p;

K&Rใช้

char *p;

ขึ้นอยู่กับคุณเว้นแต่คุณจะปฏิบัติตามมาตรฐานการเข้ารหัส - ในกรณีนี้คุณควรทำตามสิ่งที่คนอื่นทำ


4
ฉันเรียนรู้วิธีที่ยากที่ char * x, y ไม่ได้หมายความว่า y เป็นถ่าน * ตอนนี้ฉันสามารถดูได้ว่าทำไม K&R จึงเป็นไปตามรูปแบบดังกล่าว
Rahul Kadukar

K&R คืออะไรและเหตุใดจึงมีความสำคัญว่าซอร์สโค้ดเดียวใช้อะไร ฉันใช้char* p;. มันเป็นเรื่องของรูปแบบไม่ใช่แบบแผนหรือกฎเกณฑ์ สำหรับฉันมันสมเหตุสมผลกว่าที่ p เป็นประเภทchar*ดังนั้นเห็นได้ชัดว่า * ควรอยู่กับประเภท
FalcoGer

@FalcoGer ฉันได้เพิ่มลิงค์สำหรับ K&R แล้ว ไม่สำคัญว่าซอร์สโค้ดเดียวจะใช้อะไร ทีมของคุณอาจรำคาญคุณหากคุณไม่ปฏิบัติตามมาตรฐานของพวกเขาเพราะคุณทำให้พวกเขาทำงานหนักขึ้นเพื่อทำความเข้าใจโค้ดของคุณ วันนี้ฉันหวังว่าทีมจะใช้clang-formatต่อไป
jnnnnn

2

ทุกอย่างเป็นเรื่องของความชอบโดยส่วนตัวในโครงการที่ฉันเห็นตัวอักษร * ฉันมักจะประกาศตัวชี้หลายตัวในบรรทัดแยกกัน ไม่มีวิธีที่ "ถูกต้อง" ที่แท้จริงในการทำเช่นนี้และทุกอย่างขึ้นอยู่กับความชอบ บางคนบอกว่าอ่านง่ายกว่า (a) ในขณะที่บางคนบอกว่า (b) ง่ายกว่าที่จะประกาศตัวแปรประเภทเดียวกันในบรรทัดเดียวกัน

ฉันพบว่า (b) เป็นเรื่องธรรมดามากขึ้นและในบางกรณีฉันเคยเห็น

char * a;

หรืออะไรทำนองนี้ การตั้งค่าอีกครั้ง ไม่ว่าคุณจะพอใจกับอะไรหรือโครงการใดก็ตามที่ฉันกำลังทำอยู่ฉันจะใช้ (เว้นแต่ฉันจะเขียนเองซึ่งในกรณีนี้ฉันใช้ (ก))

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