ในการเขียนโปรแกรมไม่ว่าภาษาอะไรย่อมต้องเกี่ยวข้องกับข้อความตัวอักษร หรือชุดความที่เรียกว่า String แต่สำหรับภาษา C แล้วจะแตกต่างจากโปรแกรมอื่นๆ เล็กน้อย ตรงที่ไม่มีตัวแปรชนิด String แล้วจะมีตัวแปรชนิด char เพียงอย่างเดียว โดยตัวแปร char จะเป็น ASCII Code ดังนั้นการจัดเก็บจึงเป็นตัวเลขแบบ Unsigned Integer เช่น อักขระ a ในตาราง ASCII จะมีค่า 65 ดังนั้นถ้าเราพิมพ์ว่า a+1 จะมีค่าเป็น b หรือ 66
ส่วนข้อความโดยทั่วไปนั้นในภาษา C จะเรียกว่า ชุดรวมอักขระ (Chain of character) คือ เป็นการนำเอาอักขระ (ตัวแปรชนิด char) มาต่อกันหลายๆ ตัวแล้วปิดท้ายด้วยอักขระว่าง หรือ \0 เป็นการสิ้นสุดข้อความ เช่น
char a[10] = "Hello";
เมื่อเรากำหนดแบบนี้ในระบบจะเก็บข้อมูลในเม็มโมรีเป็น
'H', 'e', 'l', 'l', 'o', '\0'
ทั้งหมดมี 6 ตัวอักขระ ตรงนี้ต้องระวัง เพราะถ้าเรากำหนด a[5] = "Hello"; จะเสี่ยงต่อการเกิดข้อผิดพลาดทันที ตัวอย่างเช่น
char a[5] = "Hello";
char b[6] = "World";
printf("%s, %s\n", a, b);
ตัวอย่างนี้จะพิมพ์คำว่า HelloWorld, World ออกทางหน้าจอ เพราะข้อความแรก ตัวแปร a ไม่มีรหัสสิ้นสุด ระบบจะอ่านไปเรื่อยๆ จนกว่าจะพบอักขระ \0 แต่ตัวแปร b
นี่เป็นหลักการของ String ในภาษา C สำหรับ Gtk4 C ก็ไม่ได้แตกต่างอะไรมากมาย เพียงแต่ Gtk เป็น Linux Base ก็มีรูปแบบของตัวเอง เช่น มีตัวแปรชนิด gchar เพราะมีไลบรารี glib ซึ่งไม่มีในภาษา C มาตรฐาน ดังนั้นหากใครจะมองว่าไม่ใช่มาตรฐาน C Standard ก็ใช่ เพราะนี่เป็นโลกของ Gtk
แต่โดยหลักการแล้ว String ในภาษา C (และ C บนลีนุกซ์) ก็จะมีดังนี้
- ข้อความที่อ่านได้อย่างเดียว
- ข้อความที่เป็น Array และ
- ข้อความที่อยู่ใน Heap
Read only string
ข้อความ หรือ String literal ในภาษา C นั้นจะครอบด้วยเครื่องหมายคำพูด หรือ double quote เช่น
char *s;
char s = "Hello";
ตัวแปร s จะเป็น read only เราไม่สามารถเปลี่ยนแปลงข้อความใน s ได้ หากโปรแกรมพยายามเปลี่ยนแปลงก็จะได้รับ error ว่า Segmentation fault (core dumped) และระบบจะหยุดโปรแกรม เช่น
*(s+1) = 'a';
ตัวอย่างคำสั่งนี้จะพยายามเปลี่ยนตำแหน่งที่ +1 ของ s คือ อักขระตัวที่ 2 จาก e ให้เป็น a จะทำไม่ได้
แต่ถ้าเป็นตัวแปรแบบนี้ จะสามารถแก้ไขได้
char s[6] = "Hello";
*(s+1) = 'a';
printf("%s\n", s);
ผลที่ได้จะเป็น Hallo เพราะเราเปลี่ยนตำแหน่ง s+1 คือ ตำแหน่งที่ 2 ในที่นี้ คือ เปลี่ยน e เป็น a
Strings defined as arrays
ในการกำหนดตัวแปรข้อความหรือชุดตัวอักษรนั้นมีอีกแบบหนึ่งเรียกว่า array of character ซึ่งนำเอาตัวอักขระมาเรียงกันแล้วปิดท้ายด้วยเครื่องหมาย '\0' เช่น
char s[6] = "Hello";
การกำหนดแบบนี้ข้อความจะสามารถแก้ไขได้ เพราะตัวแปรนี้จะถูกเก็บไว้ใน Stack ซึ่งเป็นพื้นที่หน่วยความจำแบบอัตโนมัติ ไม่ต้องจองพื้นที่ เป็นแบบ LIFO หรือ เข้าทีหลังออกก่อน (Last In First Out)
ตัวแปรจะมีขอบเขตการทำงานเฉพาะภายในฟังค์ชันนั้นๆ พอออกจากสโคปหรือฟังค์ชันนั้นตัวแปรจะถูกทำลาย เช่น
int main(){
int i = 0;
for (;i < 5; i++){
char c = 65+i;
printf ("%c", c);
}
printf ("%c", c);
return 0;
}
ในฟังค์ชัน main จะมีลูป for(){ } อยู่อันหนึ่ง ภายใน for นี้จะมีประกาศตัวแปร char c ไว้ในลูป ตัวแปรแบบนี้เป็นตัวแปรที่เก็บไว้ใน stack เมื่อออกจากลูปไปแล้ว หลัง { } ของ for ตัวแปร c จะถูกทำลายไปหมดแล้ว ระบบจึงคอมไพล์ไม่ผ่านแล้วแจ้งออกมาทางหน้า ดังรูปด้านล่างนี้
ตัวอย่างข้างบนตัวแปร c จะสร้างใหม่และถูกทำลายอยู่ในลูปไปเรื่อยๆ จนกว่าจะหมดเงื่อนไข i < 5 และออกจาก loop ก็จะมองไม่เห็นตัวแปร c แล้ว
Strings in the heap area
ในภาษา C ที่เป็นมาตรฐานนั้นจะใช้ malloc และ free เพื่อจองและคืนหน่วยความจำ แต่สำหรับ Glib แล้วจะมี g_new และ g_free สำหรับจองและคืนหน่วยความจำ แต่ g_new จริงๆ แล้วเป็นมาโครเพื่อจองหน่วยความจำอีกทีหนึ่ง รูปแบบการใช้งาน คือ
g_new (struct_type, n_struct)
struct_type
คือ ชนิดของอะเรย์n_struct
คือ ขนาดของอะไร- สิ่งที่ส่งค่ากลับก็จะเป็นพอยเตอร์หน่วยความจำที่จอง
ตัวอย่างเช่น
char *s;
s = g_new (char, 10);
/* s เป็น points ชี้ไปยังอะเรย์ชนิด char มีขนาดเท่ากับ 10 */
สำหรับ g_free เป็นการคืนค่าหน่วยความจำ มีรูปแบบการใช้งานดังนี้
void
g_free (gpointer mem);
คำสั่งข้างบนจะคืนหน่วยความจำตำแหน่ง gpointer mem ถ้า mem มีค่าเป็น NULL แล้ว g_free ก็ไม่ทำอะไร การใช้งานก็จะใช้หลังจากที่เลิกใช้ตัวแปร (ที่ประกาศด้วย g_new)
ในบางฟังค์ชันของ Glib ก็จะมีการจองหน่วยความจำใน Heap เช่นกัน ตัวอย่างเช่นฟังค์ชัน g_strdup จะจอง Heap แล้วคัดลอกข้อความที่กำหนดแล้วส่งค่าตำแหน่งคืนมา เช่น
char *s;
s = g_strdup ("Hello");
g_free (s);
ข้อความ "Hello" จะถูกจองใน Heap ไว้ 6 bytes เพราะระบบจะเพิ่ม '\0' ต่อท้ายให้ และส่งค่าตำแหน่งคืนไปยังตัวแปร s ซึ่งจะเป็นตัวแปรอะเรย์นั่นเอง ดังนั้นหลังจากเลิกใช้งานตัวแปรนี้แล้วต้องคืนหน่วยความจำตำแหน่งนั้นด้วย โดยใช้คำสั่ง g_free(s);
Some GLib functions return a string which mustn't be freed by the caller.
const char *
g_quark_to_string (GQuark quark);
This function returns const char*
type. The qualifier const
means that the returned value is immutable. The characters pointed by the returned value aren't be allowed to be changed or freed.
If a variable is qualified with const
, the variable can't be assigned except during initialization.
const int x = 10; /* initialization is OK. */
x = 20; /* This is illegal because x is qualified with const */
เรียบเรียงจาก
https://github.com/ToshioCP/Gtk4-tutorial/blob/main/gfm/sec6.md
ไม่มีความคิดเห็น:
แสดงความคิดเห็น