ตัวชี้ไปยังพอยน์เตอร์ทำงานอย่างไรใน C


171

พอยน์เตอร์ไปยังพอยน์เตอร์ทำงานอย่างไรใน C คุณจะใช้มันเมื่อไหร่?


43
ไม่ไม่ทำการบ้าน .... แค่อยากรู้อยากเห็นฉันเห็นมันเยอะมากเมื่อฉันอ่านรหัส C

1
ตัวชี้ไปยังตัวชี้ไม่ใช่กรณีพิเศษของบางสิ่งดังนั้นฉันไม่เข้าใจสิ่งที่คุณไม่เข้าใจเกี่ยวกับโมฆะ **
akappa

สำหรับอาร์เรย์ 2D ตัวอย่างที่ดีที่สุดคือบรรทัดคำสั่ง args "prog arg1 arg2" ถูกเก็บไว้ถ่าน ** argv และถ้าผู้เรียกไม่ต้องการจัดสรรหน่วยความจำ (ฟังก์ชั่นที่เรียกว่าจะจัดสรรหน่วยความจำ)
resultsway

1
คุณมีตัวอย่างที่ดีของการใช้งาน "ตัวชี้ไปยังตัวชี้" ใน Git 2.0: ดูคำตอบของฉันด้านล่าง
VonC

คำตอบ:


359

สมมติว่าคอมพิวเตอร์ 8 บิตพร้อมที่อยู่ 8 บิต (และมีหน่วยความจำเพียง 256 ไบต์) นี่เป็นส่วนหนึ่งของหน่วยความจำ (ตัวเลขที่อยู่ด้านบนคือที่อยู่):

  54   55   56   57   58   59   60   61   62   63   64   65   66   67   68   69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|    | 58 |    |    | 63 |    | 55 |    |    | h  | e  | l  | l  | o  | \0 |    |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

สิ่งที่คุณสามารถดูได้ที่นี่คือที่อยู่ 63 สตริง "สวัสดี" เริ่มต้น ดังนั้นในกรณีนี้หากนี่เป็นเพียง "hello" ในหน่วยความจำเท่านั้น

const char *c = "hello";

... กำหนดcให้เป็นตัวชี้ไปยังสตริง (อ่านอย่างเดียว) "hello" และประกอบด้วย 63 ค่าcตัวเองจะต้องถูกเก็บไว้ที่ไหนสักแห่ง: ในตัวอย่างข้างต้นที่ตำแหน่ง 58 แน่นอนว่าเราไม่สามารถเพียงชี้ไปที่ตัวอักษร แต่ยังรวมถึงตัวชี้อื่น ๆ เช่น:

const char **cp = &c;

ตอนนี้cpชี้ไปcที่นั่นคือมันมีที่อยู่ของc(ซึ่งก็คือ 58) เราสามารถไปได้ไกลกว่านี้ พิจารณา:

const char ***cpp = &cp;

ตอนนี้เก็บที่อยู่ของcpp cpดังนั้นมันจึงมีค่า 55 (ตามตัวอย่างด้านบน) และคุณเดาได้: มันถูกเก็บไว้ที่ที่อยู่ 60


เป็นสาเหตุว่าทำไมจึงใช้พอยน์เตอร์กับพอยน์เตอร์:

  • ชื่อของอาร์เรย์มักจะให้ที่อยู่ขององค์ประกอบแรกของมัน ดังนั้นถ้าอาร์เรย์มีองค์ประกอบของประเภทอ้างอิงถึงอาร์เรย์มีประเภทt t *ตอนนี้ให้พิจารณาอาร์เรย์ประเภทอาร์เรย์t: โดยปกติการอ้างอิงไปยังอาร์เรย์ 2D นี้จะมีประเภท(t *)*= t **และดังนั้นจึงเป็นตัวชี้ไปยังตัวชี้
  • แม้ว่าอาเรย์ของสตริงจะฟังหนึ่งมิติ แต่ในความเป็นจริงนั้นเป็นสองมิติเนื่องจากสตริงนั้นเป็นอาเรย์ของอักขระ ดังนั้น: char **.
  • ฟังก์ชั่นfจะต้องยอมรับข้อโต้แย้งของพิมพ์ถ้ามันคือการเปลี่ยนแปลงของตัวแปรประเภทt **t *
  • สาเหตุอื่น ๆ อีกมากมายที่เกินกว่าจะแสดงที่นี่

7
ใช่เป็นตัวอย่างที่ดี .. ฉันเข้าใจว่าพวกเขาเป็นอย่างไร แต่วิธีการและเวลาที่จะใช้พวกเขามีความสำคัญมากขึ้น .. ตอนนี้ ..

2
สเตฟานทำผลงานได้ดีโดยทั่วไปแผนภาพในภาษา C ของ Kernighan และ Richie หากคุณกำลังเขียนโปรแกรม C และไม่มีหนังสือเล่มนี้และเจ๋งมากกับเอกสารที่เป็นกระดาษฉันขอแนะนำให้คุณใช้มันค่าใช้จ่ายพอสมควร (พอใช้) จะจ่ายให้ตัวเองอย่างรวดเร็วในการผลิต มันมีแนวโน้มที่จะชัดเจนมากในตัวอย่าง
J. Polfer

4
ถ่าน * c = "hello" ควรเป็น const char * c = "hello" นอกจากนี้ยังเป็นการเข้าใจผิดที่จะกล่าวว่า "อาร์เรย์ถูกเก็บไว้เป็นที่อยู่ขององค์ประกอบแรก" อาร์เรย์ถูกเก็บไว้เป็น ... อาร์เรย์ บ่อยครั้งที่ชื่อของมันทำให้ตัวชี้ไปยังองค์ประกอบแรก แต่ไม่เสมอไป เกี่ยวกับพอยน์เตอร์ถึงพอยน์เตอร์ฉันจะบอกว่ามันมีประโยชน์เมื่อฟังก์ชั่นต้องแก้ไขพอยน์เตอร์ที่ส่งผ่านเป็นพารามิเตอร์ (จากนั้นคุณส่งพอยน์เตอร์ไปที่พอยน์เตอร์แทน)
Bastien Léonard

4
ถ้าฉันไม่ตีความคำตอบนี้ผิดดูเหมือนว่าผิด c ถูกเก็บไว้ที่ 58 และชี้ไปที่ 63, cp ถูกเก็บไว้ที่ 55 และชี้ไปที่ 58, และ cpp ไม่แสดงในไดอะแกรม
Thanatos

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

46

พอยน์เตอร์ไปยังพอยน์เตอร์ทำงานอย่างไรใน C

ตัวชี้แรกคือตัวแปรเช่นเดียวกับตัวแปรอื่น ๆ แต่ที่เก็บที่อยู่ของตัวแปร

ตัวชี้ไปยังตัวชี้เป็นตัวแปรเช่นเดียวกับตัวแปรอื่น ๆ แต่ที่เก็บที่อยู่ของตัวแปร ตัวแปรนั้นเพิ่งเกิดขึ้นเพื่อเป็นตัวชี้

คุณจะใช้มันเมื่อไหร่?

คุณสามารถใช้พวกเขาเมื่อคุณต้องการส่งกลับตัวชี้ไปยังหน่วยความจำบางอย่างบนฮีป แต่ไม่ได้ใช้ค่าส่งคืน

ตัวอย่าง:

int getValueOf5(int *p)
{
  *p = 5;
  return 1;//success
}

int get1024HeapMemory(int **p)
{
  *p = malloc(1024);
  if(*p == 0)
    return -1;//error
  else 
    return 0;//success
}

และคุณเรียกว่าแบบนี้:

int x;
getValueOf5(&x);//I want to fill the int varaible, so I pass it's address in
//At this point x holds 5

int *p;    
get1024HeapMemory(&p);//I want to fill the int* variable, so I pass it's address in
//At this point p holds a memory address where 1024 bytes of memory is allocated on the heap

มีการใช้งานอื่นด้วยเช่นอาร์กิวเมนต์ main () ของทุกโปรแกรม C มีตัวชี้ไปยังตัวชี้สำหรับ argv โดยที่แต่ละองค์ประกอบเก็บอาร์เรย์ของตัวอักษรที่เป็นตัวเลือกบรรทัดคำสั่ง คุณต้องระวังแม้ว่าเมื่อคุณใช้พอยน์เตอร์พอยน์เตอร์เพื่อชี้ไปที่อาร์เรย์ 2 มิติการใช้ตัวชี้ไปยังอาร์เรย์ 2 มิตินั้นดีกว่า

ทำไมมันอันตราย

void test()
{
  double **a;
  int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*)

  double matrix[ROWS][COLUMNS];
  int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double)
}

นี่คือตัวอย่างของตัวชี้ไปยังอาร์เรย์ 2 มิติที่ทำอย่างถูกต้อง:

int (*myPointerTo2DimArray)[ROWS][COLUMNS]

คุณไม่สามารถใช้ตัวชี้ไปยังอาร์เรย์ 2 มิติได้หากคุณต้องการสนับสนุนจำนวนองค์ประกอบของตัวแปรสำหรับ ROWS และ COLUMNS แต่เมื่อคุณรู้ก่อนมือคุณจะต้องใช้อาร์เรย์ 2 มิติ


32

ฉันชอบตัวอย่างโค้ด "โลกแห่งความจริง" ของตัวชี้การใช้พอยน์เตอร์ใน Git 2.0 กระทำ 7b1004b :

Linus เคยกล่าวไว้ว่า:

ฉันอยากให้ผู้คนจำนวนมากเข้าใจการเข้ารหัสในระดับต่ำมาก ๆ ไม่ใช่เรื่องใหญ่ซับซ้อนเช่นการค้นหาชื่อ lockless แต่ใช้ประโยชน์จาก pointers-to-pointers และอื่น ๆ
ตัวอย่างเช่นฉันเห็นคนจำนวนมากเกินไปที่ลบรายการที่เชื่อมโยงโดยการติดตามรายการ "prev" แล้วจึงลบรายการทำสิ่งที่ชอบ

if (prev)
  prev->next = entry->next;
else
  list_head = entry->next;

และเมื่อใดก็ตามที่ฉันเห็นรหัสเช่นนั้นฉันเพิ่งไป "คนนี้ไม่เข้าใจตัวชี้" และเป็นเรื่องธรรมดาที่ค่อนข้างเศร้า

ผู้ที่เข้าใจพอยน์เตอร์เพียงใช้ " ตัวชี้ไปยังตัวชี้รายการ " และเริ่มต้นด้วยที่อยู่ของ list_head และเมื่อพวกเขาเข้าไปในรายการพวกเขาสามารถลบรายการโดยไม่ต้องใช้เงื่อนไขใด ๆ เพียงแค่ทำ

*pp =  entry->next

http://i.stack.imgur.com/bpfxT.gif

การใช้การทำให้เข้าใจง่ายทำให้เราสูญเสีย 7 บรรทัดจากฟังก์ชันนี้แม้ในขณะที่เพิ่มความคิดเห็น 2 บรรทัด

-   struct combine_diff_path *p, *pprev, *ptmp;
+   struct combine_diff_path *p, **tail = &curr;

คริสชี้ให้เห็นในความคิดเห็นเพื่อ 2016 วิดีโอ " Linus Torvalds ปัญหาของตัวชี้คู่ " โดยฟิลิป Buuck


kumarชี้ให้เห็นในความคิดเห็นโพสต์บล็อก " Linus ในการทำความเข้าใจตัวชี้ " ซึ่งGrisha Trubetskoyอธิบาย:

ลองนึกภาพคุณมีรายการเชื่อมโยงที่กำหนดเป็น:

typedef struct list_entry {
    int val;
    struct list_entry *next;
} list_entry;

คุณต้องวนซ้ำตั้งแต่ต้นจนจบและลบองค์ประกอบเฉพาะที่มีค่าเท่ากับค่าของ to_remove
วิธีที่ชัดเจนกว่านี้คือ:

list_entry *entry = head; /* assuming head exists and is the first entry of the list */
list_entry *prev = NULL;

while (entry) { /* line 4 */
    if (entry->val == to_remove)     /* this is the one to remove ; line 5 */
        if (prev)
           prev->next = entry->next; /* remove the entry ; line 7 */
        else
            head = entry->next;      /* special case - first entry ; line 9 */

    /* move on to the next entry */
    prev = entry;
    entry = entry->next;
}

สิ่งที่เราทำข้างต้นคือ:

  • วนซ้ำในรายการจนกว่าจะถึงรายการNULLซึ่งหมายความว่าเราได้มาถึงจุดสิ้นสุดของรายการ (บรรทัดที่ 4)
  • เมื่อเราเจอข้อความที่เราต้องการลบ (บรรทัดที่ 5)
    • เรากำหนดค่าของตัวชี้ถัดไปปัจจุบันให้กับตัวก่อนหน้า
    • จึงกำจัดองค์ประกอบปัจจุบัน (บรรทัดที่ 7)

มีกรณีพิเศษด้านบน - ที่จุดเริ่มต้นของการทำซ้ำไม่มีรายการก่อนหน้า ( prevคือNULL) และเพื่อลบรายการแรกในรายการที่คุณต้องแก้ไขหัวตัวเอง (สาย 9)

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

list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;

while (entry) {
    if (entry->val == to_remove)
        *pp = entry->next;

    pp = &entry->next;
    entry = entry->next;
}

โค้ดด้านบนคล้ายกับตัวแปรก่อนหน้า แต่สังเกตว่าเราไม่จำเป็นต้องดูกรณีพิเศษขององค์ประกอบแรกของรายการอีกต่อไปเนื่องจากppไม่ได้NULLอยู่ที่จุดเริ่มต้น เรียบง่ายและฉลาด

นอกจากนี้บางคนในเธรดนั้นแสดงความคิดเห็นว่าเหตุผลที่ดีกว่านั้นก็เพราะ*pp = entry->nextอะตอม มันเป็นที่สุดอย่างแน่นอนไม่อะตอม
นิพจน์ด้านบนมีตัวดำเนินการ dereference สองตัว ( *และ->) และหนึ่งการมอบหมายและไม่มีสามสิ่งใดในอะตอมนี้
นี่เป็นความเข้าใจผิดที่พบบ่อย แต่ก็ไม่น่าจะมีสิ่งใดใน C ที่น่าจะถือว่าเป็นอะตอม (รวมถึง++และ--โอเปอเรเตอร์)!


4
สิ่งนี้จะช่วยให้เข้าใจได้ดีขึ้น - grisha.org/blog/2013/04/02/linus-on-understanding-pointers
kumar

@ Kumar การอ้างอิงที่ดี ฉันได้รวมไว้ในคำตอบสำหรับการมองเห็นเพิ่มเติม
VonC

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

@Chris วิดีโอที่ยอดเยี่ยมขอบคุณที่พูดถึงมัน! ฉันได้รวมความคิดเห็นของคุณไว้ในคำตอบเพื่อให้มองเห็นได้ชัดเจนขึ้น
VonC

14

เมื่อครอบคลุมพอยน์เตอร์ในหลักสูตรการเขียนโปรแกรมที่มหาวิทยาลัยเราได้รับคำแนะนำสองประการเกี่ยวกับวิธีเริ่มเรียนรู้เกี่ยวกับพวกเขา ประการแรกคือการดูตัวชี้สนุกกับบิงกี้ อย่างที่สองก็คือคิดถึงเส้นทางดวงตาของ Haddocks 'จาก Lewis Carroll's Through the Look -Glass

“ คุณเศร้า” อัศวินพูดด้วยน้ำเสียงวิตก:“ ให้ฉันร้องเพลงคุณเพื่อปลอบโยนคุณ”

“ มันนานหรอ?” อลิซถามเพราะเธอเคยได้ยินบทกวีมากมายในวันนั้น

“ มันยาว” อัศวินพูด“ แต่มันสวยมาก ๆ ทุกคนที่ได้ยินฉันร้องเพลงมันไม่ว่าจะนำน้ำตามาสู่ตาของพวกเขาหรืออย่างอื่น -”

“ หรืออย่างอื่นอะไร” อลิซกล่าวว่าสำหรับอัศวินได้หยุดชั่วคราวในทันที

“ มิฉะนั้นแล้วคุณก็รู้ ชื่อของเพลงนี้มีชื่อว่า 'Haddocks' Eyes '”

“ โอ้นั่นคือชื่อเพลงใช่มั้ย” อลิซพูดพยายามที่จะรู้สึกสนใจ

“ ไม่คุณไม่เข้าใจ” อัศวินกล่าวมองดูเดือดร้อนเล็กน้อย “ นั่นคือชื่อที่เรียกว่า ชื่อนี้จริงๆคือ 'The Aged Aged Man'”

“ ถ้าอย่างนั้นฉันควรจะพูดว่า 'นั่นคือเพลงที่เรียกว่า'?” อลิซแก้ไขตัวเอง

“ ไม่คุณไม่ควร: นั่นเป็นอีกสิ่งหนึ่ง! เพลงนี้มีชื่อว่า 'Ways And Means' แต่นั่นเป็นเพียงสิ่งที่เรียกว่าคุณรู้!”

“ งั้นเพลงอะไรล่ะ?” อลิซกล่าวซึ่งตอนนี้สับสนอย่างสมบูรณ์แล้ว

“ ฉันกำลังจะมาถึง” อัศวินกล่าว “ เพลงจริงๆคือ 'A-sitting On A Gate': และเพลงนั้นเป็นสิ่งประดิษฐ์ของฉันเอง”


1
ฉันต้องอ่านข้อความนั้นสองสามครั้ง ... +1 ที่ทำให้ฉันคิด!
Ruben Steins

นี่คือสาเหตุที่ Lewis Carroll ไม่ใช่นักเขียนธรรมดา
metarose

1
ดังนั้น ... มันจะเป็นเช่นนี้? ชื่อ -> 'ผู้ชายที่มีอายุสูงวัย' -> เรียกว่า -> 'Haddock's Eyes' -> เพลง -> 'A-A On On A Gate'
tisaconundrum


7

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

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


อธิบายได้ดีสำหรับส่วน 'ทำไม'
Rana Deep

7

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

มักใช้ในสภาพแวดล้อมที่ จำกัด หน่วยความจำเช่น Palm OS

computer.howstuffworks.com ลิงก์ >>

www.flippinbits.com ลิงก์ >>


7

พิจารณาด้านล่างรูปและโปรแกรมที่จะเข้าใจแนวคิดที่ดีกว่านี้

ไดอะแกรมตัวชี้ดับเบิล

เป็นต่อรูปptr1เป็นตัวชี้เดียวซึ่งจะมีที่อยู่ของตัวแปรNUM

ptr1 = #

ในทำนองเดียวกันptr2เป็นตัวชี้ไปยังตัวชี้ (ตัวชี้คู่)ซึ่งจะมีอยู่ของตัวชี้ptr1

ptr2 = &ptr1;

ตัวชี้ที่ชี้ไปยังตัวชี้อื่นเรียกว่าตัวชี้คู่ ในตัวอย่างนี้ptr2เป็นตัวชี้ดับเบิล

ค่าจากแผนภาพด้านบน:

Address of variable num has : 1000
Address of Pointer ptr1 is: 2000
Address of Pointer ptr2 is: 3000

ตัวอย่าง:

#include <stdio.h>

int main ()
{
   int  num = 10;
   int  *ptr1;
   int  **ptr2;

   // Take the address of var 
   ptr1 = &num;

   // Take the address of ptr1 using address of operator &
   ptr2 = &ptr1;

   // Print the value
   printf("Value of num = %d\n", num );
   printf("Value available at *ptr1 = %d\n", *ptr1 );
   printf("Value available at **ptr2 = %d\n", **ptr2);
}

เอาท์พุท:

Value of num = 10
Value available at *ptr1 = 10
Value available at **ptr2 = 10

5

มันเป็นตัวชี้ไปยังค่าที่อยู่ของตัวชี้ (ฉันรู้ว่าแย่มาก)

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

void changeptr(int** pp)
{
  *pp=&someval;
}

ขอโทษฉันรู้ว่ามันค่อนข้างแย่ ลองอ่าน, ERM นี้: codeproject.com/KB/cpp/PtrToPtr.aspx
ลุค Schafer

5

คุณมีตัวแปรที่มีที่อยู่ของบางอย่าง นั่นคือตัวชี้

จากนั้นคุณมีตัวแปรอื่นที่มีที่อยู่ของตัวแปรแรก นั่นคือตัวชี้ไปยังตัวชี้


3

ตัวชี้ไปยังตัวชี้คือดีตัวชี้ไปยังตัวชี้

ตัวอย่างความหมายที่สมบูรณ์ของ someType ** เป็นอาร์เรย์สองมิติ: คุณมีหนึ่งอาร์เรย์ที่เต็มไปด้วยพอยน์เตอร์ไปยังอาร์เรย์อื่นดังนั้นเมื่อคุณเขียน

dpointer [5] [6]

คุณเข้าถึงอาเรย์ที่มีพอยน์เตอร์ไปยังอาร์เรย์อื่นในตำแหน่งที่ 5 รับพอยน์เตอร์ (ให้ fpointer ชื่อของเขา) จากนั้นเข้าถึงอิลิเมนต์ที่ 6 ของอาเรย์ที่อ้างอิงกับอาเรย์นั้น (เช่น fpointer [6])


2
พอยน์เตอร์ไปยังพอยน์เตอร์ไม่ควรสับสนกับอาร์เรย์ของอันดับ 2 เช่น int x [10] [10] โดยที่คุณเขียน x [5] [6] คุณเข้าถึงค่าในอาร์เรย์
Pete Kirkham

นี่เป็นเพียงตัวอย่างที่เป็นโมฆะ ** มีความเหมาะสม ตัวชี้ไปยังตัวชี้เป็นเพียงตัวชี้ที่ชี้ไปยังตัวชี้
akappa

1

วิธีการทำงาน: มันเป็นตัวแปรที่สามารถเก็บตัวชี้อื่น

เมื่อใดที่คุณจะใช้: หลาย ๆ คนใช้หนึ่งในนั้นคือถ้าฟังก์ชันของคุณต้องการสร้างอาร์เรย์และส่งกลับไปยังผู้เรียก

//returns the array of roll nos {11, 12} through paramater
// return value is total number of  students
int fun( int **i )
{
    int *j;
    *i = (int*)malloc ( 2*sizeof(int) );
    **i = 11;  // e.g., newly allocated memory 0x2000 store 11
    j = *i;
    j++;
    *j = 12; ;  // e.g., newly allocated memory 0x2004 store 12

    return 2;
}

int main()
{
    int *i;
    int n = fun( &i ); // hey I don't know how many students are in your class please send all of their roll numbers.
    for ( int j=0; j<n; j++ )
        printf( "roll no = %d \n", i[j] );

    return 0;
}


0

มีคำอธิบายที่เป็นประโยชน์มากมาย แต่ฉันไม่พบเพียงคำอธิบายสั้น ๆ ดังนั้น ..

ตัวชี้โดยทั่วไปคือที่อยู่ของตัวแปร รหัสสรุปสั้น ๆ :

     int a, *p_a;//declaration of normal variable and int pointer variable
     a = 56;     //simply assign value
     p_a = &a;   //save address of "a" to pointer variable
     *p_a = 15;  //override the value of the variable

//print 0xfoo and 15 
//- first is address, 2nd is value stored at this address (that is called dereference)
     printf("pointer p_a is having value %d and targeting at variable value %d", p_a, *p_a); 

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

และฉันก็ไม่แน่ใจเหมือนกันว่าเมื่อไรที่จะเป็นประโยชน์กับพอยน์เตอร์ แต่โดยทั่วไปคุณจำเป็นต้องใช้มันเมื่อคุณทำการจัดสรรหน่วยความจำด้วยตนเอง / แบบไดนามิก - malloc, calloc ฯลฯ

ดังนั้นฉันหวังว่ามันจะช่วยในการชี้แจงปัญหา :)

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