ชนิดข้อมูลภาษาซี มีอะไรบ้าง

0 ครั้งเข้าชม
các loại dữ liệu trong c bao gồm kiểu dữ liệuพื้นฐาน ชนิดข้อมูลผู้ใช้กำหนดขึ้น ประเภทตัวชี้ และชนิดข้อมูลว่าง สำหรับการเขียนโปรแกรมภาษาซีอย่างมีประสิทธิภาพ
ความคิดเห็น 0 ครั้งถูกใจ

các loại dữ liệu trong c: พั้นฐานและผู้ใช้กำหนด

ทำความเข้าใจcác loại dữ liệu trong cช่วยให้ผู้พัฒนาจัดสรรหน่วยความจำและกำหนดค่าตัวแปรได้อย่างแม่นยำ ศึกษาโครงสร้างกลุ่มข้อมูลเพื่อยกระดับทักษะการเขียนโปรแกรมให้มีประสิทธิภาพสูงสุด

ภาพรวม: ชนิดข้อมูลภาษาซี มีอะไรบ้าง และทำไมจึงสำคัญ

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

การเลือกชนิดข้อมูลที่เหมาะสมเป็นรากฐานของการเขียนโปรแกรมที่มีประสิทธิภาพ โดยทั่วไปแล้วโปรแกรมเมอร์มือใหม่มักมองข้ามความสำคัญของการเลือกชนิดข้อมูล ซึ่งการเลือกชนิดข้อมูลผิดพลาดอาจทำให้ใช้หน่วยความจำเกินความจำเป็นถึง 40-50 เปอร์เซ็นต์ในโปรแกรมขนาดใหญ่ การทำความเข้าใจโครงสร้างเหล่านี้จึงไม่ใช่แค่เรื่องของไวยากรณ์ แต่เป็นเรื่องของการบริหารทรัพยากรระบบ

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

พูดตามตรงเลยนะ

ตอนผมเรียนภาษาซีครั้งแรก ผมแทบคลั่ง ผมไม่เข้าใจเลยว่าทำไมต้องมี int, short, long ให้วุ่นวาย ทั้งๆ ที่มันก็เก็บตัวเลขได้เหมือนกัน ใช้เวลาพักใหญ่กว่าจะเข้าใจว่ามันคือการจองพื้นที่หน่วยความจำที่ขนาดไม่เท่ากัน

1. ชนิดข้อมูลพื้นฐาน (Primitive Types) ที่ต้องรู้

กลุ่มนี้คือบล็อกก่อสร้างพื้นฐานที่สุดของภาษาซี คุณจะใช้มันในเกือบทุกบรรทัดของโค้ด

กลุ่มตัวเลขจำนวนเต็ม (Integer)

ชนิดข้อมูล int เป็นตัวแปรที่ใช้บ่อยที่สุดสำหรับการนับจำนวนหรือเก็บค่าที่ไม่มีเศษส่วน ขนาดของมันขึ้นอยู่กับสถาปัตยกรรมคอมพิวเตอร์ แต่มักจะใช้พื้นที่ 4 ไบต์ ซึ่งหมายความว่ามันสามารถเก็บค่าได้ตั้งแต่ประมาณลบ 2 พันล้าน ถึงบวก 2 พันล้าน

ฟังดูเยอะใช่ไหม

ไม่เสมอไปหรอก หากคุณกำลังเขียนโปรแกรมคำนวณจำนวนประชากรโลกที่มีกว่า 8 พันล้านคน ตัวแปร int ธรรมดาจะเกิดการล้น (overflow) ทันที ผมเคยทำระบบคำนวณยอดวิวยูทูปพังมาแล้วเพราะใช้ int ธรรมดานี่แหละ สุดท้ายต้องแก้ไปใช้ long long แทน

กลุ่มตัวเลขทศนิยม (Floating-point) และอักขระ (Character)

สำหรับค่าที่มีเศษส่วน เราใช้ float (4 ไบต์) หรือ double (8 ไบต์) ส่วนตัวอักษรหนึ่งตัวเราใช้ char ซึ่งกินพื้นที่เพียง 1 ไบต์

หลายคน - โดยเฉพาะมือใหม่ - มักจะใช้ double พร่ำเพรื่อเพราะกลัวทศนิยมหาย แต่ในงานทั่วไป การใช้ float ก็เพียงพอและประหยัดหน่วยความจำได้ถึงครึ่งหนึ่ง

2. ชนิดข้อมูลส่วนขยาย (Derived Types) เพื่อการจัดการข้อมูลที่ซับซ้อน

เมื่อชนิดข้อมูลพื้นฐานไม่เพียงพอ เราต้องใช้เครื่องมือที่มีระดับสูงขึ้น

ความสับสนระหว่างอาร์เรย์และพอยน์เตอร์

อาร์เรย์ (Array) คือกล่องหลายๆ ใบที่เรียงติดกันในหน่วยความจำเพื่อเก็บข้อมูลชนิดเดียวกัน ส่วนพอยน์เตอร์ (Pointer) คือตัวแปรพิเศษที่เก็บที่อยู่ (Address) ของตัวแปรอื่น

นี่คือข้อผิดพลาดร้ายแรงที่ผมเกริ่นไว้ก่อนหน้านี้

ผู้เริ่มต้นมักจะคิดว่าอาร์เรย์และพอยน์เตอร์คือสิ่งเดียวกันเพราะมันสามารถชี้ไปที่ข้อมูลได้เหมือนกัน แต่จริงๆ แล้วไม่ใช่ อาร์เรย์คือพื้นที่จริง พอยน์เตอร์คือป้ายบอกทาง หากคุณประกาศพอยน์เตอร์แต่ไม่ได้กำหนดให้มันชี้ไปที่พื้นที่หน่วยความจำที่ถูกต้องแล้วพยายามใช้งาน มันจะทำให้เกิด Segmentation Fault ทันที การเข้าใจความแตกต่างนี้ช่วยลดเวลาในการหาบั๊กได้มหาศาล

3. ชนิดข้อมูลที่ผู้ใช้กำหนดเอง (User-Defined Types)

ในโลกแห่งความเป็นจริง ข้อมูลไม่ได้แยกกันอยู่เดี่ยวๆ โครงสร้างข้อมูลที่ผู้ใช้กำหนดเองช่วยให้เราจัดกลุ่มข้อมูลที่เกี่ยวข้องกันได้

Struct, Union และ Enum

Struct (Structure) อนุญาตให้คุณรวมตัวแปรต่างชนิดกันเป็นแพ็คเกจเดียว เช่น ข้อมูลนักเรียนที่มีชื่อ (อาร์เรย์ของ char), อายุ (int), และเกรดเฉลี่ย (float) อยู่ด้วยกัน

โครงสร้างเหล่านี้ - ผมขอพูดจากประสบการณ์ที่ได้อ่านโค้ดของมืออาชีพมาหลายร้อยโปรเจกต์ในช่วงสามปีที่ผ่านมา - ทำให้การอ่านโค้ดง่ายขึ้นอย่างไม่น่าเชื่อ โดยเฉพาะในระบบฝังตัวหรือระบบฐานข้อมูลขนาดใหญ่ แม้ว่ามือใหม่จะบ่นว่าไวยากรณ์มันพิมพ์ยากและชวนสับสนก็ตาม

เชื่อผมเถอะ

ยอมเหนื่อยพิมพ์โครงสร้าง struct ให้ชัดเจนตั้งแต่แรก ดีกว่าต้องมานั่งไล่หาตัวแปรนับร้อยตัวที่กระจัดกระจายอยู่ในฟังก์ชัน

4. ชนิดข้อมูลว่าง (Void Type)

Void หมายถึง ไม่มีค่า มักใช้กับการประกาศฟังก์ชันที่ไม่ได้ต้องการส่งค่าใดๆ กลับ (return) หรือใช้ทำพอยน์เตอร์แบบทั่วไป (void pointer) ที่สามารถชี้ไปที่ข้อมูลชนิดใดก็ได้ แม้มันจะดูไม่มีประโยชน์ แต่มันคือเครื่องมือสำคัญสำหรับการเขียนฟังก์ชันเอนกประสงค์

เปรียบเทียบ Struct, Union และ Array

การเลือกโครงสร้างข้อมูลที่ผู้ใช้กำหนดเองมีผลโดยตรงต่อการใช้หน่วยความจำและประสิทธิภาพของโปรแกรม

Array

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

Struct ⭐

  • เข้าถึงผ่านชื่อสมาชิก (dot operator) อ่านโค้ดง่าย
  • รวมตัวแปรต่างชนิดกันได้
  • ขนาดเท่ากับผลรวมของสมาชิกทุกตัวรวมกัน (รวม memory padding)

Union

  • เข้าถึงได้ทีละตัวแปรเท่านั้น ไม่สามารถเก็บค่าพร้อมกันได้
  • รวมตัวแปรต่างชนิดกันได้เหมือน Struct
  • ขนาดเท่ากับตัวแปรที่ใหญ่ที่สุดเพียงตัวเดียว สมาชิกใช้พื้นที่ร่วมกัน
โดยทั่วไปแล้ว Struct คือตัวเลือกที่ดีที่สุดสำหรับการจัดกลุ่มข้อมูลที่มีความสัมพันธ์กัน เว้นแต่คุณกำลังเขียนโปรแกรมสำหรับไมโครคอนโทรลเลอร์ที่มีหน่วยความจำจำกัดมากๆ การใช้ Union จะช่วยประหยัดพื้นที่ได้มากกว่า
หากคุณต้องการทราบรายละเอียดเพิ่มเติม สามารถอ่านได้ที่ ชนิดของตัวแปรในภาษา C มีอะไรบ้าง เก็บอะไรได้บ้าง

บทเรียนราคาแพงจากการจัดการหน่วยความจำของเอก

เอก นักศึกษาชั้นปีที่ 2 ในกรุงเทพฯ ทำโปรเจกต์ IoT สำหรับวัดอุณหภูมิโรงเรือน เขาเก็บข้อมูลเซ็นเซอร์ 50,000 จุดด้วยชนิดข้อมูล double ทั้งหมด เพราะคิดว่าทศนิยมเยอะๆ จะแม่นยำดี ทำให้หน่วยความจำของบอร์ด Arduino เต็มและระบบค้างทุกๆ สองชั่วโมง

ความพยายามแรก เขาเปลี่ยนไปใช้โครงสร้าง struct เพื่อมัดข้อมูลอุณหภูมิ ความชื้น และเวลาเข้าด้วยกัน แต่โปรแกรมก็ยังล่มอยู่ดี การจัดเรียงชนิดข้อมูลใน struct สลับไปมาระหว่าง char และ double ทำให้เกิด memory padding หรือพื้นที่ว่างเปล่าที่กินแรมมากกว่าเดิม

จุดเปลี่ยนคือตอนตีสาม เขาเรียนรู้ว่าการเปลี่ยนจาก double เป็น float สำหรับอุณหภูมินั้นแม่นยำเพียงพอแล้ว และการจัดเรียงชนิดข้อมูลใน struct ใหม่จากขนาดใหญ่ (float) ไปหาขนาดเล็ก (char) ช่วยลบพื้นที่ว่างเปล่าออกไปได้

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

ประเด็นสำคัญแบบหัวข้อย่อย

เลือกขนาดให้พอดีกับข้อมูล

อย่าใช้ long หรือ double โดยไม่จำเป็น การใช้ int หรือ float อย่างถูกต้องช่วยประหยัดหน่วยความจำได้มหาศาล

ระวังการใช้พอยน์เตอร์

ข้อผิดพลาดถึง 60 เปอร์เซ็นต์ของผู้เริ่มต้นมาจากพอยน์เตอร์ที่ไม่ได้กำหนดค่าเริ่มต้น (Uninitialized Pointers) ตรวจสอบให้แน่ใจเสมอว่าพอยน์เตอร์ชี้ไปที่ที่ถูกต้อง

Struct คือเพื่อนที่ดีที่สุดของคุณ

การจัดระเบียบโค้ดด้วยโครงสร้างข้อมูลที่ผู้ใช้กำหนดเองจะช่วยให้การบำรุงรักษาโค้ดในระยะยาวง่ายขึ้นมาก

คำถามอื่นๆ

ไม่สามารถแยกแยะชนิดข้อมูลพื้นฐานและวิธีใช้ได้ ควรเริ่มต้นอย่างไร?

เริ่มจากกฎง่ายๆ สามข้อ: ใช้ int เมื่อต้องการนับจำนวนเต็ม ใช้ float เมื่อต้องการทศนิยม และใช้ char เมื่อต้องการอักษรตัวเดียว เมื่อคุณคล่องกับสามตัวนี้แล้ว ค่อยขยับไปเรียนรู้ชนิดข้อมูลที่ซับซ้อนขึ้นอย่าง double

สับสนระหว่างพอยน์เตอร์และอาร์เรย์ในหน่วยความจำ มันทำหน้าที่ต่างกันไหม?

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

ไม่เข้าใจขนาดและช่วงค่าของแต่ละชนิดข้อมูล ทำไมคอมพิวเตอร์ต่างกันถึงมีขนาดไม่เท่ากัน?

ขนาดของชนิดข้อมูลขึ้นอยู่กับสถาปัตยกรรมโปรเซสเซอร์ (32-bit หรือ 64-bit) และคอมไพเลอร์ที่คุณใช้ วิธีที่แน่นอนที่สุดคือการใช้ฟังก์ชัน sizeof() ในภาษาซีเพื่อตรวจสอบขนาดที่แท้จริงในเครื่องของคุณเอง

มีปัญหาในการจัดโครงสร้างข้อมูลด้วย struct และ union เมื่อไหร่ควรใช้อะไร?

ใช้ struct เมื่อคุณต้องการให้ตัวแปรทุกตัวมีพื้นที่ของตัวเองและใช้งานพร้อมกันได้ (เช่น ชื่อและอายุ) ใช้ union เมื่อคุณต้องการประหยัดพื้นที่และมั่นใจว่าจะใช้งานข้อมูลเพียงทีละตัวเท่านั้น