Tuesday, November 24, 2009

มาทบทวน Pointer ในภาษา C กันเถอะ




วันนี้ผมเรียนวิชา Advance Data Structures and Algorithms มาครับ เรียนเรื่องโครงสร้างข้อมูลใน Java มีอีกหลายอย่างที่ยังไม่รู้ จริงๆก่อนหน้านี้เขียน Java บ่อยๆใช้ก็แต่ ArrayList รู้แค่ว่าใน Java มี Linked List, Graph, Tree ฯลฯ เตรียมไว้ให้ แต่พอได้เรียนจริงๆ ปรากฎว่ามีโครงสร้างข้อมูลอีกหลายชนิดเลยครับที่ Java มีให้ และผมเองก็ไม่เคยได้ยินชื่อมันมาก่อน เดี๋ยวไว้ว่างๆ จะเขียนบทความเกี่ยวกับโครงสร้างข้อมูลแปลกๆ ที่เรียนมานะครับ

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

พล่ามกันมาเยอะแล้ว เข้าเรื่องกันดีกว่า สำหรับ Pointer ในภาษาซีนั้นเชื่อว่าหลายๆ คนคงเคยใช้หรือเคยเรียนกันมาบ้าง เท่าที่ผมเคยเห็นมา พบว่าเรื่อง Pointer ถือเป็นเรื่องยากเรื่องหนึ่งในการทำความเข้าใจของหลายๆ คน ก่อนอื่นก็ต้องขอบอกก่อนว่า Pointer ก็คือตัวแปรชนิดหนึ่ง แต่แตกต่างจากตัวแปรทั่วๆไปตรงที่ Pointer ใช้ในการทำหน้าที่ชี้ (Reference) ไปยังตัวแปรอื่นๆ ซึ่ง Pointer นั้นสามารถนำไปประยุกต์ใช้งานได้หลายอย่าง แต่ที่เห็นชัดเจนและใช้กันบ่อยๆ ก็คงจะเป็นการนำ Pointer ไปสร้างเป็นโครงสร้างข้อมูลยอดนิยมอย่าง Linked List, Tree และ Graphชนิดต่างๆ แต่ผมไม่ขอพูดถึงวิธีการนำ Pointer ไปใช้ในโครงสร้างข้อมูลเหล่านั้นนะครับ ขอพูดแค่พื้นฐาน

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

สมมติผมประกาศตัวแปรว่า

int foo = 21;
int *bar;




จากคำสั่งประกาศตัวแปร foo เป็นชนิด int พร้อมกับใส่ค่าเป็น 21 แล้วประกาศตัวแปร bar เป็นแบบ Pointer ของ int ก็จะได้ตามรูปข้างบน ซึ่งตัวแปร foo จะถูกจองอยู่ในหน่วยความจำของคอมพิวเตอร์ ซึ่งจากรูปนี้ foo จะอยู่ที่ตำแหน่ง 240ff58 ของหน่วยความจำ แล้ว foo ก็เก็บค่า 21 ไว้ (ในหน่วยความจำจริงๆ จะเก็บเป็นเลขฐานสอง ไม่ได้เก็บเลข 21 ไว้นะครับ) และในทำนองเดียวกันตัวแปร bar ก็ถูกเก็บอยู่ในหน่วยความจำ ซึ่งตามรูปคือที่ตำแหน่ง 240ff5c และเรายังไม่ได้กำหนดค่าให้ bar นอกจากนั้นจะเห็นว่าตัวแปรแบบ bar นั้นจะมีfieldข้อมูลมากกว่าตัวแปรแบบธรรมดาอยู่ 1 field เรามาดูคำสั่งต่อไปกันต่อนะครับ
ผมพิมพ์โค้ดว่า

bar = &foo;



จากรูป ผลลัพธ์ที่ได้เมื่อเราสั่งให้ bar ชี้ (Reference) ไปยัง foo จะทำให้ส่วนของ value ของ bar เก็บ address ของ foo ไว้ ถ้าเราลองพิมพ์ค่าของตัวแปรทั้งสองตัวออกมาด้วยคำสั่ง printf

printf("Address of foo is %x , Values Store in foo is %d\n",&foo, foo);
printf("Address of *bar is %x, Values Store in *bar is %x, Values Point by *bar is %d", &bar, bar, *bar);


ผลลัพธ์ที่ได้ก็คือ

Address of foo is 240ff58 , Values Store in foo is 21
Address of *bar is 240ff5c , Values Store in *bar is 240ff58 , Values Point by *bar is 21



จะเห็นว่าเมื่อเราสั่งให้ Pointer ชี้ไปยังตัวแปรที่ต้องการ ค่าที่เก็บอยู่ในตัวแปร Pointer ก็คือ Address ของตัวแปรที่มันชี้อยู่ันั่นเอง ส่วนใน field * ของ Pointer นั้น เมื่อเราอ้างถึง fieldนี้ ก็จะหมายถึงการอ้างถึงค่าซื่งเก็บอยู่ในตัวแปรที่ Pointer ชี้อยู่ (ในที่นี้คือค่า 21 ที่เก็บอยู่ในตัวแปร foo) ดังนั้นถ้าเราพิมพ์ค่า bar ออกมา ก็จะได้ผลลัพธ์เป็นค่าในตัวแปร foo

และถ้าหากเราแก้ไขค่าโดยการอ้าง fild * ของ Pointer จะส่งผลให้ค่าในตัวแปรที่ Pointer ชี้อยู่ เปลี่ยนแปลงไปด้วย เช่น

*bar = 3;
printf("*bar = %d foo = %d", *bar, foo);


ผลลัพธ์ที่ได้ก็คือ

*bar = 3
foo = 3


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

ไปก่อนนะครับ ^ ^



No comments:

Post a Comment