C Programming : เขียนโปรแกรมภาษา C แบบพื้นฐาน ตอนที่ 4 – Pointer
สวัสดีครับ พบกับผมอีกแล้ว มาลุยกันต่อกับ C – Programming ฉบับย่อๆแบบเนื้อๆ บทความก่อนหน้านี้ พูดถึง array ไปแล้ว บทความตอนนี้จะยากขึ้นมาอีกนิดนึง คือเรื่องของ pointer (พ้อยเตอร์)
รู้จักกับ Pointer
pointer ผมไม่แน่ใจภาษาไทยเรียกอะไร ดัชนี หรือตัวชี้นี่แหละ ผมเรียกมันว่า พ้อยเตอร์ เหมือนเดิม
ก่อนจะรู้ว่ามันคืออะไร มาดูโค้ดนี้ก่อน
#include<stdio.h> main(){ int x = 10; printf("\n %d",&x); printf("\n %X",&x); }
ผมทำการประกาศตัวแปร x กำหนดค่าให้มันเป็น 10
แต่ตอนแสดง ผมแสดงค่า โดยใช้ &x
ค่าที่แสดง จะเป็นเลขอะไรก็ไม่รู้ อยู่ๆก็โผล่มา มันคือ ที่อยู่ของตัวแปรในหน่วยความจำนั่นเอง (Memory address)
หมายความว่า ตอนเราประกาศ int x ปุ๊บ โปรแกรมมันก็จะไปจองพื้นที่ใน memory มา ก็เพื่อให้โปรแกรมมันอ้างอิงถูก
ดังนั้น 6487628 หรือถ้าเป็นเลขฐาน 16 จะเป็น 62FE4C มันคือที่อยู่ของตัวแปร
ผมขอใช้เลขฐาน 16 ในการแสดงข้อมูล address นะ เพราะนิยมใช้เลขฐาน 16 ในการแสดงข้อมูลประเภทนี้
และนี่ก็คือ Pointer มันคือการเอา address ไปใช้มาประโยชน์
เอา Address ไปทำอะไร
มันมีประโยชน์มากๆเลยนะ เอาไปประยุกต์ได้ในหลายๆเรื่อง อย่างเช่น จะทำข้อมูลเป็นคิว ก็เอาตัว pointer นี้แหละไปชี้ได้ว่าอันไหนคือตัวต่อไป ก่อนอื่นเลย
มาดูพื้นฐานกันก่อน คือการสร้างร่างเงา หรือสร้างตัวแทนขึ้นมา
โดยประกาศตัวแปรแบบ Pointer
ก็แค่ เติม * ไว้หน้าชื่อตัวแปร
การกำหนดค่าให้ตัวแปร pointer ก็ต้องเอาค่าที่เป็น address ใส่เข้าไป
เช่น
#include<stdio.h> main(){ int x = 10; int *addressX = &x; printf("\n %X ",&x); printf("\n %X ",addressX); }
ในที่นี้คือ ให้ตัวแปร addressX เก็บที่อยู่ของ x ไว้
เท่านี้เราสามารถใช้ addressX มาทำอะไรแทน x ได้ เพราะมันคือ ร่างเงาของ x แล้ว
การอ้างอิงค่าของตัวแปรปลายทางที่ pointer เก็บจะใช้ * นำหน้าเหมือนกัน
#include<stdio.h> main(){ int x = 10; int *addressX = &x; printf("\nAddress of x = %X ",&x); printf("\nValue of addressX = %X ",addressX); *addressX = 99; printf("\nValue of x = %d ",x); }
จากโค้ด จะเห็นว่า ผมกำหนดค่า x = 10
แล้วประกาศ addressX ให้มันเป็นร่างเงาของ x
จากนั้นก็เอา addressX มากำหนดค่าให้กับร่างจริง (ตัวที่มันชี้อยู่) เป็น 99 ซึ่งในที่นี้คือ x
พอผมปริ้นค่า x ออกมา ก็คือ 99
นี่แหละคือการใช้ pointer แบบพื้นฐานนั่นเอง
ทีนี้ลองนำตัวแปร pointer มาคำนวณ
คือเอาร่างเงามาทำงานแทนร่างจริง แต่ร่างจริงก็เปลี่ยนค่าตามไปด้วย
เห็นมัยว่ามันมีประโยชน์นะ
Array of Pointer
คราวนี้จะเราเก็บ pointer เป็นตัวแปรชุด
ใน array จะประกอบไปด้วย pointer นั่นเอง
ถ้าเราเข้าใจ array กับ pointer แล้วมันก็ไม่ยาก เพราะมันก็คือหลักการเดิม
#include<stdio.h> main(){ int man = 30; int girl = 20; int boy = 10; int *shadow[3]; shadow[0] = &man; shadow[1] = &girl; shadow[2] = &boy; int i=0; for(i=0;i<3;i++){ printf("\nshadow[%d] = %d",i ,*(shadow[i])); } }
ประกาศตัวแปรแบบ array of pointer คือ มีทั้ง * และ []
จากนั้นก็กำหนดค่า ที่อยู่ให้แต่ละ pointer
แล้วก็วนลูปโดยให้แสดงค่าของ pointer ที่ชี้ ในแต่ index
Pointer กับ Array index
array กับ pointer มันทำงานร่วมกันได้นะ
array มันใช้ index ในการเข้าถึงข้อมูลอย่างที่เราเรียนกันไป ซึ่งเราก็นำ loop มาใช้ในการวน index อีกที
ทีนี้เราจะลองนำ pointer มาใช้กับ array
#include<stdio.h> main(){ int data[] = {10,20,30,40}; int *ptr = &data[0]; printf("\ndata[0] = %d",*(ptr)); printf("\ndata[1] = %d",*(ptr + 1)); printf("\ndata[2] = %d",*(ptr + 2)); printf("\ndata[3] = %d",*(ptr + 3)); }
จากโค้ดก็ประกาศตัวแปร array ข้อมูลกับตัวแปร pointer
แล้วเอา pointer มาเก็บที่อยู่ของ ข้อมูลตัวแรกของ array (จะเรียกว่า pointer ชี้มาที่ index ที่ 0 ก็ได้)
หากเราเอา pointer มา + 1 มันก็จะรู้ทันที ว่าข้อมูลตัวต่อไปคือ ข้อมูลใน array index ถัดไป 1 ตัวจากที่มันชี้อยู่ (ปัจจุบันชี้ที่ 0)
ทำให้มันได้ data[1] ออกมา
เห็นไหมว่ามันใช้งานร่วมกันได้
ทีนี้ก็เอา loop มาประยุกต์ใช้ได้ เพื่อไม่ต้องเขียนเยอะ
#include<stdio.h> main(){ int data[] = {10,20,30,40}; int *ptr = &data[0]; int i=0; for(i=0;i<4;i++){ printf("\ndata[%d] = %d",i ,*(ptr + i)); } }
ง่ายใช่ไหมละ หากเข้าใจเรื่อง loop แล้ว ก็ปรับเปลี่ยนโค้ดได้ง่ายๆเลย
Pointer to Pointer
ยังไม่พอ ลองเล่นใหญ่ขึ้นหน่อย คือ เอาร่างเงา B ควบคุมร่างเงา A แล้วร่างเงา A ควบคุมร่างจริง
ก็สามารถทำได้นะ เป็นการใช้ pointer แบบซ้อนกัน
ซึ่งก็หลักการเดิม คือ pointer มันเก็บ address
เราก็แค่ประกาศ pointer แล้วให้มันเก็บ adress ของตัวแปร pointer อีกทีนั่นเอง
#include<stdio.h> main(){ int man = 10; int *shadowA = &man; int **shadowB = &shadowA; *(*shadowB)= 8888; printf("\nValue of man = %d ",man); }
จากโค้ดคือ ผมประกาศ man = 10
ประกาศ shadowA ให้เก็บที่อยู่ของ man ได้ร่างเงามาตัวนึงแล้ว
ยังไม่พอ ผมประกาศ shadowB ให้เก็บที่อยู่ของ shadowA อีกทอด
สังเกตว่า shadowB มันเก็บที่อยู่ของ pointer อีกที ดังนั้นต้องประกาศตัวแปรแบบใส่ ** นะ
หากเราต้องการใช้ shadowB เปลี่ยนค่าของ man ก็ต้องใช้ ** สองกันแบบนี้
คือ *(*shadowB)
ความหมายคือ เอาค่าที่อยู่ปลายทางที่ shadowB เก็บออกมา ก็จะได้ shadowA แล้วก็เอา
ตัวแปรที่อยู่ที่ shadowA ออกมาก็จะได้ man จากนั้นก็กำหนดค่าใหม่ได้
Pointer to ( Pointer to Pointer )
มาลองเพิ่มร่างเงาอีกสัก 1 ชั้น เพื่อความเข้าใจ ทีนี้เป็น 3 ชั้น
#include<stdio.h> main(){ int man = 10; int *shadowA = &man; int **shadowB = &shadowA; int ***shadowC = &shadowB; *(*(*shadowC))= 8888; printf("\nValue of man = %d ",man); }
ก็หลักการเดิมเลย ใช่ไหมละ
ตัวแปร shadowC มันต้องเก็บค่า shadowB ซึ่งมันเป็นตัวแปร pointer to pointer
ก็ต้องใช้ ***
ดังนั้นต่อให้ซ้อนกัน 10 pointer ก็ใช้หลักการเดียวกัน
ระวังการใช้ ++ — กับ pointer นะ
เพราะว่า ++ , — มันมีจะถูกทำงานก่อน pointer ดังนั้นถ้าจะ ++ , — หมายถึง เพิ่มลดค่าตัวแปรที่ชี้จริงๆ
ต้องใส่ วงเล็บให้ pointer ก่อนนะ
สังเกตบรรทัดที่ 6
การบ้าน
เพื่อความเข้าใจเรื่อง pointer ให้ลองทำกันครับ
ผมมีโค้ดมาให้ มี Pointer ระดับร่างเงาซ้อน ตั้งแต่ 1 – 5 ชั้น
ให้หาผลรวมของ data โดยใช้ตัวแปรร่างเงา shadowV และใช้ loop for อันเดียวที่มีให้
#include<stdio.h> main(){ int data[] = {1000, 2000 ,3000, 4000}; int *shadowDataI[4]; int **shadowDataII[4]; int ***shadowDataIII[4]; int ****shadowDataIV[4]; int *****shadowDataV[4]; int sum = 0; int i=0; for(i=0;i<4;i++){ // do somthing เติมโค้ดลงในลูป for นี้ใน } printf("sum = %d",sum); }
ใครทำได้แล้ว คอมเม้นไว้ด้วยนะครับ
ขอขอบคุณที่อ่านจนถึงตรงนี้