ดาวน์โหลดงานนำเสนอ
งานนำเสนอกำลังจะดาวน์โหลด โปรดรอ
1
บทที่ 5 โปรแกรมย่อย
2
โปรแกรมย่อย 1. การเขียนโปรแกรมแบบโมดูล 2. โปรแกรมย่อยในภาษาปาสคาล
1. การเขียนโปรแกรมแบบโมดูล 2. โปรแกรมย่อยในภาษาปาสคาล 3. Procedure 4. การส่งผ่าน parameter - Value parameter - Variable parameter 5. Function
3
1. การเขียนโปรแกรมแบบโมดูล
ปัญหาของการเขียนชุดคำสั่งทั้งหมดอยู่ในส่วนโปรแกรมหลัก(main) แก้ไขและปรับปรุงยากเมื่อโปรแกรมมีขนาดใหญ่ ชุดคำสั่งที่ทำงานเหมือนกันไม่สามารถนำมาใช้ซ้ำได้ แก้ปัญหาด้วยการเขียนโปรแกรมแบบ Module แยกส่วนการทำงานออกเป็นส่วนย่อยหรือโปรแกรมย่อย (subprogram) หรือที่เรียกว่า module
4
ประเภทของโปรแกรมย่อย
1. การเขียนโปรแกรมแบบโมดูล ประเภทของโปรแกรมย่อย Procedure เป็นชุดคำสั่งย่อยที่มีหน้าที่เฉพาะอย่างใดอย่างหนึ่ง สามารถมีการรับส่งค่าข้อมูล(parameter)ระหว่าง procedure กับโปรแกรมส่วนอื่นๆที่เรียกใช้ procedure หรือไม่ก็ได้ จะไม่มีการส่งค่าผลลัพธ์ของการทำงานกลับไปยังคำสั่งที่เรียกใช้งาน procedure ผ่านชื่อ procedure Function เหมือน procedure ต่างกันที่ฟังก์ชันต้องมีการส่งค่าผลลัพธ์ของการทำงานกลับไปยังคำสั่งที่เรียกใช้งานฟังก์ชันผ่านชื่อฟังก์ชันด้วย
5
โปรแกรมย่อยในภาษาปาสคาล
โปรแกรมย่อย (subprogram) คือส่วนหนึ่งของโปรแกรมมีหน้าที่เฉพาะ (บางครั้งเรียกว่าโมดูล) โปรแกรมย่อยวางหลังส่วน Heading Header ของโปรแกรมหลัก(main program) ก่อน BEGIN ของโปรแกรมหลัก โครงสร้างของโปรแกรมย่อยประกอบด้วยส่วนหัว ส่วนประกาศ และส่วนคำสั่ง เช่นเดียวกับโปรแกรมหลัก แตกต่างที่ ส่วนหัวขึ้นต้นด้วย PROCEDURE หรือ FUNCTION จบด้วย END; แทน END. โปรแกรมย่อยทำงานเองไม่ได้ ต้องถูกเรียกโดยโปรแกรมอื่น ๆ ที่เรียกใช้งานโปรแกรมย่อยนั้น
6
โปรแกรมย่อยในภาษาปาสคาล
ขั้นตอน ระบุ “ปัญหาย่อย” ที่ต้องการแก้ในโปรแกรม แก้ปัญหาย่อย โดยการเขียนชุดคำสั่งเพื่อแก้ไขปัญหาย่อยเพียงครั้งเดียว แล้วกำหนดชื่อให้กับชุดคำสั่งนั้น และให้กำหนดประเภทชุดคำสั่งนั้นด้วยว่าเป็น “procedure” หรือ “function” เมื่อต้องการแก้ปัญหาย่อย สามารถทำได้โดยเรียกชื่อ “procedure” หรือ “function” เพื่อนำชุดคำสั่งมาใช้งานและในกรณีพบปัญหาย่อยที่ซ้ำกัน ให้เรียกใช้งานอีกครั้ง โดยไม่ต้องเขียนชุดคำสั่งใหม่
7
โปรแกรมย่อยในภาษาปาสคาล
PROGRAM Ex1; USES wincrt; BEGIN writeln(‘****’); writeln(‘* *’); END. 1. ระบุ “ปัญหาย่อย” PROGRAM ModuleDesignEx1; USES wincrt; PROCEDURE Box4; BEGIN writeln(‘****’); writeln(‘* *’); END; Box4; END. 2. แก้ปัญหาย่อย โดยการเขียนชุดคำสั่งเพียงครั้งเดียว และกำหนดชื่อ procedure (procedure) ให้กับชุดคำสั่งนี้ว่า Box4 3. ที่ main program สามารถเรียกชื่อ procedure เพื่อนำชุดคำสั่งมาใช้งานได้หลายครั้ง
8
โปรแกรมย่อยในภาษาปาสคาล
รับค่า parameter เข้าโปรแกรมย่อย โปรแกรมย่อย แสดงผล การติดต่อเพื่อส่งผ่านค่าข้อมูล (อาจเป็นตัวอักษร ตัวเลข ตัวแปรหรือ นิพจน์) ระหว่างโปรแกรมย่อยและโปรแกรมอื่น ๆ ที่เรียกใช้โปรแกรมย่อยนั้นทำได้โดยอาศัยพารามิเตอร์ (parameter) Formal parameter คือพารามิเตอร์ที่ประกาศในโปรแกรมย่อย กรณีมีหลาย formal parameter ให้คั่นด้วย ; (semicolon) Actual parameter คือพารามิเตอร์ในคำสั่งที่เรียกใช้โปรแกรมย่อย กรณีมีหลาย actual parameter ให้คั่นด้วย , (comma)
9
โปรแกรมย่อยในภาษาปาสคาล
การเขียนโปรแกรมย่อยที่มีการส่งผ่านพารามิเตอร์ต้องเพิ่มสิ่งต่อไปนี้ ในส่วนหัวของโปรแกรมย่อยต้องเพิ่มการกำหนดชื่อและชนิดข้อมูลของตัวแปรที่ทำหน้าที่เป็น formal parameter ดังตัวอย่าง PROCEDURE MyProc(x:real; n:integer); คำสั่งในโปรแกรมที่เรียกใช้โปรแกรมย่อยต้องส่งผ่านข้อมูลผ่านชื่อตัวแปรที่ทำหน้าที่เป็น actual parameter ดังตัวอย่าง MyProc(a,b); Actual parameter สามารถใช้เป็นตัวเลข หรือ นิพจน์ ก็ได้ เช่น MyProc(4.5,10); หรือ MyProc(0.55,a+b);
10
Procedure : กรณีไม่มี parameter
ตัวอย่างที่ 1 PROGRAM ชื่อโปรแกรมหลัก; USES wincrt; {รูปแบบ กรณีไม่มี parameter} PROCEDURE ชื่อ; VAR ส่วนประกาศตัวแปรของprocedure BEGIN คำสั่งต่าง ๆ ใน procedure END; VAR ส่วนประกาศตัวแปรต่างๆของ main คำสั่งต่างๆ ของโปรแกรมหลัก END. PROGRAM ModuleDesignEx1; USES wincrt; PROCEDURE Box4; BEGIN writeln(‘****’); writeln(‘* *’); END; Box4; END. Block ของ main program (มีคำสั่งเรียกใช้ procedure) Block ของ procedure
11
Procedure : กรณีมี parameter
เข้าโปรแกรมย่อย Procedure แสดงผล รูปแบบ (กรณีมี parameter) PROCEDURE ชื่อ(formal parameters); ชื่อ Formal parameters PROCEDURE MyProc(var x:real; n:integer); VAR n,m:integer; z:real; BEGIN คำสั่งต่างๆ ใน procedure… END; Block ของ procedure ส่วนประกาศตัวแปรของprocedure ส่วน statement ของ procedure ขึ้นด้วย begin ลงท้ายด้วย end;
12
{ This subprogram has one formal parameter}
ตัวอย่างที่ 2 : รับค่า parameter จาก main ถ้าเป็น 1 ให้พิมพ์ “Press any key to continue.” ถ้าไม่ใช่ 1 ให้พิมพ์ข้อความ “Program terminate. Goodbye” รับค่า parameter เป็นเลขจำนวนเต็ม 1 ตัว procedure ชื่อ print_msg พิมพ์ข้อความ PROGRAM Ex2; USES wincrt; { This subprogram has one formal parameter} procedure print_msg(input : integer); begin if (input = 1) then writeln(‘Press Any Key to Continue.’) else writeln(‘Program Terminate. Good Bye.’); end; var n : integer; BEGIN write(‘Input n : ’); readln(n); print_msg(n); {Calling the procedure with one actual parameter } END. Header ของ main program Block ของ procedure Block ของ main program (มีคำสั่งเรียกใช้ procedure) ตัวแปรของ main program
13
ตัวอย่างผลรันที่ 1 ของโปรแกรม Input n : 10
ตัวอย่างที่ 2 : รับค่า parameter จาก main ถ้าเป็น 1 ให้พิมพ์ “Press any key to continue.” ถ้าไม่ใช่ 1 ให้พิมพ์ข้อความ “Program terminate. Goodbye” PROGRAM Ex2; USES wincrt; { This subprogram has one formal parameter} procedure print_msg(input : integer); begin if (input = 1) then writeln(‘Press Any Key to Continue.’) else writeln(‘Program Terminate. Good Bye.’); end; var n : integer; BEGIN write(‘Input n : ’); readln(n); print_msg(n); END. ตัวอย่างผลรันที่ 1 ของโปรแกรม Input n : 10 Program Terminate. Good Bye. - จากคำสั่ง readln(n) ใน main มีการรับค่า actual parameter n เป็น 10 - และการทำคำสั่ง print_msg(n); จะส่งค่า 10 นี้ให้กับ formal parameter input จึงทำให้เงื่อนไข if เป็นเท็จ - จากคำสั่ง readln(n) ใน main มีการรับค่า actual parameter n เป็น 1 - และการทำคำสั่ง print_msg(n); จะส่งค่า 1 นี้ให้กับ formal parameter input จึงทำให้เงื่อนไข if เป็นจริง ตัวอย่างผลรันที่ 2 ของโปรแกรม Input n : 1 Press Any Key to Continue.
14
procedure EllipseArea(a,b :real); {two formal parameters }
ตัวอย่างที่ 3 : รับค่า parameter รัศมีที่ยาวที่สุด และรัศมีที่สั้นที่สุดของวงรีจาก main เพื่อคำนวณและแสดงค่าพื้นที่ของวงรีใน procedure พื้นที่วงรี = * a * b - a แทนค่ารัศมีที่สั้นที่สุด - b แทนค่ารัศมีที่ยาวที่สุด a b program Ex3; uses wincrt; procedure EllipseArea(a,b :real); {two formal parameters } const pi = ; var area : real; begin area := pi*a*b; writeln(‘a= ’,a:5:2, ‘ b= ’,b:5:2,‘ area= ’,area:5:2); end; var x, y : real; x := 1.5; y := 10.0; EllipseArea(x,y); {First Calling} EllipseArea(2.0,x+y); {Second Calling} end. Header ของ main program ตัวแปรและค่าคงที่ของ Procedure Block ของ procedure ตัวแปรของ main program two actual parameters Block ของ main program
15
ตัวอย่างผลรันของโปรแกรมนี้คือ a= 1.50 b= 10.00 area= 47.12
ตัวอย่างที่ 3 : รับค่า parameter รัศมีที่ยาวที่สุด และรัศมีที่สั้นที่สุดของวงรีจาก main เพื่อคำนวณและแสดงค่าพื้นที่ของวงรีใน procedure Two formal parameters - a แทนค่ารัศมีที่สั้นที่สุด - b แทนค่ารัศมีที่ยาวที่สุด a b ในการทำงานของ First Calling เนื่องจากการทำคำสั่ง EllipseArea(x,y); เป็นการส่งค่าของ actual parameter x และ y (1.5 และ10.0) ให้ formal parameter a และ b ตามลำดับ ดังนั้น การคำนวณพื้นที่วงรี(area) := *1.5*10.0 จะได้ค่า area เท่ากับ จึงทำให้ได้ผลรันดังตัวอย่าง program Ex3; uses wincrt; procedure EllipseArea(a , b :real); const pi = ; var area : real; begin area := pi*a*b; writeln(‘a= ’,a:5:2, ‘ b= ’,b:5:2,‘ area= ’,area:5:2); end; var x, y : real; x := 1.5; y := 10.0; EllipseArea(x,y); {First Calling} EllipseArea(2.0 , x+y);{Second Calling} end. ตัวอย่างผลรันของโปรแกรมนี้คือ a= b= area= 47.12 a= b= area= 72.26
16
การส่งผ่าน parameter การส่งผ่านพารามิเตอร์ มี 2 แบบ คือ
การส่งผ่านพารามิเตอร์ มี 2 แบบ คือ การส่งผ่านพารามิเตอร์แบบส่งค่า (Pass by value) เป็นการส่งผ่านค่า (value) ของ actual parameter ให้แก่ formal parameter หากมีการเปลี่ยนแปลงค่าของ formal parameter ในโปรแกรมย่อย จะไม่มีผลต่อค่า actual parameter ค่าของ actual parameter จะเป็นค่าของตัวแปร ค่านิพจน์ หรือค่าคงที่โดยตรงก็ได้ การส่งผ่านพารามิเตอร์แบบส่งตัวแปร (Pass by variable) เป็นการส่งผ่านตำแหน่งที่อยู่ในหน่วยความจำ(address) ของ actual parameter ให้แก่ formal parameter หากมีการเปลี่ยนแปลงค่าของ formal parameter ในโปรแกรมย่อย จะมีผลต่อค่า actual parameter เปลี่ยนแปลงด้วย ค่าของ actual parameter จะเป็นค่าของตัวแปรเท่านั้น
17
การส่งผ่าน parameter Pass by value รูปแบบการเขียน procedure
procedure ชื่อ procedure ( ชื่อพารามิเตอร์ : ชนิดข้อมูล; …); เช่น procedure EllipseArea(a,b:real); 2. Pass by Variable รูปแบบการเขียน procedure ต้องมีคำว่า var นำหน้าตัวแปรที่จะ pass by variable เสมอ ดังนี้ procedure ชื่อ procedure (var ชื่อพารามิเตอร์ :ชนิดข้อมูล; …); procedure Swap(var x,y:real);
18
การเปลี่ยนแปลงค่าของ formal parameter ไม่มีผลต่อ actual parameter
ตัวอย่าง pass by value การส่งผ่านข้อมูลแบบ pass by value จะมีการส่งเฉพาะค่า (คัดสำเนา) จาก actual parameter (ของตัวแปร a) ให้ formal parameter (ตัวแปร x)ใน Procedure program Ex41; uses wincrt; procedure one(x : integer); begin x := x+1; writeln(‘x =’ , x); end; var a : integer; a := 10 ; writeln(‘a =’ , a); one(a) ; end. ค่า actual parameter a ของ main ก่อนเรียกใช้ procedure one ผลลัพธ์ a = 10 x = 11 ค่า a ของ main หลังเรียกใช้ procedure one การเปลี่ยนแปลงค่าของ formal parameter ไม่มีผลต่อ actual parameter
19
ตัวอย่าง pass by variable
การส่งผ่าน parameter ตัวอย่าง pass by variable การส่งผ่านข้อมูลแบบ pass by variable จะมีผลให้actual parameter (ของตัวแปร a) และ formal parameter (ตัวแปร x)ใน Procedure เสมือนเป็นตัวแปรเดียวกันชั่วคราว เนื่องจากอ้างอิงที่อยู่ในหน่วยความจำตำแหน่งเดียวกัน program Ex42; uses wincrt; procedure two(var x : integer); begin x := x+1; writeln(‘x =’ , x); end; var a : integer; a := 10 ; writeln(‘a =’ , a); two(a) ; end. ค่า actual parameter a ของ main ก่อนเรียกใช้ procedure two ผลลัพธ์ a = 10 x = 11 a = 11 ค่า a ของ main หลังเรียกใช้ procedure two การเปลี่ยนแปลงค่าของ formal parameter จะทำให้ค่า actual parameter เปลี่ยนแปลงด้วย
20
การส่งผ่าน parameter จะเลือกใช้การส่งผ่าน parameters แบบไหนให้พิจารณาดังนี้ ถ้า procedure ต้องการเฉพาะค่าข้อมูลที่ส่งมาให้เพื่อมาใช้งานใน procedure เพียงอย่างเดียว ให้ใช้การส่งผ่านแบบ pass by value 2. ถ้ามี parameter ที่ procedure ต้องการส่งผลลัพธ์การทำงานกลับไปยังโปรแกรมที่เรียกใช้ procedure ผ่านตัวแปรที่เป็นพารามิเตอร์นั้น ให้ใช้การส่งผ่านแบบ pass by variable 3. ถ้ามี parameter ที่ procedure ต้องการทั้งค่าข้อมูลของตัวแปรที่ส่งมาให้ และต้องการส่งผลลัพธ์กลับผ่านตัวแปรนั้นด้วย
21
ตัวอย่างที่ 5 : รับค่า parameter ความยาวฐานและความสูงของสามเหลี่ยมจาก main เพื่อคำนวณและแสดงค่าพื้นที่ของสามเหลี่ยมใน procedure เลือกการส่งผ่านแบบ pass by value เพราะต้องการส่งเฉพาะ “ค่า” ของตัวแปรความยาวฐาน(base) และความสูง(high) ให้ procedure คำนวณค่าพื้นที่สามเหลี่ยม program Ex51; uses wincrt; procedure TriangleArea(h,b :real); var area:real; begin area := 0.5*b*h; writeln(‘base= ’,b:5:2, ‘ High= ’,h:5:2,‘ area= ’,area:5:2); end; var high, base : real; write(‘input high : ’ ); readln(high); write(‘input base : ’ ); readln(base); TriangleArea(high,base); end.
22
ตัวอย่างผลรันที่ 1 ของโปรแกรม Input high : 1.5 Input base : 10
ตัวอย่างที่ 5 : รับค่า parameter ความยาวฐานและความสูงของสามเหลี่ยมจาก main เพื่อคำนวณและแสดงค่าพื้นที่ของสามเหลี่ยมใน procedure ตัวอย่างผลรันที่ 1 ของโปรแกรม Input high : 1.5 Input base : 10 base= high= area= 7.50 program Ex51; uses wincrt; procedure TriangleArea(h,b :real); var area:real; begin area := 0.5*b*h; writeln(‘base= ’,b:5:2, ‘ high= ’,h:5:2,‘ area= ’,area:5:2); end; var high, base : real; write(‘input high : ’ ); readln(high); write(‘input base : ’ ); readln(base); TriangleArea(high,base); end. ตัวอย่างผลรันที่ 2 ของโปรแกรม Input high : 20 Input base : .5 base= high= area= 5.00
23
ตัวอย่างที่ 5 (version 2): รับค่า parameter ความยาวฐานและความสูงของสามเหลี่ยมจาก main เพื่อคำนวณพื้นที่ของสามเหลี่ยมใน procedure แต่ต้องการแสดงค่าพื้นที่สามเหลี่ยมที่ main program Ex52; uses wincrt; procedure TriangleArea(h,b :real; var area : real); begin area := 0.5*b*h; end; var high, base, area : real; write(‘input high : ’ ); readln(high); write(‘input base : ’ ); readln(base); TriangleArea(high,base,area); writeln(‘base= ’,base:5:2, ‘ High= ’,high:5:2,‘ area= ’,area:5:2); end. เฉพาะตัวแปร area ที่เลือกการส่งผ่านแบบ pass by variable เพราะต้องการส่งผลลัพธ์ค่าพื้นที่กลับไปยัง main เพื่อพิมพ์ค่าพื้นที่
24
ตัวอย่างผลรัน ของโปรแกรม Input high : 1.5 Input base10 : 10
ตัวอย่างที่ 5 (version 2) : รับค่า parameter ความยาวฐานและความสูงของสามเหลี่ยมจาก main เพื่อคำนวณพื้นที่ของสามเหลี่ยมใน procedure แต่ต้องการแสดงค่าพื้นที่สามเหลี่ยมที่ main program Ex52; uses wincrt; procedure TriangleArea(h,b :real; var area : real); begin area := 0.5*b*h; end; var high, base, area : real; write(‘input high : ’ ); readln(high); write(‘input base : ’ ); readln(base); TriangleArea(high,base,area); writeln(‘base= ’,base:5:2, ‘ High= ’,high:5:2,‘ area= ’,area:5:2); end. ตัวอย่างผลรัน ของโปรแกรม Input high : 1.5 Input base10 : 10 base= high= area= 7.50
25
ตัวอย่างที่ 6 : ให้เขียน procedure swap สำหรับสลับค่าข้อมูลระหว่างตัวแปร x และ y
Pass by value program Ex61; uses wincrt; var x,y : integer; procedure Swap(a , b:integer); var temp:integer; begin temp := a; a := b; b := temp; end; x := 2; y := 3; Swap(x , y); writeln(‘x =’ , x ,‘ y =’ , y); end. Pass by variable program Ex62; uses wincrt; var x,y : integer; procedure Swap(var a,b : integer); var temp : integer; begin temp := a; a := b; b := temp; end; x := 2; y := 3; Swap(x , y); writeln(‘x =’ , x ,‘ y =’ , y); end. จากโปรแกรม Ex61 และ Ex62 ให้ผลลัพธ์ต่างกันหรือไม่เพราะอะไร ?
26
ข้อควรระวัง จำนวนและลำดับของ actual parameter ต้องตรงกับของ formal parameter จากโปรแกรมย่อย procedure EllipseArea(a,b :real); ของตัวอย่าง 3 ใน slide หน้า 14 ถ้าก่อนการเรียกใช้งาน procedure มีการกำหนด x := 2; y := 0.5; การเรียกใช้งาน procedure EllipseArea จะให้ผลลัพธ์เป็นดังนี้ กรณีเรียกใช้ด้วยคำสั่ง EllipseArea(x,y); ผลลัพธ์คือ a= b= area= กรณีเรียกใช้ด้วยคำสั่ง EllipseArea(y,x); ผลลัพธ์คือ a= b= area=
27
ข้อควรระวัง ชนิดตัวแปรของทั้ง actual และ formal parameter ต้องเหมือนกัน จากโปรแกรมย่อย procedure EllipseArea(a,b :real); ในตัวอย่างที่ 3 หน้า 14 การเรียกใช้งาน EllipseArea(x,y); จะทำได้เมื่อ actual parameter x และ y มีการประกาศชนิดตัวแปรเป็น real หรือ integer ก็ได้ ทั้งนี้เพราะ integer และ real เป็นชนิดตัวเลขทั้งคู่ และ real เป็นชนิดตัวเลขที่มีขอบเขตข้อมูลใหญ่กว่า integer ซึ่งการเรียกใช้งาน EllipseArea(2,0.5); ก็สามารถทำได้เช่นกัน แต่ถ้าเขียนโปรแกรมย่อยเป็น procedure EllipseArea(a,b:integer); การเรียกใช้โปรแกรมย่อยด้วยคำสั่ง EllipseArea(x,y); จะต้องมีการประกาศชนิดตัวแปรของ actual parameter x และ y เป็นชนิด integer เท่านั้น และการเรียกใช้งาน EllipseArea(2,0.5); ก็ไม่สามารถทำได้ด้วย
28
สรุปข้อดีของการแยกงานเป็นโปรแกรมย่อย
ทำให้โปรแกรมขนาดใหญ่ที่มีชุดคำสั่งมีความยาวมาก เข้าใจได้ง่ายขึ้น ลดความซ้ำซ้อนในการเขียนโปรแกรมในส่วนที่ทำงานอย่างเดียวกัน ถ้านำโปรแกรมส่วนที่ต้องใช้ซ้ำๆ มาทำเป็นโปรแกรมย่อย ทำให้ โปรแกรมมีขนาดเล็ก และเข้าใจง่าย นำโปรแกรมที่สร้างไปใช้งานในโปรแกรมอื่นได้ ถ้าในโปรแกรมนั้นต้องการฟังก์ชันในการทำงานที่เหมือนกัน
29
แบบฝึกหัด 1. จงหาผลลัพธ์ของโปรแกรม Drawing program Drawing;
uses wincrt; procedure DrawRec(w,h:integer); var i,j:integer; begin for i :=1 to h do for j :=1 to w do write(‘*’); writeln; end; var n,m:integer; n := 4; m := 2; DrawRec(n,m); DrawRec(5,5); DrawRec(m, m*n); end. 1. จงหาผลลัพธ์ของโปรแกรม Drawing
30
แบบฝึกหัด 2. จงเขียน procedure เพื่อคำนวณและแสดงค่าสินค้าที่ลูกค้าต้องโดยให้คิดส่วนลดตามเงื่อนไขต่อไปนี้ 12 % สำหรับผู้ซื้อของราคาตั้งแต่ 10,000 บาทขึ้นไป 10 % ถ้ายอดซื้อตั้งแต่ 5,000 บาท แต่ต่ำกว่า 10,000 บาท 7% ถ้ายอดซื้อต่ำกว่า 5,000 บาท หมายเหตุ กำหนดให้ procedure มีการรับค่าจำนวนสินค้า และราคาต่อหน่วยจาก main program
งานนำเสนอที่คล้ายกัน
© 2024 SlidePlayer.in.th Inc.
All rights reserved.