C Language (LV.1)
ภาษาซี ระดับพื้นฐาน
โครงสร้างของโปรแกรมภาษาซี
1. ส่วนหัวของโปรแกรม
Preprocessor Directive
ใช้สำหรับเรียกไฟล์ที่โปรแกรมต้องการ และกำหนดค่าต่างๆ จะต้องเริ่มต้นด้วยเครื่องหมายไดเรกทีฟ (#) และตามด้วยชื่อที่ต้องการกำหนดค่า
Directive
การใช้งาน
#include
การโหลด source code จากไฟล์
#define
ประกาศ macro
#undef
ยกเลิกการประกาศ macro
#ifdef
ตรวจสอบว่า macro มีการประกาศไว้หรือไม่
#ifndef
ตรวจสอบว่า macro ไม่ได้มีการประกาศไว้
#if
ตรวจสอบเงื่อนไขบางอย่างกับ macro หากเข้าเงื่อนไขจะทำ directive ที่ตามมา
#else
กำหนดสิ่งที่จะทำ หากไม่เข้าเงื่อนไขใน #if
#elif
ตรวจสอบเงื่อนไขบางอย่างกับ macro เมื่อไม่ตรงเงื่อนไขใน #if
#endif
จบการตรวจสอบเงื่อนไข macro
#line
กำหนดว่าเมื่อ compiler error จะแสดงข้อผิดพลาด เป็นเลขบรรทัด หรือชื่อไฟล์อย่างไร
#error
หยุดการ compile ปกติใช้ร่วมกับ directive ประเภทเงื่อนไข
ตัวอย่าง directive ที่ใช้บ่อยคือ #include #include <...> - compiler จะทำการค้นหา header file จาก directory ที่ใช้เก็บ header file โดยเฉพาะ #include "..." - compiler จะทำการค้นหา header file จาก directory เดียวกับ source code ก่อน หากไม่พบจึงหาใน directory ที่เก็บ header file เฉพาะ #define #define - กำหนดค่าคงที่เพื่อใช้ในโปรแกรม มีประโยชน์ในกรณีที่ค่าถูกใช้หลายที่ในโปรแกรม ทำให้สะดวกต่อการแก้ไข
Global Declaration
เป็นการประกาศชื่อตัวแปร หรือ function ภายในโปรแกรม โดยที่ทุกส่วนของโปรแกรมจะสามารถเรียกใช้ตัวแปร หรือ function นี้ได้
2. ส่วนของ function
ปกติจะเขียนด้วยชื่อบล็อกของชุดคำสั่ง ตามด้วยเครื่องหมาย (...) ภายใน (...) จะระบุตัวแปร เพื่อรับค่าที่ส่งเข้าบล็อกของ function ส่วน {...} เป็นตัวกำหนดขอบเขตของบล็อก
ภายในโปรแกรมจะมีกี่บล็อกของ function ก็ได้ แต่จะต้องมีบล็อก main
3. ส่วนรายละเอียดของโปรแกรม
เป็นส่วนของการเขียนคำสั่ง เพื่อให้โปรแกรมทำงานตามที่ได้ออกแบบไว้
4. ส่วน comment (จะมีหรือไม่ก็ได้)
เขียนเพื่ออธิบายการทำงานของโปรแกรม เพื่อให้ผู้พัฒนาร่วมกันเข้าใจ ระบบจะข้ามการแปลส่วนนี้ ปกติจะเขียนด้วยเครื่องหมาย ดังนี้
comment แบบบรรทัดเดียว ใช้ //... ซึ่งข้อความที่ตามหลังจะเป็น comment
comment แบบหลายบรรทัด ใช้ /*...*/
ตัวอย่างโครงสร้างโปรแกรม
Token & Whitespace
แต่ละกลุ่มอักษร เราเรียกว่า token และช่องว่างระหว่าง token คือ whitespace
ตัวแปร (Variable)
ตัวแปรเป็นส่วนที่ใช้เก็บค่าของข้อมูล โดยสามารถเปลี่ยนแปลงค่าที่ถูกเก็บอยู่ได้ในระหว่างที่โปรแกรมทำงานอยู่ ซึ่งในการเก็บค่า จะต้องกำหนดชนิดของตัวแปรให้ตรงกับข้อมูลที่ต้องการจะเก็บ ชนิดของตัวแปรมีดังนี้
1. ตัวอักษร
char - มีขนาดหนึ่งตัวอักษร
string - กลุ่มอักษรที่เรียงต่อกัน
2. ตัวเลข
2.1 จำนวนเต็ม
int - จำนวนเต็ม
long - จำนวนเต็มที่มีขนาดใหญ่กว่า int
2.2 จำนวนทศนิยม
float - จำนวนทศนิยม
double - จำนวนทศนิยมที่มีขนาดใหญ่กว่า float
long double - จำนวนทศนิยมที่มีขนาดใหญ่กว่า double
ดั้งเดิมในสมัยที่ระบบคอมพิวเตอร์ CPU Architecture 16 bits ชนิดตัวแปรมีค่าดังนี้
Type
ขนาดความจุ (byte)
ค่าที่เป็นไปได้
char
1
-128 ถึง 127 (กรณีนำมาเก็บเลข)
int
2
-32768 ถึง 32767
long
4
-2,147,483,648 ถึง 2,147,483,647
float
4
เลขทศนิยม 6 ตำแหน่ง
double
8
เลขทศนิยม 15 ตำแหน่ง
long double
12
เลขทศนิยม 19 ตำแหน่ง
ขนาดความจุของชนิดข้อมูลมีการเปลี่ยนไป เมื่อ CPU Architecture มีการพัฒนา ดังนั้นค่าที่เป็นไปได้ของ Data Type แต่ละชนิดจึงมีค่ามากกว่าแต่ก่อน เพื่อป้องกันความสับสนในขนาดความจุของข้อมูล ภายหลังจึงมีการกำหนดชนิดตัวแปรแบบระบุ CPU Architecture ไว้ด้วย เช่น int16, int32, int64
ตัวอย่างการคำนวณหาค่าที่เป็นไปได้ของแต่ละ Data Type
sign bit 0 คือ เลขที่มีค่าเป็นบวก 1 คือ เลขที่มีค่าติดลบ value bit มีความเป็นไปได้ 32768 แบบ กรณีทั้ง sign bit และ value bit เป็น 0 ทั้งหมด จะมีค่าเป็น ศูนย์ ดังนั้นในค่าที่เป็นบวก จะมีได้ถึงเลข 32767 ทำให้ int สามารถแทนเลข ที่มีค่าระหว่าง -32768 จนถึง 32767 ได้
กรณีเลขชนิด Unsigned
ในตัวแปรชนิดที่เราไม่ต้องการค่าติดลบ เราสามารถประกาศชนิดข้อมูลแบบ unsigned ได้ เช่น
unsigned int
unsigned long
unsigned float
bit ที่เคยเป็นของ sign bit จะมาเป็นส่วนหนึ่งของ value bit แทน ทำให้ค่าความเป็นไปได้เพิ่มขึ้น ตัวอย่างเช่น int มีความเป็นไปได้ 65536 แบบ ทำให้สามารถแทนเลขได้ตั้งแต่ 0 ถึง 65535
การตั้งชื่อตัวแปร
ห้ามขึ้นต้นด้วยตัวเลข
ห้ามมี whitespace
ห้ามมีสัญลักษณ์พิเศษ ยกเว้น underscore (_)
ห้ามมี reserve word
Reserved word
reserved word คือคำสงวนที่ห้ามใช้เป็นชื่อตัวแปรในโปรแกรม เนื่องจากคำเหล่านี้มีความหมายเฉพาะภายในโปรแกรม ในแต่ละโปรแกรมจะมี reserve word ต่างกันออกไป
auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while
ตัวดำเนินการ (Operator)
ตัวดำเนินการทางคณิตศาสตร์ (Mathematical Operator)
Operator
ความหมาย
ตัวอย่าง
ผลลัพธ์
+
บวก
4+6
10
-
ลบ
5-4
1
*
คูณ
7*1
7
/
หารเอาผล
4/2
2
%
หารเอาเศษ
5%2
1
++
เพิ่มค่าขึ้นหนึ่ง
4++
5
--
ลดค่าลงหนึ่ง
4--
3
ข้อควรระวัง ควรหลีกเลี่ยงการใช้ ++, -- ร่วมกับ operator อื่นในบรรทัดเดียวกัน เนื่องจากอาจทำให้เข้าใจกันผิดพลาดได้ง่าย ตัวอย่าง y = (a++) * 2; จะมีความหมายเท่ากับ y = a * 2; a = a + 1; ในขณะที่ y = (++a) * 2; จะมีความหมายเท่ากับ a = a + 1; y = a * 2; ซึ่งจะทำให้ผลลัพธ์ค่า y ต่างกัน
ลำดับในการดำเนินการทางคณิตศาสตร์
ทำค่าในวงเล็บก่อน
ทำคูณและหารก่อน โดยเรียงลำดับจากซ้ายไปขวา
ทำบวกและลบ โดยเรียงลำดับจากซ้ายไปขวา
ตัวอย่างการคำนวณ
1000/100%(5+6)+13*7 =1000/100%11+13*7 =10%11+13*7 =10+13*7 =10+91 =101
ตัวดำเนินการเปรียบเทียบ (Comparison Operator)
Operator
ความหมาย
ตัวอย่าง
ผลลัพธ์
==
เท่ากับ
4==3
เท็จ
!=
ไม่เท่ากับ
4!=3
จริง
>
มากกว่า
4>3
จริง
>=
มากกว่าหรือเท่ากับ
3>=3
จริง
<
น้อยกว่า
4<3
เท็จ
<=
น้อยกว่าหรือเท่ากับ
4<=4
จริง
ตัวดำเนินการทางตรรกะ (Logical Operator)
Operator
ควาหมาย
&&
และ
||
หรือ
!
นิเสธ
ค่าที่หนึ่ง
Operator
ค่าที่สอง
ผลลัพธ์
T
&&
T
T
T
&&
F
F
F
&&
T
F
F
&&
F
F
T
||
T
T
T
||
F
T
F
||
T
T
F
||
F
F
ค่า
ผลลัพธ์
!T
F
!F
T
ตัวดำเนินการกำหนดค่า (Assignment Operator)
Operator
การใช้งาน
ผลของตัวแปร
ตัวอย่าง
ผลลัพธ์
=
ตัวแปร = ตัวเลข
ตัวเลข
a = 3
a = 3
+=
ตัวแปร += ตัวเลข
ตัวแปร + ตัวเลข
a += 3
a = a+3
-=
ตัวแปร -= ตัวเลข
ตัวแปร - ตัวเลข
a -= 3
a = a-3
*=
ตัวแปร *= ตัวเลข
ตัวแปร * ตัวเลข
a *= 3
a = a*3
/=
ตัวแปร /= ตัวเลข
ตัวแปร / ตัวเลข
a /= 3
a = a/3
%=
ตัวแปร %= ตัวเลข
ตัวแปร % ตัวเลข
a %= 3
a = a%3
ข้อควรระวัง ชนิดของตัวแปรมีผลต่อผลลัพธ์ เช่น int a = 5, b = 2; float x; x = a/b; จะได้ผลลัพธ์ ค่า x เป็น 2 เนื่องจากโปรแกรมคิดว่า int/int ต้องได้ผลลัพธ์เป็น int แม้ว่าชนิดตัวแปรที่รับการกำหนดค่าเป็นชนิดอื่นก็ตาม หากต้องการให้ผลลัพธ์เป็น float ต้องทำการแปลงชนิดข้อมูล โดยใส่ (ชนิด) ไว้ข้างหน้า เช่น x = (float) a/b; วิธีนี้เรียกว่า Implicit Type Conversion หรือ Implicit Type Casting
การแสดงผล
ใช้ function printf ในการแสดงค่าออกหน้าจอ
ตัวอย่างการใช้งาน
ผลลัพธ์บนหน้าจอ
printf("Hello World")
Hello World
int x = 10;
printf("%d", x);
10
int x =10;
printf("A = %d", x);
A = 10
int x = 1, y = 2, z = 3;
printf("%d %d %d", x, y, z)
1 2 3
ตัวแทนชนิดข้อมูลที่ใช้บ่อย
เครื่องหมาย
ชนิดข้อมูล
%d
int
%u
unsigned int
%f
float
%c
char
%s
string
Escape sequence
เป็นรหัสพิเศษที่ช่วยในการจัดการแสดงผล ค่าที่ใช้บ่อยดังนี้
เครื่องหมาย
ผลลัพธ์
\n
ขึ้นบรรทัดใหม่
\r
เลื่อนเคอเซอร์ไปซ้ายสุด
\t
Tab ในแนวนอน
\'
พิมพ์ single quote (')
\"
พิมพ์ double quote (")
\\
พิมพ์ backslash (\)
\0
ค่าว่าง (Null character)
การประกาศค่าคงที่
ใช้เพื่อให้ไม่สามารถเปลี่ยนค่าของตัวแปรได้ เมื่อประกาศไปแล้ว ทำได้โดยใส่ const นำหน้าชื่อตัวแปร เมื่อประกาศตัวแปร เช่น
การรับค่าจากผู้ใช้
ใช้ฟังก์ชัน scanf วิธีการใช้ดังนี้
scanf("ตัวแทนชนิดข้อมูล", &ตัวแปร);
เช่น
หากมี อักษรอื่นๆ นอกจากตัวแทนชนิดข้อมูลอยู่ใน function scanf แล้ว ผู้ใช้ต้องกรอกอักษรเหล่านั้นให้ตรงด้วย ไม่เช่นนั้นโปรแกรมจะตัดค่าลงตัวแปรไม่ถูกต้อง เช่น scanf("%d:%d", &hour, &minute); ผู้ใช้อาจจะกรอกเป็น "10:23"
รูปแบบคำสั่งกำหนดเงื่อนไข (Conditional Statements)
ใช้เพื่อเปลี่ยน Flow การทำงานของโปรแกรม มีรูปแบบดังนี้
IF statement
เป็นการกำหนดเงื่อนไข ซึ่งจะทำคำสั่งซึ่งอยู่ภายในขอบเขต {...} ก็ต่อเมื่อเงื่อนไขเป็นจริง
ตัวอย่างเช่น
หาก a > b เป็นจริง ก็จะทำคำสั่งภายในบล็อก
ข้อควรระวัง หากไม่เขียน {...} เพื่อกำหนดขอบเขตของบล็อก จะถือว่าส่วนที่อยู่ภายในขอบเขต มีเพียงบรรทัดเดียวถัดจากบรรทัด if ซึ่งจะส่งผลให้การทำงานผิดจากที่ต้องการได้ int a=5, b=6; if(a > b) a=b; //ผลเป็นเท็จจึงข้ามบรรทัดนี้ a--; //ไม่มี {...} จึงถือว่าส่วนนี้อยู่นอก scope if และทำงาน เกิดการข้ามเพียงบรรทัดเดียว จึงได้ผลลัพธ์ ดังนี้ a=>4, b=>6
IF-ELSE Statement
เป็นการกำหนดเงื่อนไขการทำงาน โดยหากเงื่อนไขเป็นจริง จะทำงานในส่วนขอบเขตของ if แต่หากไม่เป็นจริง จะทำงานภายใต้ขอบเขตของ else
ตัวอย่างเช่น
ถ้า a เป็น 5 จะมีเงื่อนไขเป็นจริง ทำให้ทำงาน statement a++ และได้ผลลัพธ์เป็น 6 แต่ถ้า a เป็น 2 จะมีเงื่อนไขเป็นเท็จ ทำให้ทำงาน statement a-- และได้ผลลัพธ์เป็น 1
IF-ELSE IF-ELSE Statement
เป็นการกำหนดเงื่อนไขที่ซับซ้อนขึ้น โดยหากเงื่อนไขใน if ไม่เป็นจริง จะมีการไปตรวจสอบเงื่อนไขในส่วน else if ต่อไปก่อนว่าเป็นจริงหรือไม่ แล้วจึงค่อยไปทำงานในส่วนของ else หากไม่มีเงื่อนไขใดเป็นจริงเลย
ตัวอย่างเช่น
Switch Statement
ในบางครั้ง condition อาจเป็นการตรวจสอบว่า variable มีค่าตรงกับค่าใด การเขียน IF-ELSE IF-ELSE Statement บางครั้งอาจดูซับซ้อนไป สามารถเขียนให้อ่านง่ายได้ด้วย switch statement แทน
ตัวอย่างเช่น
จะได้ผลลัพธ์ออกหน้าจอเป็น I got B
ข้อควรระวัง หากใน case นั้นๆ break หายไป อาจทำให้โปรแกรมทำงานผิดจากที่ต้องการได้ เพราะเมื่อไม่มี break จะทำให้ หลังจากโปรแกรมทำงานใน statement ของตัวเองแล้ว จะทำ statement ใน case ถัดไปด้วย เช่น จากตัวอย่าง หาก break ใน case 1(บรรทัดที่6) หายไป จะได้ผลลัพธ์ออกหน้าจอเป็น I got DI got F
รูปแบบคำสั่งทำซ้ำ (Iteration Statements)
ใช้เพื่อเปลี่ยน Flow การทำงานของโปรแกรม มีรูปแบบดังนี้
WHILE Loop Statement
จะมีการตรวจสอบเงื่อนไขก่อนว่าเป็นจริงหรือไม่ หากเป็นจริงจึงจะทำคำสั่งที่อยู่ในขอบเขต {...} และจะมีการทำซ้ำไปเรื่อยๆ หากเงื่อนไขยังคงเป็นจริงอยู่
ตัวอย่างเช่น
ข้อควรระวัง เช่นเดียวกับ if statement หากไม่เขียน {...} เพื่อกำหนดขอบเขตของบล็อก จะถือว่าบรรทัดถัดจาก while เพียงบรรทัดเดียว ที่อยู่ในขอบเขต
DO-WHILE Loop Statement
คล้าย While Loop statement แต่จะมีการทำงานไปรอบหนึ่ง แล้วจึงค่อยตรวจสอบเงื่อนไข หากเงื่อนไขยังคงเป็นจริงอยู่ก็จะทำซ้ำไปเรื่อยๆ จนกว่าเงื่อนไขจะเป็นเท็จ
FOR Loop Statement
มักจะใช้ในรูปแบบการวนซ้ำที่มีมีการระบุจำนวนครั้งอย่างชัดเจน จะมีความคล้ายกับ While Loop statement คือตรวจสอบเงื่อนไขก่อนเริ่มทำงานในขอบเขต {...}
ตัวอย่างเมื่อเปรียบเทียบกับ While Loop statement
Array
เป็นโครงสร้างการเก็บข้อมูลจำนวนมากซึ่งมีชนิดเดียวกัน มีจำนวนข้อมูลที่แน่นอน และมีความสัมพันธ์ในเชิงลำดับต่อกัน โดยข้อมูลที่เก็บจะมีการจองพื้นที่หน่วยความจำซึ่งเรียงต่อกันอีกด้วย
เปรียบเทียบระหว่างการประกาศตัวแปรตามปกติ กับ array
การประกาศตัวแปรตามปกติจะมีขนาดสำหรับเก็บข้อมูลตามชนิดของตัวแปร เพียง 1 ค่า แต่การประกาศตัวแปรแบบ Array จะได้พื้นที่เก็บข้อมูลเรียงต่อกัน ตามจำนวนที่เรากำหนด
การประกาศตัวแปร
ตัวอย่างเช่น
การระบุตำแหน่งข้อมูลใน Array
ตำแหน่งข้อมูลใน Array เราเรียกว่า index โดย index จะเริ่มตั้งแต่ 0
การเข้าถึงข้อมูลทำได้โดยระบุเลข index ภายใน [...] ซึ่งตามหลังชื่อตัวแปรของ Array เช่น
ข้อควรระวัง ในตัวแปรประเภท character การจะเก็บข้อความซึ่งความยาว n ตัวอักษร จะต้องการพื้นที่เก็บจำนวน n+1 ตัวอักษร เนื่องจากต้องมี NULL character ('\0') เป็นตัวปิดท้ายข้อความ เช่น char message[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
การเก็บ String ลงใน Array ประเภท character ทำได้ดังนี้
การใช้ %s แทน %c จะทำให้สามารถรับค่าทั้งข้อความได้เลย ไม่ต้องเก็บทีละตัวอักษร โปรแกรมจะทำการเก็บค่าแต่ละตัวอักษรในข้อความลงในตัวแปรตามลำดับตั้งแต่ index 0 ไปจนจบข้อความ
Array หลายมิติ
เราสามารถสร้าง Array หลายมิติได้ โดยกำหนดขนาดของมิติอื่นได้ด้วยการระบุ [...] ต่อท้ายเพิ่มไป เช่น
Array สามารถมีจำนวนมิติได้ไม่จำกัด ตำแหน่งของพื้นที่ในหน่วยความจำสำหรับ Array หลายมิติ เป็นดังนี้
ตัวอย่างการเข้าถึงข้อมูลใน Array หลายมิติ
Pointers
เป็นตัวแปรซึ่งเก็บค่า memory address ของข้อมูล การประกาศ Pointer ทำได้ดังนี้
ตัวอย่างเช่น
การเข้าถึงค่าหรือพื้นที่จัดเก็บข้อมูล ซึ่งอยู่ภายใต้ address แต่ละตัว สามารถทำได้โดย ระบุ * หน้า Pointer เช่น
จากตัวอย่าง จะเป็นการเข้าถึงค่าของข้อมูลโดยอ้างอิงจาก address ซึ่งเก็บอยู่ใน pa (ซึ่งเป็น address ของตัวแปร a) และนำค่าไปเก็บในตัวแปร b
ในทางกลับกัน เราอาจจะกำหนดค่า และนำไปใส่ในตำแหน่งพื้นที่ที่ Pointer อ้างอิงอยู่ก็ได้ ดังนี้
การเลื่อน Pointer
ในการเลื่อน Pointer ไปยังตำแหน่ง address ถัดไป หรือก่อนหน้า จะทำได้โดยการบวก/ลบค่าของ address ที่เก็บอยู่ เพื่อเป็นการอ้างอิงไปยัง address ข้างเคียง เพียงแต่ขนาดของข้อมูลแต่ชนิดนั้น มีผลต่อเลข address หากบวก/ลบ ผิดขนาด จะส่งผลให้โปรแกรมทำงานผิดพลาดได้ ทางแก้คือ ควรใช้ ++ หรือ -- แทน เนื่องจากโปรแกรมจะทราบว่า Pointer นั้นเป็น Pointer ของข้อมูลชนิดใด และจะทำการบวก/ลบค่า ตามขนาดข้อมูลให้ เช่น
ข้อแตกต่างระหว่าง Array กับ Pointer
Pointer
Array
เก็บ Address ของข้อมูล
เก็บข้อมูล
การเข้าถึงข้อมูลเป็นแบบทางอ้อม (ต้องผ่าน address ก่อน)
สามารถเข้าถึงข้อมูลได้ทางตรงโดยการระบุ index
มักจะใช้กับโครงสร้างข้อมูลที่มีการเปลี่ยนแปลงได้ในขณะ run time
มักจะใช้กับข้อมูลที่มีขนาดแน่นอนตลอดการทำงานของโปรแกรม
มักจะใช้คู่กับ function malloc() และ free()
มีการจัดสรรไว้ก่อนที่โปรแกรมจะเริ่มทำงาน
โดยปกติใช้อ้างอิงข้อมูลที่ไม่เจาะจงตำแหน่ง มีตำแหน่งตอน run-time
ตำแหน่ง address ของข้อมูลถูกกำหนดแน่นอนตอนที่ compile โปรแกรม
การใช้ function malloc() และ free()
malloc เป็น function ที่ใช้ในการจองพื้นที่หน่วยความจำขณะ run time และ free เป็น function ที่ใช้คืนพื้นที่หน่วยความจำที่ขอมา
ข้อควรระวัง ในการจองพื้นที่หน่วยความจำด้วย malloc หากไม่ใช้งานพื้นที่หน่วยความจำแล้ว ควรจะใช้ free เพื่อคืนพื้นที่หน่วยความจำกลับไปด้วย ไม่เช่นนั้นอาจจะทำให้พื้นที่หน่วยความจำหมด ไม่สามารถจองเพิ่มได้อีก
การใช้ malloc ทำได้โดยการกำหนดขนาด byte ที่ต้องการจะจองเป็น argument ใน function malloc และจะได้ค่า address ของพื้นที่ที่จอง ตอบกลับมา เช่น
จากตัวอย่างจะเป็นการจองพื้นที่ขนาด 4 bytes ให้กับ Pointer pa จะมี int* เพื่อทำ implicit type conversion เพื่อให้รู้ว่าค่า ที่ return กลับมาจาก function malloc เป็น address ของ int pointer
การใช้ free ทำได้โดยระบุ address แรกของพื้นที่ซึ่งต้องการคืนพื้นที่มาเป็น argument ของ function เช่น
การใช้ function gets() และ puts()
function gets() สามารถใช้รับค่า string จากผู้ใช้มาได้เหมือนกับ function scanf() มีตัวอย่างการใช้ดังนี้
function puts() สามารถใช้แสดงค่า string ได้เหมือนกับ function printf()
Functions
เป็นส่วนของโปรแกรมที่แยกออกมา เพื่อกำหนดขั้นตอนการทำงานซึ่งมีความซ้ำซ้อนหรือคล้ายคลึงกัน มีการใช้ซ้ำบ่อยๆ การแยกส่วนของโปรแกรมออกมาเป็นฟังก์ชัน จะทำให้โปรแกรมเป็นส่วนๆมากขึ้น ลดความซ้ำซ้อน ลดความผิดพลาดจากการแก้ไขไม่ครบ และทำให้โปรแกรมอ่านง่ายขึ้น
การทำงานของ Function
ฟังก์ชันจะถูกใช้งานเมื่อมีการเรียกใช้ และทำงานตามคำสั่งที่อยู่ภายใต้ขอบเขตของฟังก์ชัน หลังจากทำงานเสร็จจะโดดกลับไปทำงานต่อจากส่วนที่เรียกใช้
รูปแบบการประกาศ Function
ฟังก์ชันสามารถรับค่ามาได้หลายค่า และมาเก็บอยู่ในตัวแปร Parameter แต่การที่ฟังก์ชันจะส่งค่าตอบกลับไปหลังจากทำงานเสร็จนั้น จะตอบกลับได้เพียงค่าเดียว การตอบกลับจะใช้ส่วนที่เรียกว่า return เมื่อฟังก์ชันพบส่วน return จะโดดกลับไปที่ส่วนที่เรียกฟังก์ชันทันที ดังนั้นหากมี code ส่วนใดอยู่ถัดจากส่วน return นั้น code ส่วนนั้นจะไม่ถูกทำงาน
เราสามารถที่จะสร้างฟังก์ชันที่จะทำงานไปจนจบฟังก์ชันโดยไม่ตอบกลับค่าใดๆไปได้ ดังนั้นภายในฟังก์ชันจะไม่มีบรรทัด return และชนิดของค่าที่ return จะแทนด้วย void
ตัวอย่างการประกาศ Function
การจะใช้งานฟังก์ชันได้ จะต้องประกาศฟังก์ชันไว้ก่อน ในบางภาษาจึงต้องประกาศฟังก์ชันไว้ก่อนส่วนที่เป็นการทำงานหลัก เช่น ก่อนส่วน function main() ซึ่งภาษาซีก็มีลักษณะนั้นเช่นกัน ดังนั้นหากมีรายละเอียดคำสั่งภายในฟังก์ชันเยอะ ก็จะเป็นความลำบากในการหาส่วนการทำงานหลัก และไล่การทำงานของโปรแกรม ทางแก้คือ การแยกส่วนประกาศ interface เชื่อมต่อในการเรียกใช้งานฟังก์ชัน (function prototype) ออกจากส่วนที่เป็นรายละเอียดของฟังก์ชัน (function implementation) ได้ ตัวอย่างเช่น
ซึ่งการทำเช่นนี้จะทำให้เราสามารถเขียนส่วนที่เป็นรายละเอียดการทำงานของฟังก์ชันอยู่บรรทัดหลังจาก function main() ได้ และสะดวกต่อการอ่าน code โปรแกรม
รูปแบบการส่งค่า argument ให้กับ Function
Pass by value
เป็นการส่งค่าแบบปกติ เป็นการ copy ค่าจาก argument ที่ให้มาในการเรียกฟังก์ชัน ไปใส่ในตัวแปร parameter ของฟังก์ชัน ตัวอย่างเช่น
การเปลี่ยนแปลงค่าภายในฟังก์ชัน ไม่มีผลต่อตัวแปรของการทำงานหลัก เพราะเป็นคนละตัวแปรกัน เพียงแค่ชื่อตัวแปรอาจจะตรงกันและ copy ค่าไปให้ทำงานภายในฟังก์ชันเท่านั้น
Pass by pointer
เป็นการ copy ค่า address ของตัวแปรไปให้ ดังนั้นหากภายในฟังก์ชันมีการเรียกใช้ตำแหน่งข้อมูลจาก address นั้น จะเป็นการเรียกใช้โดยอ้อม และมีผลต่อค่าที่เก็บอยู่ในตำแหน่งข้อมูลนั้น ตัวอย่างเช่น
ประโยชน์อย่างหนึ่งที่ได้จากการใช้ Pass by pointer คือ การแก้ไขค่าโดยฟังก์ชัน เพราะฟังก์ชันสามารถ return ค่ากลับได้เพียงค่าเดียว การส่ง address ของข้อมูลไปให้อ้างอิง และแก้ไข จะทำให้ฟังก์ชันสามารถอัพเดตข้อมูลได้มากกว่าหนึ่งค่า แต่การใช้ Pass by pointer ก็มีจุดอ่อนด้านความปลอดภัย เพราะ การใช้ pointer ชี้ตำแหน่ง address และทำการแก้ไขข้อมูลอาจจะเป็นจุดอ่อนให้ Hacker สามารถอ้างอิงไปยัง address อื่นๆได้
ตัวอย่างการใช้ Pass by pointer กับข้อมูลชนิด array สามารถรับมาและใช้ในรูปแบบ Array ได้ตามเดิม ตอนที่รับค่ามาใช้ มีเพียงมิติแรกเท่านั้นที่ไม่ต้องระบุขนาดของมิติ มิติอื่นๆต้องกำหนดขนาด เพื่อใช้ในการคำนวณขนาดมิติแรก
Strings
เป็น Array 1 มิติของ char ตัวอักษรภายใน string สามารถเข้าถึงได้เช่นเดียวกับส่วนหนึ่งของ array หรือใช้ pointer ระบุตำแหน่ง char NULL character ('\0'; ASCII 0) ถูกใช้เพื่อบอกจุดสิ้นสุดของ string
การประกาศ string คือการสร้าง Array ของ character ขนาดตามข้อมูลที่จะเก็บ + 1
การรับค่ามาเก็บสามารถใช้ function scanf() ร่วมกับตัวแทนชนิดข้อมูล string (%s)
เราสามารถประกาศข้อมูล string ได้โดยตรงเมื่อสร้าง Array
Structure & Union
Structure
Structure คือชนิดข้อมูลที่นิยามขึ้นภายในโปรแกรม จะประกอบด้วยชื่อชนิดข้อมูลที่จะสร้าง และโครงสร้างชนิดข้อมูลของสมาชิกภายใน
การประกาศ Structure
ตัวอย่างเช่น
จากตัวอย่าง จะเกิดชนิดข้อมูลชนิดใหม่ขึ้นชื่อ "struct student" ตัวอย่างการเรียกใช้ เช่น
การใช้แบบนี้จะไม่สะดวก โดยปกติจึงจะนำ typedef มาช่วยแก้ปัญหานี้ เช่น
นอกจากนี้ เรายังสามารถสร้าง Structure ซ้อนกันได้ ตัวอย่างเช่น
การเข้าถึงข้อมูลภายใน structure
กรณีตัวแปรธรรมดา เข้าถึงได้ด้วย dot operator (.) เช่น
กรณีตัวแปรแบบ Pointer
การเข้าถึงด้วย dot operator อาจสร้างความซับซ้อน ผิดพลาดได้ง่าย และไม่สะดวกต่อการใช้งาน จึงควรใช้ arrow operator (->) แทน เช่น
Union
จะแตกต่างจาก Structure ชนิดข้อมูลแบบ Structure จะมีขนาดเท่ากับผลรวมของขนาดสมาชิกทุกตัว และสมาชิกทุกตัวจะมี address ของตนเอง แต่ Union จะมีขนาดเท่ากับขนาดของสมาชิกที่ใหญ่ที่สุด และสมาชิกทุกตัวจะมี address เดียวกัน
ปกติ union จะถูกใช้ทำหน้าที่เป็น buffer ของข้อมูล
การประกาศ Union
ตัวอย่างเช่น
Files
ในภาษาซี การจัดการเกี่ยวกับไฟล์ไม่ว่าจะเป็นการเขียน หรือการอ่านจากไฟล์ จะดำเนินการผ่านสิ่งที่เรียกว่า data stream stream ในภาษาซีมีสองแบบ คือ text (อักษร) กับ binary (ข้อมูลที่เป็น bit 0,1)
การระบุตำแหน่งของข้อมูลภายในไฟล์ จะดำเนินการผ่าน Pointer ของข้อมูลชนิด FILE
ในการสร้างไฟล์หรือจัดการกับไฟล์เดิมที่มีอยู่ จะต้องเริ่มจากการเปิดไฟล์ ด้วย function fopen() ซึ่งในการเปิดไฟล์จะต้องระบุโหมดการเข้าถึงไฟล์ (access mode) เพื่อให้โปรแกรมเข้าใจว่าเป็นการเปิดเพื่อ อ่าน หรือเขียน หรือทั้งสองอย่าง เมื่อใช้เสร็จแล้วก็ควรจะปิดไฟล์เพื่อคืน resource ให้กับระบบ
การเปิดไฟล์
มี Pattern ดังนี้
ตัวอย่างการใช้งาน
access mode
ความหมาย
r
เปิดไฟล์เพื่ออ่านอย่างเดียว โดยมี cursor อยู่ที่หัวไฟล์
w
สร้างไฟล์เพื่อเขียน หากไฟล์มีอยู่แล้วจะเกิดการเขียนทับ
a
เปิดเพื่อเพิ่มข้อมูลที่ ท้ายไฟล์ (end-of-file) หากไฟล์ไม่เคยมีอยู่จะสร้างและเขียนลงไป
r+
เปิดไฟล์เพื่ออ่านและเขียน โดยมี cursor อยู่ที่หัวไฟล์
w+
สร้างไฟล์เพื่ออ่านและเขียน โดยมี cursor อยู่ที่หัวไฟล์ หากไฟล์มีอยู่แล้วจะถูกเขียนทับ
a+
เปิดไฟล์เพื่ออ่านและเขียน โดยการอ่านจะมี cursor อยู่ที่หัวไฟล์ แต่การเขียนจะเป็นการเขียนข้อมูลต่อท้ายไฟล์ หากไฟล์ไม่เคยมีอยู่จะสร้างและเขียนลงไป
การปิดไฟล์
จะใช้ function fclose() โดยมี argument เป็น Pointer ของ FILE เช่น
ข้อมูลที่มีการสั่งเขียนและยังคงค้างอยู่ใน Buffer จะถูก flush (เขียน) ลงไฟล์ แล้วจึงปิดไฟล์ หน่วยความจำสำหรับ input buffer และ output buffer จะถูกคืนให้กับระบบ
การอ่านและเขียนไฟล์มี 3 แบบ
ดำเนินการทีละตัวอักษร
ดำเนินการทีละ string
ดำเนินการทีละ Block ของข้อมูล
ฟังก์ชันอ่านทีละตัวอักษร
จะ return เป็นเลข ASCII ของอักษรที่ถูกอ่าน หากมี error จะ return เป็น EOF
ฟังก์ชันเขียนทีละตัวอักษร
จะ return เป็นเลข ASCII ของอักษรที่ถูกเขียน หากมี error จะ return เป็น EOF
ตัวอย่างการใช้งาน
ฟังก์ชันอ่านทีละ string
ฟังก์ชันจะอ่านข้อมูลจากไฟล์ จนถึง string_length - 1 หรือขึ้นบรรทัดใหม่ และจะเติม NULL character ให้ที่ท้ายข้อมูลที่อ่าน กรณีที่อ่านสำเร็จจะมี return string กรณีอ่านจนจบไฟล์ (End-of-File; EOF) จะ return ค่า NULL
ฟังก์ชันเขียนทีละ string
ฟังก์ชันจะอ่าน NULL character ไปด้วย แต่จะไม่เขียน NULL character ลงไฟล์ ถ้าเขียนสำเร็จจะ return non-negative value แต่ถ้า error จะ return EOF
ตัวอย่างการใช้งาน
ฟังก์ชันอ่านทีละ block
ฟังก์ชันจะอ่านข้อมูลจากไฟล์ โดยจำนวนที่อ่านขึ้นมาในแต่ละรอบมีขนาดเท่ากับที่ระบุใน size และจะอ่านทั้งหมดเท่ากับ N_block รอบ หากอ่านสำเร็จ จะ return จำนวนรอบที่อ่านสำเร็จ ซึ่งจะเท่ากับค่า size หาก error หรืออ่านไปจนสุดไฟล์ จะ return ค่าที่ไม่ตรงกับ size (อาจจะเป็น 0 ได้)
ฟังก์ชันเขียนทีละ block
ฟังก์ชันจะเขียนข้อมูลลงไฟล์ โดยจำนวนที่เขียนในแต่ละรอบมีขนาดเท่ากับที่ระบุใน size และจะเขียนทั้งหมดเท่ากับ N_block รอบ หากเขียนสำเร็จ จะ return จำนวนรอบที่เขียนสำเร็จ ซึ่งจะเท่ากับค่า size หากจำนวนที่ return ไม่ตรงกับที่ระบุใน size แสดงว่าอาจจะเกิด error
ตัวอย่างการใช้งาน
Last updated
Was this helpful?