ความรู้เกี่ยวกับการเขียนโปรแกรมภาษา C ที่นักอิเล็กทรอนิกส์ไม่ค่อยรู้ ตอนที่ 4 ตัวเเปร Pointer (ภาคต่อ)

ความรู้เกี่ยวกับการเขียนโปรแกรมภาษา C ที่นักอิเล็กทรอนิกส์ไม่ค่อยรู้

ตอนที่ 4 ตัวเเปร Pointer (ภาคต่อ)

The C Programming Language logo

การอ่านเขียนค่าในตำแหน่งที่ pointer ชี้
          ในการอ่านหรือเขียนค่าในตำแหน่งที่ตัวแปร pointer ชี้อยู่ จะใช้ ‘*’ วางไว้ข้างหน้าตัวแปร pointer เพื่อเป็นการบอกว่าเราจะใช้ค่า ณ ตำแหน่งที่ pointer ชี้ จะตรงข้ามกับตอนที่แล้ว ที่เราใช้ ‘&’ เพื่ออ่านค่าตำแหน่ง สมมติว่าเราประกาศตัวแปร 
char c = ‘1’; 
และ c นี้อยู่ที่ตำแหน่ง 0x20000000 จะได้ว่า 
&c จะมีค่าเป็น 0x20000000 
ถ้าเราประกาศตัวแปร pointer p ดังนี้
char *p = &c; 
จะเป็นการประกาศตัวแปร pointer p พร้อมกับกำหนดให้ชี้ไปที่ c จะได้ว่า 
*p จะมีค่าเป็น ‘1’ 
ขณะที่ p เฉยๆจะมีค่าเป็น 0x20000000 ทีนี้เราจะสามารถอ่านหรือเขียนค่าที่ตำแหน่ง 0x20000000 ได้โดยใช้ *p เช่น

          สมมติว่าเรามี function ที่มีการส่งค่ากลับ 1 ค่า ปกติเราก็จะประกาศให้ function นั้น return ค่ากลับออกมาด้วยชนิดของตัวแปรตามที่เราต้องการ เช่น 
int add(int a, int b) {
          return (a + b);
}
แต่ในบางครั้ง function ที่เราสร้างขึ้นมา จำเป็นจะต้องมีการส่งค่ากลับมากกว่า 1 ค่า เช่น เราต้องการอ่านค่าตำแหน่งที่ถูกกดจากหน้าจอ touch screen ก็จะต้องส่งค่ากลับออกมา 2 ค่า คือพิกัดในแกน x กับแกน y เราก็อาจจะสร้างตัวแปร global ขึ้นมา 2 ตัวเพื่อเก็บค่านี้ หลังจากคำนวณเสร็จเราก็เอาค่าที่ได้เก็บในตัวแปรทั้งสอง แล้วจึงทำการอ่านออกไป ซึ่งต้องใช้หลายขั้นตอน และโดยทั่วไปถ้าเป็นการเขียนโปรแกรมที่มีหลายๆไฟล์ ก็จะพยายามสร้างตัวแปร global ขึ้นมาใช้ร่วมกันระหว่างไฟล์เท่าที่จำเป็น ในสถานการณ์แบบนี้ เราสามารถนำตัวแปร pointer มาใช้ทำให้เขียนโปรแกรมง่ายขึ้น
void get_touch_point(int *x, int *y) {
          … //ทำการคำนวณค่าพิกัดแกน x และแกน y โดยอาจจะอ่านค่ามาจาก ADC
          *x = พิกัดแกน x
          *y = พิกัดแกน y
}
ในการเรียกใช้งาน ก็เพียงแค่ต้องประกาศตัวแปร int ขึ้นมารับค่า โดยส่งตำแหน่งของตัวแปรทั้งสองให้กับ function
int x, y; //ประกาศตัวแปรชนิดเดียวกันไว้สำหรับรับข้อมูล
get_touch_point(&x, &y); //ส่งตำแหน่งของตัวแปรทั้งสอง ไปใน function เพื่อให้เขียนทับกลับมา
จะเห็นว่าการเขียนโปรแกรมแบบนี้ เราจะให้ function ส่งกลับค่ากลับมากี่ค่าก็ได้ นอกจากนี้ยังนิยมใช้การ return เป็นการส่งกลับผลลัพธ์การทำงานของ function ว่าปกติ หรือมีความผิดพลาดบางอย่างเกิดขึ้น เช่น เกิด timeout เรามักจะเห็น function ที่มีการติดต่อกับอุปกรณ์ภายนอก เช่น SD card หรือ IC ต่างๆ return ค่าเป็น int โดยจะ return 0 เมื่อทำงานสำเร็จตามปกติ และ return ค่า -1 หรือค่าอื่นๆ ตามความผิดปกติที่เกิดขึ้น
การเลื่อนตำแหน่งของ pointer
          เราสามารถเลื่อนตำแหน่งของ pointer ได้ด้วยการเขียนโปรแกรมเพิ่มค่าหรือลดค่าเหมือนกับตัวแปรทั่วไป เช่น ใช้ ++, — หรือ +=1, -= 1 แต่มีข้อคำนึงก็คือ การเขียนเพิ่มค่าของตัว pointer เอง จะเป็นการเพิ่มตามขนาดของตัวแปรที่ชี้อยู่ เช่น char, unsigned char มีขนาด 1 byte pointer ของ char จะเลื่อนตำแหน่งทีละ 1 byte แต่สำหรับ long, unsigned long ซึ่งมีขนาด 4 byte การเลื่อนตำแหน่ง 1 ครั้งของ pointer ที่ชี้ไปยังตัวแปรชนิดนี้ จะเพิ่มหรือลดทีละ 4 byte แม้ว่าเราจะใช้ ++ หรือ –
ตัวอย่างการใส่ตำแหน่งของ pointer เป็นตัวเลขโดยตรง
long *ptr; //long มีขนาด 4 byte
ptr = (long *)(0xA0000000+2); //เป็นการใส่ค่าตัวเลขเข้าไปตรงๆ แต่มีการเปลี่ยน type จากตัวเลขธรรมดาให้เป็น (long*) เรียกว่า casting ซึ่งจะมีอธิบายในบทความตอนสุดท้าย
จะได้ตำแหน่งใหม่เป็น 0xA0000002
คราวนี้มาดูตัวอย่างการเลื่อนตำแหน่งของ pointer
long *ptr; //long มีขนาด 4 byte
ptr = (long*)0xA0000000; //เป็นการใส่ค่าตัวเลขเข้าไปตรงๆ เหมือนตัวอย่างที่แล้ว
ptr += 2; //ทำการเลื่อนตำแหน่งไป 2 ตำแหน่ง
จะได้ตำแหน่งใหม่เป็น 0xA0000008
          นอกจากการเลื่อนตำแหน่งที่ชี้อยู่ไปเรื่อยๆแล้ว เรายังอาจจะใช้ [ ] แทนก็ได้ โดยตำแหน่งของ pointer จะไม่เลื่อนไป เช่น ตัวอย่าง 2 ตัวอย่างที่เป็นการส่งข้อความ (string) ออกทางช่อง serial port สมมติให้ UART0_TX เป็น register ที่ใช้ส่งค่าออกทาง UART0 ปกติในการส่งข้อความ เราจะส่งจนกว่าจะเจอค่า 0 ซึ่งเป็นตัวปิด string (สมมติว่าเราไม่ต้องรอให้ UART ส่งข้อมูลแต่ละ byte เสร็จ)
ตัวอย่างแรกจะเป็นการเลื่อนตำแหน่งของ pointer
void print_serial(char *str) {
          while (*str) //จะส่งจนกว่าจะเจอค่า 0
                    UART0_TX = *str++; //ส่งค่าออกทาง serial และเลื่อนตำแหน่ง 1 ตำแหน่ง
}
ตัวอย่างที่สองจะเป็นการใช้ [ ]
void print_serial(char *str) {
          int k = 0;
          while (str[k]) //จะส่งจนกว่าจะเจอค่า 0
                    UART0_TX = str[k++]; //ส่งค่าออกทาง serial และเพิ่มค่า k ทีละ 1
}
          ตัวอย่างทั้งสองนี้ ให้ผลลัพธ์ที่เหมือนกัน เพียงแต่ถ้าเทียบประสิทธิภาพการทำงาน ตัวอย่างแรกจะดีกว่าเพราะตำแหน่งของข้อมูลที่จะอ่านออกมาในตัวอย่างที่ 2 จะต้องใช้การคำนวณที่มากกว่าในทุกๆรอบ
          สำหรับการใช้งานตัวแปร pointer พื้นฐานก็คงมีเท่านี้ ในตอนต่อไปเราจะมาดูกันว่าจะใช้ pointer ทำอะไรได้อีกบ้าง อย่าลืมติดตามนะครับ !!!

<< กลับไปสู่หน้าแรกสารบัญ