👤
Novice Handbook
  • Novice Handbook
  • Guide
  • Internet และ Web
    • HTML
  • Computer Language
    • Basic Computer Language (LV.1)
    • C Language (LV.1)
    • Python3 (LV.1)
  • Operating System
    • Linux
      • Basic Linux (LV.1)
  • TOOLS
    • Text Editor
      • Vim Editor
    • Source Control
      • GitLab
        • GitLab for small site (LV.1)
    • Container
      • Docker
        • Docker (LV.1)
        • Docker (LV.2)
      • Kubernetes
        • Kubernetes Intro (LV.0)
        • Kubernetes Basic (LV.1)
        • Kubernetes Intermediate (LV.2)
        • Helm (LV.2)
        • RKE2 (LV.3)
        • K3S (LV.3)
        • K3D (LV.3)
    • Repository
      • Harbor
        • Harbor for small site (LV.1)
        • Harbor for enterprise (LV.2)
    • Database
      • Redis
        • Redis on Docker Compose (LV.1)
        • Redis on Kubernetes (LV.2)
      • Elastic Stack
        • Elasticsearch & Kibana for small site (LV.1)
    • Observability
      • Prometheus
        • Prometheus for small site (LV.1)
        • Prometheus Operator (LV.2)
    • Security
      • Certbot (LV.1)
      • Falco
      • Hashicorp Vault
    • Collaboration
      • Nextcloud
Powered by GitBook
On this page
  • โครงสร้างของโปรแกรมภาษาซี
  • 1. ส่วนหัวของโปรแกรม
  • 2. ส่วนของ function
  • 3. ส่วนรายละเอียดของโปรแกรม
  • 4. ส่วน comment (จะมีหรือไม่ก็ได้)
  • ตัวอย่างโครงสร้างโปรแกรม
  • Token & Whitespace
  • ตัวแปร (Variable)
  • 1. ตัวอักษร
  • 2. ตัวเลข
  • การตั้งชื่อตัวแปร
  • Reserved word
  • ตัวดำเนินการ (Operator)
  • ตัวดำเนินการทางคณิตศาสตร์ (Mathematical Operator)
  • ตัวดำเนินการเปรียบเทียบ (Comparison Operator)
  • ตัวดำเนินการทางตรรกะ (Logical Operator)
  • ตัวดำเนินการกำหนดค่า (Assignment Operator)
  • การแสดงผล
  • ตัวแทนชนิดข้อมูลที่ใช้บ่อย
  • Escape sequence
  • การประกาศค่าคงที่
  • การรับค่าจากผู้ใช้
  • รูปแบบคำสั่งกำหนดเงื่อนไข (Conditional Statements)
  • IF statement
  • IF-ELSE Statement
  • IF-ELSE IF-ELSE Statement
  • Switch Statement
  • รูปแบบคำสั่งทำซ้ำ (Iteration Statements)
  • WHILE Loop Statement
  • DO-WHILE Loop Statement
  • FOR Loop Statement
  • Array
  • การประกาศตัวแปร
  • การระบุตำแหน่งข้อมูลใน Array
  • Array หลายมิติ
  • ตัวอย่างการเข้าถึงข้อมูลใน Array หลายมิติ
  • Pointers
  • การเลื่อน Pointer
  • ข้อแตกต่างระหว่าง Array กับ Pointer
  • การใช้ function malloc() และ free()
  • การใช้ function gets() และ puts()
  • Functions
  • การทำงานของ Function
  • รูปแบบการประกาศ Function
  • รูปแบบการส่งค่า argument ให้กับ Function
  • Strings
  • Structure & Union
  • Structure
  • Union
  • Files
  • การเปิดไฟล์
  • การปิดไฟล์
  • ฟังก์ชันอ่านทีละตัวอักษร
  • ฟังก์ชันเขียนทีละตัวอักษร
  • ฟังก์ชันอ่านทีละ string
  • ฟังก์ชันเขียนทีละ string
  • ฟังก์ชันอ่านทีละ block
  • ฟังก์ชันเขียนทีละ block

Was this helpful?

  1. Computer Language

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

main(...) {
   ...
}

3. ส่วนรายละเอียดของโปรแกรม

เป็นส่วนของการเขียนคำสั่ง เพื่อให้โปรแกรมทำงานตามที่ได้ออกแบบไว้

4. ส่วน comment (จะมีหรือไม่ก็ได้)

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

comment แบบบรรทัดเดียว ใช้ //... ซึ่งข้อความที่ตามหลังจะเป็น comment

// this is comment

comment แบบหลายบรรทัด ใช้ /*...*/

/* this
is
multiple
line
comment*/

ตัวอย่างโครงสร้างโปรแกรม

#include <stdio.h> //Include Standard I/O
#include "conio.h"
#define pi 3.14159265
int z=1;

float cal_circle_area(int radius) {
  /* this function receive radius as input
     it calculate the area
     and then return the result */
  return pi * radius * radius;
}

int main() {
  float result = cal_circle_area(z);
  printf("Result is %.2f", result);
  return 0;
}

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 215=327682^{15} = 32768215=32768 มีความเป็นไปได้ 32768 แบบ กรณีทั้ง sign bit และ value bit เป็น 0 ทั้งหมด จะมีค่าเป็น ศูนย์ ดังนั้นในค่าที่เป็นบวก จะมีได้ถึงเลข 32767 ทำให้ int สามารถแทนเลข ที่มีค่าระหว่าง -32768 จนถึง 32767 ได้

กรณีเลขชนิด Unsigned

ในตัวแปรชนิดที่เราไม่ต้องการค่าติดลบ เราสามารถประกาศชนิดข้อมูลแบบ unsigned ได้ เช่น

  • unsigned int

  • unsigned long

  • unsigned float

bit ที่เคยเป็นของ sign bit จะมาเป็นส่วนหนึ่งของ value bit แทน ทำให้ค่าความเป็นไปได้เพิ่มขึ้น ตัวอย่างเช่น int 216=655362^{16} = 65536216=65536 มีความเป็นไปได้ 65536 แบบ ทำให้สามารถแทนเลขได้ตั้งแต่ 0 ถึง 65535

การตั้งชื่อตัวแปร

  • ห้ามขึ้นต้นด้วยตัวเลข

int 1a;
int a1;
  • ห้ามมี whitespace

int x 1;
int x1;
  • ห้ามมีสัญลักษณ์พิเศษ ยกเว้น underscore (_)

int x+y;
int x_y;
  • ห้ามมี reserve word

int printf;
int double;
int something;

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

% เรียกว่า มอดูลัส (modulus)

ข้อสังเกต การหารเอาเศษ 7%4 => 3 4%7 => 4 -7%4 => -3 7%-4 => 3 -7%-4 => -3 ดังนั้น ถ้าตัวถูกหารมีค่าเป็นลบ จะได้ผลลัพธ์เป็นค่าลบ

ข้อควรระวัง ควรหลีกเลี่ยงการใช้ ++, -- ร่วมกับ operator อื่นในบรรทัดเดียวกัน เนื่องจากอาจทำให้เข้าใจกันผิดพลาดได้ง่าย ตัวอย่าง y = (a++) * 2; จะมีความหมายเท่ากับ y = a * 2; a = a + 1; ในขณะที่ y = (++a) * 2; จะมีความหมายเท่ากับ a = a + 1; y = a * 2; ซึ่งจะทำให้ผลลัพธ์ค่า y ต่างกัน

ลำดับในการดำเนินการทางคณิตศาสตร์

  1. ทำค่าในวงเล็บก่อน

  2. ทำคูณและหารก่อน โดยเรียงลำดับจากซ้ายไปขวา

  3. ทำบวกและลบ โดยเรียงลำดับจากซ้ายไปขวา

ตัวอย่างการคำนวณ

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 = 3; a = a+1; จะเป็นการคำนวณ 3+1 ได้ผลลัพธ์เป็น 4 แล้วเก็บลงตัวแปร a ทำให้ หลังการดำเนินการ a มีค่าเป็น 4

ข้อควรระวัง ชนิดของตัวแปรมีผลต่อผลลัพธ์ เช่น 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

หากมีการใช้ตัวเลขร่วมกับชนิดตัวแทนข้อมูล จะมีความหมายเฉพาะ %<ตัวเลข><เครื่องหมาย> - จะบอกว่าต้องการพื้นที่ช่องอักษรตามจำนวนตัวเลข และใส่อักษรลงไปในพื้นที่นั้นโดยชิดขวา เช่น %3d ของ 10 จะได้ " 10" หากตัวเลขติดลบ จะหมายถึงการชิดซ้าย เช่น %-3d ของ 10 จะได้ "10 " กรณีตัวเลขขึ้นต้นด้วย 0 (ใช้ได้กับข้อมูลตัวเลขเท่านั้น เช่น int float) หมายถึงพื้นที่ว่างนั้นให้เติมด้วย 0 เช่น %02d ของ 6 จะได้ "06" กรณี มีจุดทศนิยม ก่อนหน้าตัวเลข หมายความว่า ตัวเลขนั้น แทนจำนวนหลักของทศนิยม เช่น %.2f ของ 3.14159265 จะได้ "3.14" %2.2f ของ 3.14159265 จะได้ "3.14" (เพราะเลขน้อยกว่าจำนวนอักษรที่ต้องพิมพ์ทั้งหมด) %5.2f ของ 3.14159265 จะได้ " 3.14" %06.2f ของ 3.14159265 จะได้ "003.14"

Escape sequence

เป็นรหัสพิเศษที่ช่วยในการจัดการแสดงผล ค่าที่ใช้บ่อยดังนี้

เครื่องหมาย

ผลลัพธ์

\n

ขึ้นบรรทัดใหม่

\r

เลื่อนเคอเซอร์ไปซ้ายสุด

\t

Tab ในแนวนอน

\'

พิมพ์ single quote (')

\"

พิมพ์ double quote (")

\\

พิมพ์ backslash (\)

\0

ค่าว่าง (Null character)

การประกาศค่าคงที่

ใช้เพื่อให้ไม่สามารถเปลี่ยนค่าของตัวแปรได้ เมื่อประกาศไปแล้ว ทำได้โดยใส่ const นำหน้าชื่อตัวแปร เมื่อประกาศตัวแปร เช่น

const int a=200;

การรับค่าจากผู้ใช้

ใช้ฟังก์ชัน scanf วิธีการใช้ดังนี้

scanf("ตัวแทนชนิดข้อมูล", &ตัวแปร);

เช่น

scanf("%d", &x);

ในการรับค่า string จะไม่ใช้ %s ในการรับค่า แต่จะใช้ %c แทน เช่น scanf("%c", &mystring);

หากมี อักษรอื่นๆ นอกจากตัวแทนชนิดข้อมูลอยู่ใน function scanf แล้ว ผู้ใช้ต้องกรอกอักษรเหล่านั้นให้ตรงด้วย ไม่เช่นนั้นโปรแกรมจะตัดค่าลงตัวแปรไม่ถูกต้อง เช่น scanf("%d:%d", &hour, &minute); ผู้ใช้อาจจะกรอกเป็น "10:23"

รูปแบบคำสั่งกำหนดเงื่อนไข (Conditional Statements)

ใช้เพื่อเปลี่ยน Flow การทำงานของโปรแกรม มีรูปแบบดังนี้

IF statement

เป็นการกำหนดเงื่อนไข ซึ่งจะทำคำสั่งซึ่งอยู่ภายในขอบเขต {...} ก็ต่อเมื่อเงื่อนไขเป็นจริง

if(condition) {
  statement;
  ...
}

ตัวอย่างเช่น

if(a > b) {
  a = b;
  b++;
}

หาก a > b เป็นจริง ก็จะทำคำสั่งภายในบล็อก

ข้อควรระวัง หากไม่เขียน {...} เพื่อกำหนดขอบเขตของบล็อก จะถือว่าส่วนที่อยู่ภายในขอบเขต มีเพียงบรรทัดเดียวถัดจากบรรทัด if ซึ่งจะส่งผลให้การทำงานผิดจากที่ต้องการได้ int a=5, b=6; if(a > b) a=b; //ผลเป็นเท็จจึงข้ามบรรทัดนี้ a--; //ไม่มี {...} จึงถือว่าส่วนนี้อยู่นอก scope if และทำงาน เกิดการข้ามเพียงบรรทัดเดียว จึงได้ผลลัพธ์ ดังนี้ a=>4, b=>6

สามารถใช้ตัวเลขแทน True/False ใน condition ได้ โดยค่าใดก็ตามที่เป็น zero จะถือเป็น False ส่วน non-zero จะเป็น True เช่น if(0) => False if(1) => True if(-1) => True

IF-ELSE Statement

เป็นการกำหนดเงื่อนไขการทำงาน โดยหากเงื่อนไขเป็นจริง จะทำงานในส่วนขอบเขตของ if แต่หากไม่เป็นจริง จะทำงานภายใต้ขอบเขตของ else

if(condition) {
  ... // TRUE block
} else {
  ... // FALSE block
}

ตัวอย่างเช่น

if( a > 3 ) {
  a++;
} else {
  a--;
}

ถ้า a เป็น 5 จะมีเงื่อนไขเป็นจริง ทำให้ทำงาน statement a++ และได้ผลลัพธ์เป็น 6 แต่ถ้า a เป็น 2 จะมีเงื่อนไขเป็นเท็จ ทำให้ทำงาน statement a-- และได้ผลลัพธ์เป็น 1

IF-ELSE IF-ELSE Statement

เป็นการกำหนดเงื่อนไขที่ซับซ้อนขึ้น โดยหากเงื่อนไขใน if ไม่เป็นจริง จะมีการไปตรวจสอบเงื่อนไขในส่วน else if ต่อไปก่อนว่าเป็นจริงหรือไม่ แล้วจึงค่อยไปทำงานในส่วนของ else หากไม่มีเงื่อนไขใดเป็นจริงเลย

if(condition1) {
  ... // Condition1 is True
} else if(condition2) {
  ... // Condition2 is True
} else if(condition3) {
  ... // Confition3 is True
} else {
  ... // no condition meet
}

ตัวอย่างเช่น

if(grade > 80) {
  printf("you got A");
} else if(grade > 70) {
  printf("you got B");
} else if(grade > 60) {
  printf("you got C");
} else if(grade > 50) {
  printf("you got D");
} else {
  printf("you got F");
}

Switch Statement

ในบางครั้ง condition อาจเป็นการตรวจสอบว่า variable มีค่าตรงกับค่าใด การเขียน IF-ELSE IF-ELSE Statement บางครั้งอาจดูซับซ้อนไป สามารถเขียนให้อ่านง่ายได้ด้วย switch statement แทน

switch(variable) {
  case value1 : statement1; break; // do if variable==value1
  case value2 : statement2; break; // do if variable==value2
  case value3 : statement3; break; // do if variable==value3
  ...
  default: statementN;
}

ตัวอย่างเช่น

int grade=3;
switch(grade) {
  case 4 : printf("I got A"); break;
  case 3 : printf("I got B"); break;
  case 2 : printf("I got C"); break;
  case 1 : printf("I got D"); break;
  case 0 : printf("I got F"); break;
  default: printf("Something went wrong!");
}

จะได้ผลลัพธ์ออกหน้าจอเป็น I got B

ข้อควรระวัง หากใน case นั้นๆ break หายไป อาจทำให้โปรแกรมทำงานผิดจากที่ต้องการได้ เพราะเมื่อไม่มี break จะทำให้ หลังจากโปรแกรมทำงานใน statement ของตัวเองแล้ว จะทำ statement ใน case ถัดไปด้วย เช่น จากตัวอย่าง หาก break ใน case 1(บรรทัดที่6) หายไป จะได้ผลลัพธ์ออกหน้าจอเป็น I got DI got F

รูปแบบคำสั่งทำซ้ำ (Iteration Statements)

ใช้เพื่อเปลี่ยน Flow การทำงานของโปรแกรม มีรูปแบบดังนี้

WHILE Loop Statement

จะมีการตรวจสอบเงื่อนไขก่อนว่าเป็นจริงหรือไม่ หากเป็นจริงจึงจะทำคำสั่งที่อยู่ในขอบเขต {...} และจะมีการทำซ้ำไปเรื่อยๆ หากเงื่อนไขยังคงเป็นจริงอยู่

while(condition) {
  statement;
}

ตัวอย่างเช่น

int x = 3;
while(x > 0) {
  x--;
  printf("%d", x);
}

ข้อควรระวัง เช่นเดียวกับ if statement หากไม่เขียน {...} เพื่อกำหนดขอบเขตของบล็อก จะถือว่าบรรทัดถัดจาก while เพียงบรรทัดเดียว ที่อยู่ในขอบเขต

DO-WHILE Loop Statement

คล้าย While Loop statement แต่จะมีการทำงานไปรอบหนึ่ง แล้วจึงค่อยตรวจสอบเงื่อนไข หากเงื่อนไขยังคงเป็นจริงอยู่ก็จะทำซ้ำไปเรื่อยๆ จนกว่าเงื่อนไขจะเป็นเท็จ

do {
  statement;
}while(condition)

FOR Loop Statement

มักจะใช้ในรูปแบบการวนซ้ำที่มีมีการระบุจำนวนครั้งอย่างชัดเจน จะมีความคล้ายกับ While Loop statement คือตรวจสอบเงื่อนไขก่อนเริ่มทำงานในขอบเขต {...}

for(initialization ; condition; increment) {
  statement;
}

ตัวอย่างเมื่อเปรียบเทียบกับ While Loop statement

for(int i = 1; i >= 10; i++) {
  printf("%d", i);
}
int i = 1;
while(i >= 10) {
  printf("%d", i);
  i++;
}

Array

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

เปรียบเทียบระหว่างการประกาศตัวแปรตามปกติ กับ array

การประกาศตัวแปรตามปกติจะมีขนาดสำหรับเก็บข้อมูลตามชนิดของตัวแปร เพียง 1 ค่า แต่การประกาศตัวแปรแบบ Array จะได้พื้นที่เก็บข้อมูลเรียงต่อกัน ตามจำนวนที่เรากำหนด

การประกาศตัวแปร

type arrayName[arraySize];

ตัวอย่างเช่น

int a[3];
int b[3] = {1,2,3};
char c[4];

การระบุตำแหน่งข้อมูลใน Array

ตำแหน่งข้อมูลใน Array เราเรียกว่า index โดย index จะเริ่มตั้งแต่ 0

การเข้าถึงข้อมูลทำได้โดยระบุเลข index ภายใน [...] ซึ่งตามหลังชื่อตัวแปรของ Array เช่น

int a[10];
a[2] = 10; // assign number 10 to array a at index 2 (the third element)
a[3] = a[2] * 2; /* retrieve the value from index 2 and multiply with 2.
Then, assign the result to array a at index 3 (the fourth element). */

ข้อควรระวัง ในตัวแปรประเภท character การจะเก็บข้อความซึ่งความยาว n ตัวอักษร จะต้องการพื้นที่เก็บจำนวน n+1 ตัวอักษร เนื่องจากต้องมี NULL character ('\0') เป็นตัวปิดท้ายข้อความ เช่น char message[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

ใน Array ตัวเลข การมีการกำหนดค่าเริ่มต้นให้เมื่อประกาศตัวแปร ในตำแหน่งที่ไม่ได้กำหนดค่ามา จะมีค่าเป็น 0 เช่น int n[5]={1,2,3} n[4] และ n[5] จะมีค่าเป็น 0

การเก็บ String ลงใน Array ประเภท character ทำได้ดังนี้

char string[30];
scanf("%s", string);

การใช้ %s แทน %c จะทำให้สามารถรับค่าทั้งข้อความได้เลย ไม่ต้องเก็บทีละตัวอักษร โปรแกรมจะทำการเก็บค่าแต่ละตัวอักษรในข้อความลงในตัวแปรตามลำดับตั้งแต่ index 0 ไปจนจบข้อความ

Array หลายมิติ

เราสามารถสร้าง Array หลายมิติได้ โดยกำหนดขนาดของมิติอื่นได้ด้วยการระบุ [...] ต่อท้ายเพิ่มไป เช่น

// define 1 dimension array - size
int array1dimension[5] = {1,2,3,4,5};
// define 2 dimentsion array - row, column
int array2dimension[3][4] = { {0,1,2,3},
                              {1,3,5,7},
                              {2,4,6,8} };
// define 3 dimension array - x, y, z
int array3dimension[2][2][2] = { { {0,1}, {2,3} },
                                 { {4,5}, {6,7} } };

Array สามารถมีจำนวนมิติได้ไม่จำกัด ตำแหน่งของพื้นที่ในหน่วยความจำสำหรับ Array หลายมิติ เป็นดังนี้

ตัวอย่างการเข้าถึงข้อมูลใน Array หลายมิติ

int a[3][3]={};
a[0][2] = 1;
a[2][2] = a[0][2] * 3;
printf("%d\n", a[2][2]);

for(int i=0; i<3 ; i++) {
  for(int j=0; j<3 ; j++) {
    printf("%d\n", a[i][j]);
  }
}

Pointers

เป็นตัวแปรซึ่งเก็บค่า memory address ของข้อมูล การประกาศ Pointer ทำได้ดังนี้

type *variable_name;
type* variable1, variable2;

ตัวอย่างเช่น

char a = 'H';
char *pa;
pa = &a;

เราสามารถหา address ของตัวแปรแต่ละตัวได้จากเครื่องหมาย ampersand (&) เช่น pa = &a; จะเป็นการหา address ของตัวแปร a และนำไปเก็บในตัวแปร pa

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

int a = 10, b;
int *pa;
pa = &a;
b = *pa;
printf("%d", b);

จากตัวอย่าง จะเป็นการเข้าถึงค่าของข้อมูลโดยอ้างอิงจาก address ซึ่งเก็บอยู่ใน pa (ซึ่งเป็น address ของตัวแปร a) และนำค่าไปเก็บในตัวแปร b

ในทางกลับกัน เราอาจจะกำหนดค่า และนำไปใส่ในตำแหน่งพื้นที่ที่ Pointer อ้างอิงอยู่ก็ได้ ดังนี้

int a;
int *pa;
pa = &a;
*pa = 10;
printf("%d", a);

การเลื่อน Pointer

ในการเลื่อน Pointer ไปยังตำแหน่ง address ถัดไป หรือก่อนหน้า จะทำได้โดยการบวก/ลบค่าของ address ที่เก็บอยู่ เพื่อเป็นการอ้างอิงไปยัง address ข้างเคียง เพียงแต่ขนาดของข้อมูลแต่ชนิดนั้น มีผลต่อเลข address หากบวก/ลบ ผิดขนาด จะส่งผลให้โปรแกรมทำงานผิดพลาดได้ ทางแก้คือ ควรใช้ ++ หรือ -- แทน เนื่องจากโปรแกรมจะทราบว่า Pointer นั้นเป็น Pointer ของข้อมูลชนิดใด และจะทำการบวก/ลบค่า ตามขนาดข้อมูลให้ เช่น

int b[5] = {1,2,3,4,5};
int *pb;
pb = &b[2];
printf("%d", (int) pb); // first address number
pb++;
printf("%d", (int) pb); // second address is first address + size of int

ข้อแตกต่างระหว่าง 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 ที่ใช้คืนพื้นที่หน่วยความจำที่ขอมา

function นี้อยู่ภายใต้ lib stdlib.h ดังนั้นต้อง include header file ก่อนใช้งานด้วย

ข้อควรระวัง ในการจองพื้นที่หน่วยความจำด้วย malloc หากไม่ใช้งานพื้นที่หน่วยความจำแล้ว ควรจะใช้ free เพื่อคืนพื้นที่หน่วยความจำกลับไปด้วย ไม่เช่นนั้นอาจจะทำให้พื้นที่หน่วยความจำหมด ไม่สามารถจองเพิ่มได้อีก

การใช้ malloc ทำได้โดยการกำหนดขนาด byte ที่ต้องการจะจองเป็น argument ใน function malloc และจะได้ค่า address ของพื้นที่ที่จอง ตอบกลับมา เช่น

int *pa;
pa = (int*) malloc(4); // malloc will allocate 4 bytes space for pa;

จากตัวอย่างจะเป็นการจองพื้นที่ขนาด 4 bytes ให้กับ Pointer pa จะมี int* เพื่อทำ implicit type conversion เพื่อให้รู้ว่าค่า ที่ return กลับมาจาก function malloc เป็น address ของ int pointer

ในคอมพิวเตอร์รุ่นใหม่ๆ ขนาดของตัวแปรอาจจะมากกว่าเดิม เช่น int เปลี่ยนจาก 2 bytes เป็น 4 bytes ดังนั้นเพื่อความถูกต้องในการกำหนดขนาดของข้อมูล เราจะใช้ function sizeof เพื่อหาขนาดของข้อมูลกัน เช่น pa = (int*) malloc(sizeof(int) * 5); ซึ่งจะเป็นการจองพื้นที่สำหรับ int 5 ตัว

การใช้ free ทำได้โดยระบุ address แรกของพื้นที่ซึ่งต้องการคืนพื้นที่มาเป็น argument ของ function เช่น

int *pa;
pa = (int*) malloc(sizeof(int) * 2);
free(pa);

การใช้ function gets() และ puts()

function ทั้งสองอยู่ภายใต้ lib stdio.h ดังนั้นต้อง include header file ก่อนใช้งานด้วย

function gets() สามารถใช้รับค่า string จากผู้ใช้มาได้เหมือนกับ function scanf() มีตัวอย่างการใช้ดังนี้

char string[20];
gets(string);
char string[20];
fgets(string,20,stdin);
char string[20];
scanf("%s",string);

function gets ปัจจุบันไม่แนะนำให้ใช้แล้ว เนื่องจากมีจุดอ่อนในการออกแบบซึ่งทำให้เกิด Buffer overflow ไปยังพื้นที่ข้อมูลอื่นๆได้ จึงไม่ปลอดภัย และถูกแนะนำให้เปลี่ยนไปใช้ function fgets() แทน ซึ่ง function fgets() มีการกำหนดจำนวนข้อมูลที่จะรับเข้ามา จึงมีความปลอดภัยมากกว่า

function puts() สามารถใช้แสดงค่า string ได้เหมือนกับ function printf()

char string[6]={'H','e','l','l','o','\0'};
puts(string);
char string[6]={'H','e','l','l','o','\0'};
printf("%s",string);

Functions

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

การทำงานของ Function

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

รูปแบบการประกาศ Function

return_data_type function_name(param1_data_type parameter1, param2_data_type parameter2, ..., paramN_data_type parameterN) {
  statement;
  return data_to_return //optional
}

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

เราสามารถที่จะสร้างฟังก์ชันที่จะทำงานไปจนจบฟังก์ชันโดยไม่ตอบกลับค่าใดๆไปได้ ดังนั้นภายในฟังก์ชันจะไม่มีบรรทัด return และชนิดของค่าที่ return จะแทนด้วย void

ตัวอย่างการประกาศ Function

int fac(int a) {
  int f = 1;
  for(; a>0 ; a--)
    f = f * a;
  return f;
}

การจะใช้งานฟังก์ชันได้ จะต้องประกาศฟังก์ชันไว้ก่อน ในบางภาษาจึงต้องประกาศฟังก์ชันไว้ก่อนส่วนที่เป็นการทำงานหลัก เช่น ก่อนส่วน function main() ซึ่งภาษาซีก็มีลักษณะนั้นเช่นกัน ดังนั้นหากมีรายละเอียดคำสั่งภายในฟังก์ชันเยอะ ก็จะเป็นความลำบากในการหาส่วนการทำงานหลัก และไล่การทำงานของโปรแกรม ทางแก้คือ การแยกส่วนประกาศ interface เชื่อมต่อในการเรียกใช้งานฟังก์ชัน (function prototype) ออกจากส่วนที่เป็นรายละเอียดของฟังก์ชัน (function implementation) ได้ ตัวอย่างเช่น

void main() {
  //do something
  int i = 1, x = 2, y = 3;
  void increment(int, float); // function prototype
  // do something
  increment(i, x); // function call
  // do something
  increment(i, y); // function call againg
  // do something
}

void increment(int m, int n) { // function implementation
  // do something
  m += n;
}

ซึ่งการทำเช่นนี้จะทำให้เราสามารถเขียนส่วนที่เป็นรายละเอียดการทำงานของฟังก์ชันอยู่บรรทัดหลังจาก function main() ได้ และสะดวกต่อการอ่าน code โปรแกรม

รูปแบบการส่งค่า argument ให้กับ Function

Pass by value

เป็นการส่งค่าแบบปกติ เป็นการ copy ค่าจาก argument ที่ให้มาในการเรียกฟังก์ชัน ไปใส่ในตัวแปร parameter ของฟังก์ชัน ตัวอย่างเช่น

void increment(int a, int b) {
  a += b; // a and b is not the same variables in main()
}

int main() {
  int a = 1, b = 2;
  increment(a, b);
  printf("%d\n", a); // a is 1
  return 0;
}

การเปลี่ยนแปลงค่าภายในฟังก์ชัน ไม่มีผลต่อตัวแปรของการทำงานหลัก เพราะเป็นคนละตัวแปรกัน เพียงแค่ชื่อตัวแปรอาจจะตรงกันและ copy ค่าไปให้ทำงานภายในฟังก์ชันเท่านั้น

Pass by pointer

เป็นการ copy ค่า address ของตัวแปรไปให้ ดังนั้นหากภายในฟังก์ชันมีการเรียกใช้ตำแหน่งข้อมูลจาก address นั้น จะเป็นการเรียกใช้โดยอ้อม และมีผลต่อค่าที่เก็บอยู่ในตำแหน่งข้อมูลนั้น ตัวอย่างเช่น

void increment(int *m, int n) {
  *m += n;
}

int main() {
  int a = 1, b = 2;
  increment(&a, b);
  // m will contains address of variable a
  // change to the value in the pointed address will affect to the variable
  printf("%d\n", a); // a is now 3
  return 0;
}

ประโยชน์อย่างหนึ่งที่ได้จากการใช้ Pass by pointer คือ การแก้ไขค่าโดยฟังก์ชัน เพราะฟังก์ชันสามารถ return ค่ากลับได้เพียงค่าเดียว การส่ง address ของข้อมูลไปให้อ้างอิง และแก้ไข จะทำให้ฟังก์ชันสามารถอัพเดตข้อมูลได้มากกว่าหนึ่งค่า แต่การใช้ Pass by pointer ก็มีจุดอ่อนด้านความปลอดภัย เพราะ การใช้ pointer ชี้ตำแหน่ง address และทำการแก้ไขข้อมูลอาจจะเป็นจุดอ่อนให้ Hacker สามารถอ้างอิงไปยัง address อื่นๆได้

ภายหลังปัญหานี้ได้ถูกแก้ในภาษาซีสมัยใหม่ เช่น C++ โดยมี Pass by reference มาทดแทน ซึ่งจะปลอดภัยกว่า เพราะไม่สามารถไปปรับเปลี่ยนค่า address ของข้อมูลโดยตรงได้

ตัวอย่างการใช้ Pass by pointer กับข้อมูลชนิด array สามารถรับมาและใช้ในรูปแบบ Array ได้ตามเดิม ตอนที่รับค่ามาใช้ มีเพียงมิติแรกเท่านั้นที่ไม่ต้องระบุขนาดของมิติ มิติอื่นๆต้องกำหนดขนาด เพื่อใช้ในการคำนวณขนาดมิติแรก

void max(int A[], int size) { // A[] will hold int* type
  int maxVal = A[0];
  for(int i=0; i<size; i++) {
    if(A[i] > maxVal)
      maxVal = A[i];
  }
  printf("%d\n", maxVal); // print 6
}

int main() {
  int A[5] = {1,2,3,6,5};
  int size = sizeof(A) / sizeof(A[0]);
  max(A, size); // send address of Array
  return 0;
}
void max(int A[][2], int row, int col) {
  // only first dimension doesn't need to define the size
  int maxVal = A[0][0];
  for(int i=0; i<row; i++) {
    for(int j=0; j<col; j++) {
      if(A[i][j] > maxVal)
        maxVal = A[i][j];
    }
  }
  printf("%d\n", maxVal); // print 5
}

int main() {
  int A[2][2] = { {1,2},
                  {5,4} };
  max(A, 2, 2); // send address of Array
  return 0;
}

Strings

เป็น Array 1 มิติของ char ตัวอักษรภายใน string สามารถเข้าถึงได้เช่นเดียวกับส่วนหนึ่งของ array หรือใช้ pointer ระบุตำแหน่ง char NULL character ('\0'; ASCII 0) ถูกใช้เพื่อบอกจุดสิ้นสุดของ string

การประกาศ string คือการสร้าง Array ของ character ขนาดตามข้อมูลที่จะเก็บ + 1

char string_name[data_size+1];

การรับค่ามาเก็บสามารถใช้ function scanf() ร่วมกับตัวแทนชนิดข้อมูล string (%s)

char my_string[20];
scanf("%s", my_string);
printf("%c\n", my_string[2]); // directly access char in string

เราสามารถประกาศข้อมูล string ได้โดยตรงเมื่อสร้าง Array

char my_string[20] = "Hello World";
printf("%s\n",my_string);

lib string.h เป็น library ที่ใช้จัดการงานเกี่ยวกับ string function ที่น่าสนใจดังนี้ strcpy - ใช้ copy ข้อมูลภายใน string จาก source ไป destination strlen - บอกจำนวนตัวอักษรภายใน string (ตั้งแต่ต้นไปจนถึง NULL character) strcmp - ใช้ในการเปรียบเทียบว่า string ทั้งสองเหมือนกันหรือไม่ การทำงานเบื้องหลังจากเป็นการนำ ASCII character มาลบกันทีละตัว หาก string ทั้งสองเหมือนกันจะได้ค่า return เป็น 0

lib ctype.h เป็น library ที่ใช้จัดการงานเกี่ยวกับ character function ที่น่าสนใจดังนี้ toupper - จะ return ค่าอักษรตัวพิมพ์ใหญ่ของตัวอักษรที่ pass เป็น argument ไป tolower - จะ return ค่าอักษรตัวพิมพ์เล็กของตัวอักษรที่ pass เป็น argument ไป ดังนั้นโดยปกติหากต้องการเปลี่ยนทั้ง string เป็นตัวพิมพ์ใหญ่หรือพิมพ์เล็กทั้งหมด จะใช้ function เหล่านี้คู่กับ loop

Structure & Union

Structure

Structure คือชนิดข้อมูลที่นิยามขึ้นภายในโปรแกรม จะประกอบด้วยชื่อชนิดข้อมูลที่จะสร้าง และโครงสร้างชนิดข้อมูลของสมาชิกภายใน

การประกาศ Structure

struct struct_name {
  member1_type member1;
  member2_type member2;
  ...
  memberN_type memberN;
};

ตัวอย่างเช่น

struct student {
  char firstname[15];
  char lastname[20];
  int age;
};

จากตัวอย่าง จะเกิดชนิดข้อมูลชนิดใหม่ขึ้นชื่อ "struct student" ตัวอย่างการเรียกใช้ เช่น

struct student my_student;

การใช้แบบนี้จะไม่สะดวก โดยปกติจึงจะนำ typedef มาช่วยแก้ปัญหานี้ เช่น

typedef struct student student;
student my_student;

นอกจากนี้ เรายังสามารถสร้าง Structure ซ้อนกันได้ ตัวอย่างเช่น

struct date {
  int year, month, day;
};
typedef struct date date;
struct song {
  char title[64];
  char artist[32];
  char composer[32];
  unsigned int duration;
  date published;
};
typedef struct song song;

การเข้าถึงข้อมูลภายใน structure

กรณีตัวแปรธรรมดา เข้าถึงได้ด้วย dot operator (.) เช่น

// don't forget to include <string.h>
song first_song;
strcpy(first_song.title, "Hello World");
strcpy(first_song.artist, "Foo Bar");
first_song.duration = 120;
first_song.published.year = 1998;

กรณีตัวแปรแบบ Pointer

song *pfirst_song = &first_song;
(*pfirst_song).published.month = 11;

การเข้าถึงด้วย dot operator อาจสร้างความซับซ้อน ผิดพลาดได้ง่าย และไม่สะดวกต่อการใช้งาน จึงควรใช้ arrow operator (->) แทน เช่น

pfirst_song->published.day = 14;

Union

จะแตกต่างจาก Structure ชนิดข้อมูลแบบ Structure จะมีขนาดเท่ากับผลรวมของขนาดสมาชิกทุกตัว และสมาชิกทุกตัวจะมี address ของตนเอง แต่ Union จะมีขนาดเท่ากับขนาดของสมาชิกที่ใหญ่ที่สุด และสมาชิกทุกตัวจะมี address เดียวกัน

ปกติ union จะถูกใช้ทำหน้าที่เป็น buffer ของข้อมูล

การประกาศ Union

union union_name {
  member1_type member1;
  member2_type member2;
  ...
  memberN_type memberN;
}

ตัวอย่างเช่น

union buffer {
  int i;
  float f;
  char c[10];
};
typedef union buffer buffer;
buffer my_buffer;

Files

ในภาษาซี การจัดการเกี่ยวกับไฟล์ไม่ว่าจะเป็นการเขียน หรือการอ่านจากไฟล์ จะดำเนินการผ่านสิ่งที่เรียกว่า data stream stream ในภาษาซีมีสองแบบ คือ text (อักษร) กับ binary (ข้อมูลที่เป็น bit 0,1)

การระบุตำแหน่งของข้อมูลภายในไฟล์ จะดำเนินการผ่าน Pointer ของข้อมูลชนิด FILE

FILE *file_name;

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

การเปิดไฟล์

มี Pattern ดังนี้

file_pointer = fopen(file_name, access_mode);

ตัวอย่างการใช้งาน

FILE *fp;
fp = fopen("sample.txt","r");

access mode

ความหมาย

r

เปิดไฟล์เพื่ออ่านอย่างเดียว โดยมี cursor อยู่ที่หัวไฟล์

w

สร้างไฟล์เพื่อเขียน หากไฟล์มีอยู่แล้วจะเกิดการเขียนทับ

a

เปิดเพื่อเพิ่มข้อมูลที่ ท้ายไฟล์ (end-of-file) หากไฟล์ไม่เคยมีอยู่จะสร้างและเขียนลงไป

r+

เปิดไฟล์เพื่ออ่านและเขียน โดยมี cursor อยู่ที่หัวไฟล์

w+

สร้างไฟล์เพื่ออ่านและเขียน โดยมี cursor อยู่ที่หัวไฟล์ หากไฟล์มีอยู่แล้วจะถูกเขียนทับ

a+

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

การเปิดไฟล์ด้วย function fopen() หากเปิดไฟล์ไม่สำเร็จ จะได้ค่าตอบกลับมาเป็น NULL

การปิดไฟล์

จะใช้ function fclose() โดยมี argument เป็น Pointer ของ FILE เช่น

fclose(fp);

ข้อมูลที่มีการสั่งเขียนและยังคงค้างอยู่ใน Buffer จะถูก flush (เขียน) ลงไฟล์ แล้วจึงปิดไฟล์ หน่วยความจำสำหรับ input buffer และ output buffer จะถูกคืนให้กับระบบ

การปิดไฟล์ด้วย function fclose() หากปิดไฟล์สำเร็จ จะได้ค่าตอบกลับเป็น 0 หากปิดไฟล์ไม่สำเร็จจะได้ค่าตอบกลับเป็น EOF

การอ่านและเขียนไฟล์มี 3 แบบ

  • ดำเนินการทีละตัวอักษร

  • ดำเนินการทีละ string

  • ดำเนินการทีละ Block ของข้อมูล

ฟังก์ชันอ่านทีละตัวอักษร

fgetc(file_pointer);
getc(file_pointer);

จะ return เป็นเลข ASCII ของอักษรที่ถูกอ่าน หากมี error จะ return เป็น EOF

ฟังก์ชันเขียนทีละตัวอักษร

fputc(charater, file_pointer);
putc(character, file_pointer);

จะ return เป็นเลข ASCII ของอักษรที่ถูกเขียน หากมี error จะ return เป็น EOF

ตัวอย่างการใช้งาน

void readFile(FILE *fp) {
  int c;
  rewind(fp); //set fp to the head of file
  while( ( c = fgetc(fp) ) != EOF) {
    printf("%c", c);
  }
}

void writeFile(FILE *fp, char *c) {
  rewind(fp);
  while( *c != '\0' ) {
    if( fputc(*c, fp) == EOF ) {
      break;
    }
    c++;
  }
}

int main() {
	FILE *fp;
	fp = fopen("sample.txt", "w+");
	char sentence[20] = "Hello World\n";
	writeFile(fp, sentence);
	readFile(fp);
	fclose(fp);
    return 0;
}

ฟังก์ชันอ่านทีละ string

fgets(string_pointer, string_length, file_pointer);

ฟังก์ชันจะอ่านข้อมูลจากไฟล์ จนถึง string_length - 1 หรือขึ้นบรรทัดใหม่ และจะเติม NULL character ให้ที่ท้ายข้อมูลที่อ่าน กรณีที่อ่านสำเร็จจะมี return string กรณีอ่านจนจบไฟล์ (End-of-File; EOF) จะ return ค่า NULL

ฟังก์ชันเขียนทีละ string

fputs(string_pointer, file_pointer);

ฟังก์ชันจะอ่าน NULL character ไปด้วย แต่จะไม่เขียน NULL character ลงไฟล์ ถ้าเขียนสำเร็จจะ return non-negative value แต่ถ้า error จะ return EOF

ตัวอย่างการใช้งาน

#define MAX_LINE 256

void readFile(FILE *fp) {
  char s[MAX_LINE] = "";
  rewind(fp);
  while( fgets(s, MAX_LINE, fp) != '\0') {
    printf("%s", s);
  }
}

void writeFile(FILE *fp, char *c) {
  rewind(fp);
  fputs(c, fp);
}

int main() {
	FILE *fp;
	fp = fopen("sample.txt", "w+");
	char sentence[20] = "Hello World\n";
	writeFile(fp, sentence);
	readFile(fp);
	fclose(fp);
    return 0;
}

ฟังก์ชันอ่านทีละ block

fread(buffer_pointer, size, N_block, file_pointer);

ฟังก์ชันจะอ่านข้อมูลจากไฟล์ โดยจำนวนที่อ่านขึ้นมาในแต่ละรอบมีขนาดเท่ากับที่ระบุใน size และจะอ่านทั้งหมดเท่ากับ N_block รอบ หากอ่านสำเร็จ จะ return จำนวนรอบที่อ่านสำเร็จ ซึ่งจะเท่ากับค่า size หาก error หรืออ่านไปจนสุดไฟล์ จะ return ค่าที่ไม่ตรงกับ size (อาจจะเป็น 0 ได้)

ฟังก์ชันเขียนทีละ block

fwrite(buffer_pointer, size, N_block, file_pointer);

ฟังก์ชันจะเขียนข้อมูลลงไฟล์ โดยจำนวนที่เขียนในแต่ละรอบมีขนาดเท่ากับที่ระบุใน size และจะเขียนทั้งหมดเท่ากับ N_block รอบ หากเขียนสำเร็จ จะ return จำนวนรอบที่เขียนสำเร็จ ซึ่งจะเท่ากับค่า size หากจำนวนที่ return ไม่ตรงกับที่ระบุใน size แสดงว่าอาจจะเกิด error

ตัวอย่างการใช้งาน

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct student {
  int id;
  char name[20];
} student;

int readFile(FILE *fp, student *data) {
  rewind(fp);
  if((fread(data, sizeof(student), 1, fp)) == 0)
    return 0;
  else
    return 1;
}

int writeFile(FILE *fp, student *data) {
  rewind(fp);
  if((fwrite(data, sizeof(student), 1, fp)) == 0)
    return 0;
  else
    return 1;
}

int main() {
	FILE *fp;
	fp = fopen("sample.txt", "w+");
	student jame, *bob;
	bob = (student*) malloc(sizeof(student));
	int status;
	jame.id = 1;
	strcpy(jame.name, "Jame");
	status = writeFile(fp, &jame);
	status = readFile(fp, bob);
	printf("Bob id is %d.\n", bob->id);
	printf("Bob name is %s.\n", bob->name);
	fclose(fp);
    return 0;
}
PreviousBasic Computer Language (LV.1)NextPython3 (LV.1)

Last updated 3 years ago

Was this helpful?

Token & Whitespace
sign int
simple variable VS array variable
Array and Indices
Array for string
Memory location for multi-dimension array
Program and Function Flow
Structure and Union