ตัวชี้ C: ชี้ไปยังอาร์เรย์ที่มีขนาดคงที่


120

คำถามนี้ออกไปยังผู้เชี่ยวชาญด้าน C ที่นั่น:

ใน C สามารถประกาศตัวชี้ได้ดังนี้:

char (* p)[10];

.. ซึ่งโดยพื้นฐานแล้วระบุว่าตัวชี้นี้ชี้ไปที่อาร์เรย์ 10 ตัวอักษร สิ่งที่เรียบร้อยเกี่ยวกับการประกาศตัวชี้เช่นนี้คือคุณจะได้รับข้อผิดพลาดเวลาคอมไพล์หากคุณพยายามกำหนดตัวชี้ของอาร์เรย์ที่มีขนาดต่างกันให้กับ p นอกจากนี้ยังจะทำให้คุณมีข้อผิดพลาดเวลาคอมไพล์หากคุณพยายามกำหนดค่าของตัวชี้ถ่านให้กับ p ฉันลองใช้ gcc และดูเหมือนว่าจะใช้ได้กับ ANSI, C89 และ C99

สำหรับฉันแล้วดูเหมือนว่าการประกาศตัวชี้แบบนี้จะมีประโยชน์มากโดยเฉพาะอย่างยิ่งเมื่อส่งตัวชี้ไปยังฟังก์ชัน โดยปกติผู้คนจะเขียนต้นแบบของฟังก์ชันเช่นนี้:

void foo(char * p, int plen);

หากคุณคาดหวังว่าจะมีบัฟเฟอร์ที่มีขนาดเฉพาะคุณก็แค่ทดสอบค่าของ plen อย่างไรก็ตามคุณไม่สามารถรับประกันได้ว่าบุคคลที่ส่ง p ถึงคุณจะให้ตำแหน่งหน่วยความจำที่ถูกต้องในบัฟเฟอร์นั้น คุณต้องเชื่อมั่นว่าบุคคลที่เรียกว่าฟังก์ชันนี้ทำในสิ่งที่ถูกต้อง ในทางกลับกัน:

void foo(char (*p)[10]);

.. จะบังคับให้ผู้โทรให้บัฟเฟอร์ตามขนาดที่กำหนด

ดูเหมือนว่ามีประโยชน์มาก แต่ฉันไม่เคยเห็นตัวชี้ที่ประกาศแบบนี้ในรหัสใด ๆ ที่ฉันเคยพบ

คำถามของฉันคือมีเหตุผลใดบ้างที่คนไม่ประกาศคำชี้เช่นนี้? ฉันไม่เห็นข้อผิดพลาดที่ชัดเจนหรือไม่?


3
หมายเหตุ: เนื่องจาก C99 อาร์เรย์ไม่จำเป็นต้องมีขนาดคงที่ตามที่แนะนำโดยชื่อเรื่องจึง10สามารถแทนที่ด้วยตัวแปรในขอบเขต
MM

คำตอบ:


174

สิ่งที่คุณพูดในโพสต์ของคุณนั้นถูกต้องที่สุด ฉันจะบอกว่านักพัฒนา C ทุกคนได้รับการค้นพบที่เหมือนกันทุกประการและได้ข้อสรุปเหมือนกันทุกประการเมื่อ (ถ้า) พวกเขามีความเชี่ยวชาญในภาษา C ถึงระดับหนึ่ง

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

void foo(char (*p)[10]);

(ในภาษา C ++ สิ่งนี้ทำได้ด้วยการอ้างอิง

void foo(char (&p)[10]);

)

การดำเนินการนี้จะเปิดใช้งานการตรวจสอบประเภทระดับภาษาซึ่งจะทำให้แน่ใจว่าอาร์เรย์ที่มีขนาดที่ถูกต้องถูกระบุเป็นอาร์กิวเมนต์ ในความเป็นจริงในหลาย ๆ กรณีผู้คนใช้เทคนิคนี้โดยปริยายโดยไม่รู้ตัวด้วยซ้ำโดยซ่อนประเภทอาร์เรย์ไว้ด้านหลังชื่อ typedef

typedef int Vector3d[3];

void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);

โปรดทราบว่ารหัสข้างต้นไม่แปรผันตามความสัมพันธ์กับVector3dประเภทที่เป็นอาร์เรย์หรือstruct. คุณสามารถเปลี่ยนคำจำกัดความVector3dจากอาร์เรย์เป็น a structและย้อนกลับได้ตลอดเวลาและคุณไม่ต้องเปลี่ยนการประกาศฟังก์ชัน ไม่ว่าในกรณีใดฟังก์ชันจะได้รับออบเจ็กต์รวม "โดยการอ้างอิง" (มีข้อยกเว้นสำหรับสิ่งนี้ แต่ในบริบทของการสนทนานี้เป็นจริง)

อย่างไรก็ตามคุณจะไม่เห็นวิธีการส่งผ่านอาร์เรย์นี้อย่างชัดเจนบ่อยเกินไปเพียงเพราะมีคนจำนวนมากสับสนกับไวยากรณ์ที่ค่อนข้างซับซ้อนและไม่สะดวกพอที่จะใช้คุณสมบัติดังกล่าวของภาษา C ได้อย่างเหมาะสม ด้วยเหตุนี้ในชีวิตจริงโดยเฉลี่ยแล้วการส่งอาร์เรย์เป็นตัวชี้ไปยังองค์ประกอบแรกจึงเป็นแนวทางที่ได้รับความนิยมมากกว่า มันดู "เรียบง่ายกว่า"

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

void foo(char p[], unsigned plen);

จริงๆแล้วในหลาย ๆ กรณีการประมวลผลอาร์เรย์ที่มีขนาดรันไทม์ซึ่งมีประโยชน์มากซึ่งก่อให้เกิดความนิยมของวิธีนี้ด้วย นักพัฒนา C หลายคนไม่เคยพบ (หรือไม่เคยรับรู้) ถึงความจำเป็นในการประมวลผลอาร์เรย์ขนาดคงที่ดังนั้นจึงยังคงไม่สนใจเทคนิคขนาดคงที่ที่เหมาะสม

อย่างไรก็ตามหากขนาดอาร์เรย์คงที่จะส่งผ่านเป็นตัวชี้ไปยังองค์ประกอบ

void foo(char p[])

เป็นข้อผิดพลาดระดับเทคนิคที่สำคัญซึ่งน่าเสียดายที่แพร่หลายในปัจจุบัน เทคนิคตัวชี้ไปยังอาร์เรย์เป็นแนวทางที่ดีกว่ามากในกรณีเช่นนี้

อีกสาเหตุหนึ่งที่อาจขัดขวางการนำเทคนิคการส่งผ่านอาร์เรย์ขนาดคงที่มาใช้คือการครอบงำของวิธีการที่ไร้เดียงสาในการพิมพ์อาร์เรย์ที่จัดสรรแบบไดนามิก ตัวอย่างเช่นหากโปรแกรมเรียกใช้อาร์เรย์ประเภทคงที่char[10](ดังตัวอย่างของคุณ) นักพัฒนาทั่วไปจะเรียกmallocอาร์เรย์เป็น

char *p = malloc(10 * sizeof *p);

ไม่สามารถส่งอาร์เรย์นี้ไปยังฟังก์ชันที่ประกาศเป็น

void foo(char (*p)[10]);

ซึ่งสร้างความสับสนให้กับนักพัฒนาโดยเฉลี่ยและทำให้พวกเขาละทิ้งการประกาศพารามิเตอร์ขนาดคงที่โดยไม่คิดอะไรเพิ่มเติม ในความเป็นจริงแล้วต้นตอของปัญหาอยู่ที่mallocวิธีการที่ไร้เดียงสา mallocรูปแบบที่ปรากฏข้างต้นควรจะสงวนไว้สำหรับอาร์เรย์ขนาดเวลาทำงาน หากประเภทอาร์เรย์มีขนาดเวลาคอมไพล์วิธีที่ดีกว่าmallocจะมีลักษณะดังนี้

char (*p)[10] = malloc(sizeof *p);

แน่นอนสิ่งนี้สามารถส่งผ่านไปยังที่ระบุไว้ข้างต้นได้อย่างง่ายดาย foo

foo(p);

และคอมไพเลอร์จะทำการตรวจสอบประเภทที่เหมาะสม แต่อีกครั้งสิ่งนี้สร้างความสับสนให้กับนักพัฒนา C ที่ไม่ได้เตรียมตัวไว้มากเกินไปซึ่งเป็นสาเหตุที่คุณจะไม่เห็นมันบ่อยเกินไปในรหัสประจำวันโดยเฉลี่ย "ทั่วไป"


2
คำตอบนี้ให้คำอธิบายที่กระชับและให้ข้อมูลเกี่ยวกับความสำเร็จของ sizeof () อย่างไรบ่อยครั้งที่ล้มเหลวและวิธีที่ล้มเหลวอยู่เสมอ การสังเกตของคุณเกี่ยวกับวิศวกร C / C ++ ส่วนใหญ่ไม่เข้าใจดังนั้นการทำบางสิ่งที่พวกเขาคิดว่าพวกเขาเข้าใจแทนที่จะเป็นหนึ่งในคำทำนายมากกว่าที่ฉันเคยเห็นในช่วงเวลาหนึ่งและม่านก็ไม่มีอะไรเทียบได้กับความแม่นยำที่อธิบาย อย่างจริงจังครับ คำตอบที่ดี
WhozCraig

ฉันเพิ่งปรับโครงสร้างโค้ดใหม่ตามคำตอบนี้ไชโยและขอบคุณสำหรับทั้ง Q และ A.
Perry

1
ฉันอยากรู้ว่าคุณจัดการกับconstทรัพย์สินด้วยเทคนิคนี้อย่างไร const char (*p)[N]อาร์กิวเมนต์ดูเหมือนจะไม่เข้ากันได้กับตัวชี้ไปchar table[N];ในทางตรงกันข้ามง่ายๆchar*PTR ยังคงเข้ากันได้กับconst char*ข้อโต้แย้ง
ฟ้า

4
มันอาจจะเป็นประโยชน์ที่จะทราบว่าในการเข้าถึงองค์ประกอบของอาร์เรย์ของคุณคุณต้องทำและไม่ได้(*p)[i] *p[i]ตัวหลังจะเพิ่มขึ้นตามขนาดของอาร์เรย์ซึ่งแทบจะไม่ใช่สิ่งที่คุณต้องการ อย่างน้อยสำหรับฉันการเรียนรู้ไวยากรณ์นี้เกิดจากความผิดพลาดแทนที่จะป้องกัน ฉันจะได้รับรหัสที่ถูกต้องเร็วขึ้นเพียงแค่ส่ง float *
Andrew Wagner

1
ใช่ @ มิกกี้สิ่งที่คุณแนะนำคือconstตัวชี้ไปยังอาร์เรย์ขององค์ประกอบที่เปลี่ยนแปลงได้ และใช่สิ่งนี้แตกต่างอย่างสิ้นเชิงจากตัวชี้ไปยังอาร์เรย์ขององค์ประกอบที่ไม่เปลี่ยนรูป
Cyan

11

ฉันต้องการเพิ่มคำตอบของ AndreyT (ในกรณีที่มีใครสะดุดหน้านี้กำลังมองหาข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้):

เมื่อฉันเริ่มเล่นกับคำประกาศเหล่านี้มากขึ้นฉันก็รู้ว่ามีแฮนดิแคปหลักที่เกี่ยวข้องกับพวกเขาใน C (ดูเหมือนจะไม่อยู่ใน C ++) เป็นเรื่องปกติที่จะมีสถานการณ์ที่คุณต้องการให้ผู้โทรกำหนดตัวชี้ const ไปยังบัฟเฟอร์ที่คุณเขียนไว้ น่าเสียดายที่ไม่สามารถทำได้เมื่อประกาศตัวชี้เช่นนี้ใน C กล่าวอีกนัยหนึ่งคือมาตรฐาน C (6.7.3 - ย่อหน้าที่ 8) ขัดแย้งกับสิ่งนี้:


   int array[9];

   const int (* p2)[9] = &array;  /* Not legal unless array is const as well */

ข้อ จำกัด นี้ดูเหมือนจะไม่มีอยู่ใน C ++ ทำให้การประกาศประเภทนี้มีประโยชน์มากขึ้น แต่ในกรณีของ C จำเป็นต้องถอยกลับไปใช้การประกาศตัวชี้ปกติเมื่อใดก็ตามที่คุณต้องการให้ตัวชี้ const ไปที่บัฟเฟอร์ขนาดคงที่ (เว้นแต่บัฟเฟอร์จะถูกประกาศให้เริ่มต้นด้วย) คุณสามารถค้นหาข้อมูลเพิ่มเติมได้ในเธรดอีเมลนี้: ข้อความลิงก์

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


2
ดูเหมือนว่าจะเป็นปัญหาเฉพาะของคอมไพเลอร์ ฉันสามารถทำซ้ำได้โดยใช้ gcc 4.9.1 แต่เสียงดังก้อง 3.4.2 สามารถเปลี่ยนจากเวอร์ชันที่ไม่ใช่ const เป็น const ได้อย่างไม่มีปัญหา ฉันได้อ่านข้อมูลจำเพาะของ C11 (p 9 ในเวอร์ชันของฉัน ... ส่วนที่พูดถึงสองประเภทที่เข้ากันได้) และยอมรับว่าดูเหมือนว่าการแปลงเหล่านี้ผิดกฎหมาย อย่างไรก็ตามในทางปฏิบัติเราทราบดีว่าคุณสามารถแปลงจาก char * เป็น char const * ได้โดยอัตโนมัติโดยไม่มีการเตือนล่วงหน้า IMO เสียงดังมีความสอดคล้องกันในการอนุญาตมากกว่า gcc แม้ว่าฉันเห็นด้วยกับคุณว่าข้อกำหนดดูเหมือนจะห้ามการแปลงอัตโนมัติใด ๆ เหล่านี้
Doug Richardson

4

เหตุผลที่ชัดเจนคือรหัสนี้ไม่ได้รวบรวม:

extern void foo(char (*p)[10]);
void bar() {
  char p[10];
  foo(p);
}

การส่งเสริมเริ่มต้นของอาร์เรย์คือตัวชี้ที่ไม่มีเงื่อนไข

นอกจากนี้โปรดดูคำถามนี้การใช้foo(&p)ควรใช้งานได้


3
แน่นอนว่า foo (p) จะไม่ทำงาน foo กำลังขอตัวชี้ไปยังอาร์เรย์ 10 องค์ประกอบดังนั้นคุณต้องส่งที่อยู่ของอาร์เรย์ของคุณ ...
Brian R.Bondy

9
"เหตุผลที่ชัดเจน" นั้นเป็นอย่างไร? foo(&p)มันเป็นอย่างเห็นได้ชัดเข้าใจว่าวิธีการที่เหมาะสมที่จะเรียกฟังก์ชั่น
AnT

3
ฉันเดาว่า "ชัดเจน" เป็นคำที่ไม่ถูกต้อง ฉันหมายถึง "ตรงไปตรงมาที่สุด" ความแตกต่างระหว่าง p และ & p ในกรณีนี้ค่อนข้างคลุมเครือสำหรับโปรแกรมเมอร์ C โดยเฉลี่ย มีคนพยายามทำตามที่ผู้โพสต์แนะนำจะเขียนสิ่งที่ฉันเขียนรับข้อผิดพลาดเวลาคอมไพล์และยอมแพ้
Keith Randall

2

ฉันต้องการใช้ไวยากรณ์นี้เพื่อเปิดใช้งานการตรวจสอบประเภทเพิ่มเติม

แต่ฉันก็เห็นด้วยว่ารูปแบบทางไวยากรณ์และจิตใจของการใช้พอยน์เตอร์นั้นง่ายกว่าและจำได้ง่ายกว่า

นี่คืออุปสรรคเพิ่มเติมที่ฉันเจอ

  • การเข้าถึงอาร์เรย์จำเป็นต้องใช้(*p)[]:

    void foo(char (*p)[10])
    {
        char c = (*p)[3];
        (*p)[0] = 1;
    }

    เป็นที่น่าสนใจที่จะใช้ตัวชี้เพื่อถ่านแทน:

    void foo(char (*p)[10])
    {
        char *cp = (char *)p;
        char c = cp[3];
        cp[0] = 1;
    }

    แต่สิ่งนี้จะเอาชนะวัตถุประสงค์ของการใช้ประเภทที่ถูกต้องได้บางส่วน

  • เราต้องจำไว้ว่าให้ใช้แอดเดรสของตัวดำเนินการเมื่อกำหนดแอดเดรสของอาร์เรย์ให้กับตัวชี้ไปยังอาร์เรย์:

    char a[10];
    char (*p)[10] = &a;

    ที่อยู่ของผู้ประกอบการได้รับที่อยู่ของอาร์เรย์ทั้งหมดในกับประเภทที่ถูกต้องที่จะกำหนดให้&a pหากไม่มีตัวดำเนินการaจะถูกแปลงเป็นที่อยู่ขององค์ประกอบแรกของอาร์เรย์โดยอัตโนมัติเช่นเดียวกับใน&a[0]ซึ่งมีประเภทอื่น

    เนื่องจากการแปลงอัตโนมัตินี้เกิดขึ้นแล้วฉันจึงงงงวยเสมอว่า&จำเป็นหรือไม่ มันสอดคล้องกับการใช้&กับตัวแปรประเภทอื่น ๆ แต่ฉันต้องจำไว้ว่าอาร์เรย์นั้นพิเศษและฉันต้องการ&เพื่อให้ได้ประเภทที่อยู่ที่ถูกต้องแม้ว่าค่าที่อยู่จะเหมือนกันก็ตาม

    สาเหตุหนึ่งสำหรับปัญหาของฉันอาจเป็นเพราะฉันเรียนรู้ K&R C ในช่วงทศวรรษที่ 80 ซึ่งยังไม่อนุญาตให้ใช้ตัว&ดำเนินการกับอาร์เรย์ทั้งหมด (แม้ว่าคอมไพเลอร์บางตัวจะไม่สนใจสิ่งนั้นหรือยอมรับไวยากรณ์) ซึ่งอาจเป็นอีกสาเหตุหนึ่งที่ทำให้ตัวชี้ไปยังอาร์เรย์มีปัญหาในการนำมาใช้: พวกเขาทำงานได้อย่างถูกต้องตั้งแต่ ANSI C เท่านั้นและ&ข้อ จำกัด ของตัวดำเนินการอาจเป็นอีกสาเหตุหนึ่งที่ทำให้พวกเขาอึดอัดเกินไป

  • เมื่อtypedefใดที่ไม่ได้ใช้ในการสร้างชนิดสำหรับตัวชี้ไปยังอาร์เรย์ (ในไฟล์ส่วนหัวทั่วไป) ดังนั้นตัวชี้ไปยังอาร์เรย์ส่วนกลางจึงจำเป็นต้องมีexternการประกาศที่ซับซ้อนมากขึ้นเพื่อแบ่งปันระหว่างไฟล์:

    fileA:
    char (*p)[10];
    
    fileB:
    extern char (*p)[10];

1

พูดง่ายๆก็คือ C ไม่ได้ทำอย่างนั้น อาร์เรย์ของประเภทTถูกส่งไปรอบ ๆ เป็นตัวชี้ไปยังตัวแรกTในอาร์เรย์และนั่นคือทั้งหมดที่คุณได้รับ

สิ่งนี้ช่วยให้มีอัลกอริทึมที่ยอดเยี่ยมและสวยงามเช่นการวนลูปผ่านอาร์เรย์ด้วยนิพจน์เช่น

*dst++ = *src++

ข้อเสียคือการจัดการขนาดขึ้นอยู่กับคุณ น่าเสียดายที่ความล้มเหลวในการทำเช่นนี้อย่างเป็นเรื่องเป็นราวยังนำไปสู่ข้อบกพร่องนับล้านในการเข้ารหัส C และ / หรือโอกาสในการแสวงหาประโยชน์ที่ไม่เหมาะสม

สิ่งที่ใกล้เคียงกับสิ่งที่คุณถามใน C คือการส่งผ่าน a struct (ตามค่า) หรือตัวชี้ไปที่หนึ่ง (โดยการอ้างอิง) ตราบเท่าที่มีการใช้ประเภทโครงสร้างเดียวกันกับทั้งสองด้านของการดำเนินการนี้ทั้งรหัสที่ส่งข้อมูลอ้างอิงและรหัสที่ใช้จะอยู่ในข้อตกลงเกี่ยวกับขนาดของข้อมูลที่กำลังจัดการ

โครงสร้างของคุณสามารถมีข้อมูลใดก็ได้ที่คุณต้องการ อาจมีอาร์เรย์ของขนาดที่กำหนดไว้อย่างดี

ถึงกระนั้นก็ไม่มีอะไรป้องกันคุณหรือผู้เข้ารหัสที่ไร้ความสามารถหรือผู้ไม่ประสงค์ดีจากการใช้ casts เพื่อหลอกคอมไพเลอร์ให้ถือว่าโครงสร้างของคุณมีขนาดแตกต่างกัน ความสามารถในการทำสิ่งนี้ที่แทบจะไม่สะดุดเป็นส่วนหนึ่งของการออกแบบของ C


1

คุณสามารถประกาศอาร์เรย์ของอักขระได้หลายวิธี:

char p[10];
char* p = (char*)malloc(10 * sizeof(char));

ต้นแบบของฟังก์ชันที่รับอาร์เรย์ตามค่าคือ:

void foo(char* p); //cannot modify p

หรืออ้างอิง:

void foo(char** p); //can modify p, derefernce by *p[0] = 'f';

หรือตามไวยากรณ์อาร์เรย์:

void foo(char p[]); //same as char*

2
อย่าลืมว่าอาร์เรย์ขนาดคงที่สามารถจัดสรรแบบไดนามิกได้เช่นchar (*p)[10] = malloc(sizeof *p)กัน
AnT

ดูรายละเอียดเพิ่มเติมเกี่ยวกับความแตกต่างของ char array [] และ char * ptr ได้ที่นี่ stackoverflow.com/questions/1807530/…
t0mm13b

1

ฉันจะไม่แนะนำวิธีแก้ปัญหานี้

typedef int Vector3d[3];

เนื่องจากมันปิดบังความจริงที่ว่า Vector3D มีประเภทที่คุณต้องรู้ โดยปกติโปรแกรมเมอร์จะไม่คาดหวังให้ตัวแปรประเภทเดียวกันมีขนาดต่างกัน พิจารณา :

void foo(Vector3d a) {
   Vector3D b;
}

โดยที่ sizeof a! = sizeof b


เขาไม่ได้แนะนำว่านี่เป็นวิธีแก้ปัญหา เขาใช้สิ่งนี้เป็นตัวอย่าง
figurassa

ฮึ่ม ทำไมsizeof(a)ไม่เหมือนกับsizeof(b)?
sherrellbc

0

บางทีฉันอาจจะขาดอะไรไป แต่ ... เนื่องจากอาร์เรย์เป็นตัวชี้คงที่โดยพื้นฐานแล้วนั่นหมายความว่าไม่มีจุดที่จะส่งผ่านตัวชี้ไปยังพวกเขา

คุณไม่สามารถใช้void foo(char p[10], int plen);?


4
อาร์เรย์ไม่ใช่ตัวชี้คงที่ โปรดอ่านคำถามที่พบบ่อยเกี่ยวกับอาร์เรย์
AnT

2
สำหรับสิ่งที่สำคัญที่นี่ (อาร์เรย์แบบมิติเดียวเป็นพารามิเตอร์) ความจริงก็คือพวกมันสลายตัวเป็นตัวชี้คงที่ โปรดอ่านคำถามที่พบบ่อยเกี่ยวกับการอวดดีน้อยลง
fortran

-2

บนคอมไพเลอร์ของฉัน (vs2008) จะถือว่าchar (*p)[10]เป็นอาร์เรย์ของตัวชี้อักขระราวกับว่าไม่มีวงเล็บแม้ว่าฉันจะรวบรวมเป็นไฟล์ C ก็ตาม คอมไพเลอร์รองรับ "ตัวแปร" นี้หรือไม่? ถ้าเป็นเช่นนั้นก็เป็นเหตุผลสำคัญที่จะไม่ใช้มัน


1
-1 ผิด ใช้งานได้ดีกับ vs2008, vs2010, gcc โดยเฉพาะตัวอย่างนี้ใช้งานได้ดี: stackoverflow.com/a/19208364/2333290
kotlomoy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.