วันพุธที่ 21 สิงหาคม พ.ศ. 2556

ใบความรู้ที่ 4.1 โครงสร้าง while ลูป

ใบความรู้ที่ 4.1
โครงสร้าง while ลูป
          โครงสร้าง while ลูปเป็นโครงสร้างแบบง่ายที่สุดที่สามารถนำมาใช้เขียนโปรแกรมเพื่อวนทำ
คำสั่ง (หรือกลุ่มของคำสั่ง) ซ้ำหลาย ๆ รอบ รูปแบบ การใช้งาน while ลูปเป็นดังนี้

while (condition)
   statement;

         เช่นเดียวกับโครงสร้าง if เราสามารถกำหนดการวนซ้ำให้กับกลุ่มของคำสั่งได้โดยใช้วงเล็บปีกกา
({...})

while (condition) {
   statement1;
   statement2;
   :
   statementN;
}
ตัวอย่างที่ 4.1 จงเขียนโปรแกรมเพื่อพิมพ์ค่าตั้งแต่ 1 ถึง N โดยรับค่า N จากผู้ใช้

1:  using System;
2:  class OneToN {
3:    static void Main() {
4:      int i, N;
5:      Console.Write("Enter N: ");
6:      N = int.Parse(Console.ReadLine());
7:      i = 1; // initialize variable i to 1
8:      while (i <= N) {
9:        Console.WriteLine(i);
10:       i++;
11:     }
12:   }
13: }
ตัวอย่างผลการทำงาน

Please input N: 5
1
2
3
4
5


           ลองมาพิจารณาการทำงานของโปรแกรมทีละขั้นตอน เมื่อโปรแกรมเริ่มทำงาน ผู้ใช้จะป้อนตัวเลข
เพื่อใช้เป็นค่าของ N ณ บรรทัดที่ 6 และโปรแกรมจะกำหนดให้ค่า 1 เป็นค่าเริ่มต้นของ i ที่บรรทัดถัดมา
จากนั้นโครงสร้าง while จะมีผลทำให้โปรแกรมทำคำสั่งที่บรรทัดที่ 9 และ 10 จนกระทั่งนิพจน์ i <=

N มีค่าเป็นเท็จ ในการวนซ้ำแต่ละครั้งโปรแกรมจะพิมพ์ค่า i และเพิ่มค่า i ขึ้นทีละหนึ่ง ผลการทำงานของ
โปรแกรมจึงเป็นการพิมพ์ตัวเลขตั้งแต่ 1 (ซึ่งเป็นค่าเริ่มต้นของ i) จนถึงค่าของ N (ซึ่งเป็นค่าสุดท้ายของ i ที่ยังทำให้นิพจน์ i <= N เป็นจริง)

ตัวอย่างที่ 4.2 เราสามารถเขียนโปรแกรมเพื่อคำนวณหาผลรวมทั้งแต่ 1 ถึง N ใด ๆ โดยแก้ไขโปรแกรมใน
ตัวอย่างที่ 4.1 เพียงเล็กน้อยเท่านั้นดังต่อไปนี้

using System;
class Summing {
  static void Main() {
    int N, i, sum;
    Console.Write("Please input N: ");
    N = int.Parse(Console.ReadLine());
    i = 1; sum = 0;
    while (i <= N) {
      sum = sum + i;
      i++;
    }
    Console.WriteLine("Sum from 1 to {0} = {1} ", N, sum);
  }
}

ตัวอย่างผลการทำงาน
Please input N: 4
1
2
3
4
Sum from 1 to 4 = 10

            ในตัวอย่างที่ผ่านมาจะมีการกำหนดเงื่อนไขการทำงานของลูปโดยการกำหนดตัวแปรตัวหนึ่งขึ้นมาใช้เป็นตัวนับ (counter) ซึ่งมักจะถูกตั้งค่าเริ่มต้นให้เป็นศูนย์ก่อนเริ่มเข้าลูป และเพิ่มค่าขึ้นทีละหนึ่งหลังจากคำสั่งภายในลูปถูกทำงานเสร็จสิ้นหนึ่งรอบ โปรแกรมจะทำซ้ำไปเรื่อย ๆ จนกระทั่งตัวนับมีค่าเกินกว่าค่าที่กำหนด การวนลูปในลักษณะนี้เรียกว่าลูปวนนับ (counting loop)

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

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

using System;
class While4 {
  static void Main() {
    int N = 0;
    while (N >= 0) { // stop when N is negative
      Console.Write("Please input N: ");
      N = int.Parse(Console.ReadLine());
    }
    Console.WriteLine("Bye Bye!!!");
  }
}

ตัวอย่างผลการทำงาน

Please input N: 3
Please input N: 2
Please input N: 3000
Please input N: 9999
Please input N: -50
Bye Bye!!!


ใบความรู้ที่ 4.2 โครงสร้าง do...while ลูป

ใบความรู้ที่ 4.2
โครงสร้าง do...while ลูป

         โครงสร้างแบบ do..while เป็นอีกโครงสร้างหนึ่งที่นำมาใช้เขียนโปรแกรมเพื่อทำงานวนซ้ำได้
และมีการทำงานคล้ายคลึงกับโครงสร้างแบบ while มาก สิ่งที่แตกต่างกันก็คือ do..while จะตรวจสอบเงื่อนไขหลังจากทำคำสั่งภายในลูปไปแล้วหนึ่งครั้ง และจะวนซ้ำไปเรื่อย ๆ จนกระทั้งเงื่อนไขที่ ระบุมีค่าเป็นเท็จ ดังนั้นโครงสร้างแบบ do..while จึงทำคำสั่งในลูปอย่างน้อย หนึ่งครั้ง แม้ว่าเงื่อนไขจะเป็นเท็จตั้งแต่แรกก็ตาม รูปแบบการใช้งาน โครงสร้าง do..while เป็นดังนี้
do statement; while (condition);

และเช่นเคย วงเล็บปีกกาถูกนำมาใช้เพื่อรวมหลาย ๆ คำสั่งให้เสมือนเป็นหนึ่งเอาไว้ภายในลูปได้

do {
   statement1;
   statement2;
   :
   statementN;
} while (condition);

ตัวอย่างที่ 4.4 โปรแกรมด้านล่างมีการใช้งานโครงสร้าง do..while แต่ให้ผลการทำงานเหมือนกัน
โปรแกรมในตัวอย่างที่ 4.3 ทุกประการ
using System;
class DoWhile1 {
  static void Main() {
    int N = 0;
    do {
      Console.Write("Please input N: ");
      N = int.Parse(Console.ReadLine());
    } while (N >= 0);
    Console.WriteLine("Bye Bye!!!");
  }
}


ใบความรู้ที่ 4.3 โครงสร้าง for ลูป

ใบความรู้ที่ 4.3
โครงสร้าง for ลูป

           ในใบความรู้ก่อนหน้านี้เราได้เห็นโครงสร้างของโปรแกรมแบบวนซ้ำที่ใช้คำสั่ง while และ
do..while เมื่อพิจารณาการใช้คำสั่งเหล่านี้ในการเขียนลูปแบบวนนับ (counting loop) เราจะพบว่า
โครงสร้างของลูปมักจะมีส่วนประกอบเหล่านี้เสมอ

   • ส่วนกำหนดค่าเริ่มต้นให้ตัวนับ – เป็นคำสั่งให้ค่าเริ่มต้นกับตัวแปรที่นำมาใช้เป็นตัวนับ คำสั่งนี้มัก
     ถูกเขียนไว้ทันทีก่อนที่โปรแกรมจะเข้าทำงานในโครงสร้าง while หรือ do..while

   • ส่วนคำสั่งที่ถูกทำซ้ำ – ส่วนหลักของลูปที่ประกอบด้วยคำสั่งที่ถูกเรียกทำงานในแต่ละรอบการวน
     ซ้ำ

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

   • ส่วนปรับค่าตัวนับ – มักเป็นเพียงคำสั่งสั้น ๆ เพื่อเพิ่มหรือลดค่าตัวแปรที่นำมาใช้เป็นตัวนับ

         ตัวอย่างโปรแกรมต่อไปนี้แสดงให้เห็นส่วนประกอบต่าง ๆ ทั้งสี่ส่วน (แต่ละส่วนกำกับไว้ด้วยคอม
เมนต์ท้ายบรรทัด)

using System;
class CountDown {
  static void Main() {
    int i;
    i = 10;                  // (1) ส่วนกำหนดค่าเริ่มต้นให้ตัวนับ
    while (i >= 0) {         // (3) ส่วนเงื่อนไข
      Console.WriteLine(i);  // (2) ส่วนคำสั่งที่ถูกทำซ้ำ
      i--;                   // (4) ส่วนปรับค่าตัวนับ
    }
  }
}

            เนื่องจากลูปแบบวนนับมีการใช้งานบ่อยครั้งในโปรแกรมทั่ว ๆ ไป ภาษา C# (รวมถึงภาษา
โปรแกรมอื่น ๆ ด้วย) จึงได้เตรียมโครงสร้างพิเศษเพื่อใช้จัดการลูปประเภทนี้ได้โดยสะดวกยิ่งขึ้น
โครงสร้างนี้คือโครงสร้าง for ซึ่งมีรูปแบบการใช้งานดังนี้

for (init_stmt; condition; update_stmt) {
  statement1;
  statement2;
  :
  statementN;
}

           ผังงานด้านล่างแสดงขั้นตอนการทำงานของ for ลูป สังเกตว่าเงื่อนไขของลูปจะถูกตรวจสอบ
ก่อนที่คำสั่งวนซ้ำคำสั่งแรกจะถูกเรียกใช้ ดังนั้นโครงสร้าง for จึงมีการทำงานที่คล้ายคลึงกับโครงสร้าง
while มากกว่าโครงสร้าง do..while



ตัวอย่างที่ 4.5 โปรแกรมต่อไปนี้จะแสดงตัวเลข 1,2,3,...,20 บนหน้าจอ

using System;
class Counting {
  static void Main() {
    int i;
    for (i = 1; i <= 20; i++)
      Console.WriteLine(i);
  }
}

ตัวอย่างที่ 4.6 โปรแกรมต่อไปนี้รับตัวเลขอินพุท N จากผู้ใช้และแสดงตัวเลขทั้งหมดที่เป็นตัวประกอบของ N (นำไปหาร N แล้วลงตัว)

using System;
class Divisors {
  static void Main() {
    int i, N;
    Console.Write("Enter N: ");
    N = int.Parse(Console.ReadLine());
    for (i = 1; i <= N; i++) {
      if (N%i == 0) Console.WriteLine(i);
    }
  }
}

ตัวอย่างผลการทำงาน

Enter N: 100
1
2
4
5
10
20
25
50
100



ใบความรู้ที่ 5.1 การประกาศและเรียกใช้เมท็อด

ใบความรู้ที่ 5.1
การประกาศและเรียกใช้เมท็อด

           ที่ผ่านมาเราได้เขียนโปรแกรมโดยใส่คำสั่งทั้งหมดไว้ในส่วนที่เรียกว่าเมท็อด Main อย่างไรก็ตามการเขียนโปรแกรมในลักษณะนี้จะเหมาะสำหรับโปรแกรมสั้น ๆ ที่ใช้แก้ปัญหาง่าย ๆ เท่านั้น แต่สำหรับปัญหาที่มีขนาดใหญ่และมีความซับซ้อนมากขึ้นการเขียนโปรแกรมแบบนี้นอกจากจะทำให้โปรแกรมดูเทอะทะไม่เป็นระเบียบแล้วยังทำให้เกิดความผิดพลาดภายในโปรแกรมได้ง่ายขึ้นอีกด้วย ดังนั้นนักเขียนโปรแกรมที่มีประสบการณ์จึงมักออกแบบโปรแกรมโดยการแบ่งปัญหาที่ต้องการแก้ออกเป็นงานย่อย ๆ หลาย ๆ งานจากนั้นจึงเขียนโปรแกรมเป็นส่วน ๆ เพื่อจัดการงานย่อยในแต่ละงาน เราเรียกส่วนของโปรแกรมเพื่อจัดการงานย่อยหนึ่ง ๆ ว่า ซับรูทีน (subroutine) นอกจากนี้ยังมีคำอีกหลายคำที่ให้ความหมายในทำนองเดียวกัน เช่น โปรแกรมย่อย (subprogram) และฟังก์ชัน (function) สำหรับภาษาที่สนับสนุนการเขียนโปรแกรมเชิงวัตถุเช่นภาษา C# นั้นส่วนของโปรแกรมดังกล่าวจะถูกเรียกว่า เมท็อด (method)

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

           เราได้รู้จักวิธีการและได้เรียกใช้เมท็อดมาแล้วก่อนหน้านี้หลายครั้งเช่นการใช้งานเมท็อด
Console.WriteLine และ Math.Sqrt เมท็อดเหล่านี้เป็นเมท็อดที่ถูกสร้างมาให้พร้อมกับตัว
ภาษา C# ซึ่งเราสามารถเรียกใช้งานได้ทันที แต่ในปฏิบัติการครั้งนี้เราจะได้รู้จักวิธีการสร้างเมท็อดของเราขึ้นมาเอง

1. การประกาศเมท็อด
          ในความเป็นจริงเราเคยได้สร้างเมท็อดขึ้นมาเองมาก่อนหน้านี้แล้ว ยิ่งไปกว่านั้นเราได้สร้างเมท็อด
ลักษณะนี้เสมอในทุก ๆ โปรแกรมภาษา C# ที่เราเขียน เมท็อดดังกล่าวก็คือเมท็อด Main ที่ใช้สำหรับระบุ
จุดตั้งต้นของโปรแกรมนั่นเอง ลองพิจารณาโครงสร้างของโปรแกรมภาษา C# ที่เราคุ้นเคยมาก่อนแล้วดังนี้

namespace (มีหรือไม่มีก็ได้)
class
เมท็อด Main
statement;
...



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

namespace (มีหรือไม่มีก็ได้)
Class
เมท็อด Main
statement;
...

เมท็อด MyMethod_1
statement;
...

เมท็อด MyMethod_2
statement;
...

เมท็อด MyMethod_N
statement;
...



          สังเกตว่าเมท็อดแต่ละอันต้องถูกประกาศอยู่ภายนอกเมท็อดอื่น ๆ แต่อยู่ภายในคลาสเสมอ
   น      อ        ก       จ       า       ก         นั้         น
  เมท็อด Main ไม่จำเป็นต้องถูกประกาศเป็นเมท็อดแรกของโปรแกรม การประกาศเมท็อดจะมีรูปแบบดังนี้
static return_type method_name(parameter_list)
{
  statement1;
  statement2;
  :
}


          จะเห็นว่าเมท็อด Main ที่เราใช้กันมาตั้งแต่แรกก็มีการเขียนอยู่ในรูปแบบข้างต้นเช่นเดียวกัน เรา
สามารถแบ่งชนิดของเมท็อดเป็นสองประเภทคร่าว ๆ ได้แก่ เมท็อดแบบไม่คืนค่า (non-value returning
methods) และเมท็อดแบบคืนค่า (value-returning methods)

2. เมท็อดแบบไม่คืนค่า
         เมท็อดแบบไม่คืนค่า (บางครั้งเรียกว่า subroutine หรือ procedure) เป็นเมท็อดที่เขียนขึ้นมาเพื่อ
ปฏิบัติงานบางอย่างและจบงานนั้นในตัวมันเองโดยไม่ส่งค่าคืนกลับไปยังผู้เรียก การประกาศเมท็อด
ประเภทนี้ต้องมีการใช้คีย์เวิร์ด void ในตำแหน่ง return_type และการเรียกใช้เมท็อดประเภทนี้จะ
ปรากฏอยู่ในโปรแกรมเสมือนคำสั่งหนึ่งคำสั่ง

ตัวอย่างที่ 5.1 โปรแกรมต่อไปนี้ประกาศเมท็อดชื่อ PrintLine เพื่อทำหน้าที่พิมพ์ดาว (*) 10 ดวงออก
ทางหน้าจอ จากนั้นภายในเมท็อด Main จะเรียกใช้เมท็อด PrintLine สองครั้ง ดังนั้นผลลัพธ์ของ
โปรแกรมจะปรากฏเป็นดาวสองแถว แถวละ 10 ดวง

1:  using System;
2:  class MyClass {
3:    static void PrintLine() {
4:      for (int i = 0; i < 10; i++)
5:         Console.Write('*');
6:      Console.WriteLine();
7:    }
8:
9:    static void Main() {
10:      MyClass.PrintLine();
11:      MyClass.PrintLine();
12:   }
13: }

            จากการเรียกใช้งานเมท็อดในบรรทัดที่ 10--11 จะเห็นว่าการใช้งานเมท็อดนี้จะอยู่ในรูป
ClassName.MethodName โดย ClassName ในที่นี้คือ MyClass ซึ่งเป็นชื่อคลาสที่เราใช้ใน
โปรแกรมนี้ (บรรทัดที่ 2) และเป็นคลาสที่เมท็อด PrintLine ถูกนิยามไว้ ดังนั้นการใช้งานเมท็อดที่
สร้างขึ้นมาเองจึงเป็นลักษณะเดียวกันกับการใช้งานเมท็อดที่ภาษา C# เตรียมไว้ให้แล้ว เช่น
Console.WriteLine ซึ่ง WriteLine คือชื่อเมท็อดและ Console คือชื่อคลาสนั่นเอง

           อย่างไรก็ตามหากการเรียกใช้งานเมท็อดอยู่ภายในคลาสเดียวกันกับคลาสที่เมท็อดนั้น ๆ ถูก
ประกาศไว้ ภาษา C# อนุญาตให้เราละส่วนของชื่อคลาสออกไปได้ ดังนั้นเมท็อด Main ในตัวอย่างข้างต้น
จึงเขียนให้สั้นลงได้ดังนี้

static void Main() {
  PrintLine();
  PrintLine();
}


ใบความรู้ที่ 5.2 การส่งค่าไปยังเมท็อด

ใบความรู้ที่ 5.2
การส่งค่าไปยังเมท็อด

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

ตัวอย่างที่ 5.2 เมท็อด PrintCharLine ด้านล่างนี้ดัดแปลงมาจากเมท็อด PrintLine เมท็อดใหม่นี้
กำหนดให้มีพารามิเตอร์สองตัว คือ c เป็นชนิด char และ len เป็นชนิด int โดยที่พารามิเตอร์ c ใช้
สำหรับระบุอักขระที่จะพิมพ์ออกทางจอภาพ ) ไม่ได้พิมพ์เพียงแค่ดาวอีกต่อไป (และ len ใช้ระบุจำนวน
อักขระที่ต้องการพิมพ์ในหนึ่งบรรทัด
1: using System;
2: class ParamNoRet {
3:   static void PrintCharLine(char c, int len) {
4:     for (int i = 0; i < len; i++)
5:       Console.Write(c);
6:     Console.WriteLine();
7:   }
8:
9:   static void Main() {
10:    PrintCharLine(’o’, 10);
11:    PrintCharLine(’x’, 20);
12:  }
13: }

          จากโปรแกรมข้างต้น การเรียกใช้เมท็อด PrintCharLine ครั้งแรกภายในเมท็อด Main ใน
บรรทัดที่ 10 มีอาร์กิวเมนต์เป็น 'o' และ 10 ซึ่งเมท็อด PrintCharLine จะรับค่าอาร์กิวเมนต์นี้เข้ามา
อยู่ในพารามิเตอร์ c และ len ตามลำดับ ดังนั้นจะเห็นว่าบรรทัดที่ 4 และ 5 จะมีผลทำให้โปรแกรมพิมพ์
อักขระ o ออกทางหน้าจอเป็นจำนวน 10 ตัว ในทำนองเดียวกัน การเรียกใช้เมท็อด PrintCharLine
ในบรรทัดที่ 11 จะมีผลทำให้โปรแกรมพิมพ์อักขระ x ออกทางหน้าจอเป็นจำนวน 20 ตัว

ใบความรู้ที่ 5.3 เมท็อดแบบคืนค่า

ใบความรู้ที่ 5.3
เมท็อดแบบคืนค่า
         เมท็อดแบบคืนค่าเป็นเมท็อดที่ส่งผลลัพธ์กลับไปให้ยังผู้เรียกหลังจากการทำงานในเมท็อดเสร็จสิ้นลงตัวอย่างที่เราคุ้นเคยดีอยู่แล้วคือเมท็อด Console.ReadLine ซึ่งทำหน้าที่รอรับข้อมูลจากผู้ใช้และ
คืนค่าที่ผู้ใช้ป้อนในรูปของข้อความเพื่อให้โปรแกรมนำไปใช้ต่อไป หรือเมท็อด int.Parse ที่มีการรับ
ค่าพารามิเตอร์ในรูปข้อความและคืนค่ากลับออกมาเป็นตัวเลขที่สามารถนำไปใช้ในการคำนวณต่อไปได้
ดังนั้นโดยทั่วไปแล้วเมท็อดประเภทนี้จะปรากฏอยู่ในโปรแกรมในรูปของนิพจน์ชนิดต่าง ๆ ขึ้นอยู่กับชนิด
ของข้อมูลที่เมท็อดนั้น ๆ คืนกลับมาให้ อย่างไรก็ตามเราสามารถเรียกใช้เมท็อดเหล่านี้เป็นคำสั่งโดด ๆ ได้เช่นเดียวกับเมท็อดที่ไม่คืนค่าหากเราไม่ต้องการนำค่าที่คืนกลับมาไปประมวลผลใด ๆ

         การสร้างเมท็อดแบบคืนค่าขึ้นมาเองนั้นต้องระบุชนิดของข้อมูลที่เมท็อดจะส่งกลับเอาไว้ในส่วนที่
เป็นreturn_type ของการประกาศเมท็อดนั้น ๆ แทนที่จะใช้คีย์เวิร์ด void เหมือนที่เคยใช้กับเมท็อด
แบบไม่คืนค่า และภายในตัวเมท็อดเองจะต้องมีการใช้คำสั่ง return เพื่อให้เมท็อดสิ้นสุดการทำงาน
ทันทีและส่งค่ากลับไปยังผู้เรียก รูปแบบการใช้งานคำสั่ง return เป็นดังนี้
return expression;

โดยแทนที่ expression ด้วยนิพจน์ที่จะถูกประเมินเป็นค่าที่ต้องการส่งกลับ
          เมท็อดแบบคืนค่านิยมใช้ในกรณีที่ต้องการแจ้งให้ผู้เรียกใช้งานเมท็อดทราบถึงสถานะการทำงาน
ในเมท็อดเองว่าทำงานได้เสร็จสมบูรณ์หรือผิดพลาดอย่างไรโดยรายงานอยู่ในรูปของค่าความจริง true
หรือ false หรือหากความผิดพลาดสามารถเกิดขึ้นได้ในหลายกรณีแล้วเมท็อดนั้น ๆ สามารถรายงาน
ความผิดพลาดกลับไปได้ในรูปของรหัสความผิดพลาดที่กำหนดขึ้นมาเอง (เช่น ค่า 0 หมายถึงทำงานถูกต้องสมบูรณ์ 1 หมายถึงผู้ใช้ป้อนข้อมูลผิด หรือ 2 หมายถึงผู้ใช้ยกเลิกการทำงาน เป็นต้น)
          อีกกรณีหนึ่งที่เมท็อดแบบคืนค่าถูกนำมาใช้มากคือการนิยามฟังก์ชัน (function) ทางคณิตศาสตร์
ขึ้นมาเองเพื่อชดเชยจากส่วนที่ขาดไปในคลาส Math อีกทั้งยังใช้ในการสร้างฟังก์ชันเพื่อคำนวณที่ซับซ้อนเพื่อซ่อนความซับซ้อนนั้นไม่ให้ปรากฏในส่วนของโปรแกรมหลักดังเช่นตัวอย่างต่อไปนี้

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

1:  using System;
2:  class Triangle {
3:    static double TriangleArea(double w, double h) {
4:      double area = w*h/2.0;
5:      return area;
6:    }
7:
8:    static void Main() {
9:      Console.Write("Enter width: ");
10:     double width = double.Parse(Console.ReadLine());
11:     Console.Write("Enter height: ");
12:     double height = double.Parse(Console.ReadLine());
13:     Console.WriteLine("The area of the triangle is {0:f2}.",
14:       TriangleArea(width, height));
15:   }
16: }


          สังเกตว่าเนื่องจากเมท็อด TriangleArea ถูกประกาศให้คืนค่าเป็นชนิด double ในบรรทัด
ที่ 3ดังนั้นการเรียกใช้เมท็อดนี้จึงอยู่ในรูปของนิพจน์แบบ double ทำให้สามารถใช้งานร่วมกับเมท็อด
Console.WriteLine ในบรรทัดที่ 13-14 ได้ทันที

ตัวอย่างที่ 5.4 ตัวอย่างนี้แสดงการนิยามฟังก์ชัน



          ให้อยู่ในรูปของเมท็อดที่ถูกเรียกใช้จากเมท็อด Main เพื่อแสดงตารางค่าของ f (n) สำหรับแต่ละค่าของ n ตั้งแต่ 1 ถึง 15

1:  using System;
2:  class Function {
3:    static double f(int n) {
4:       double sum = 0.0;
5:       for (int i = 1; i <= n; i++)
6:          sum += Math.Sqrt(i);
7:
8:       return sum;
9:    }
10:
11:   static void Main() {
12:      Console.WriteLine(" n | f(n)");
13:      Console.WriteLine("---+------");
14:      for (int n = 1; n <= 15; n++) {
15:         Console.WriteLine("{0,2} | {1:f3}", n, f(n));
16:      }
17:   }
18: }

ตัวอย่างผลการทำงาน

 n | f(n)
---+------
 1 | 1.000
 2 | 2.414
 3 | 4.146
 4 | 6.146
 5 | 8.382
 6 | 10.832
 7 | 13.478
 8 | 16.306
 9 | 19.306
10 | 22.468
11 | 25.785
12 | 29.249
13 | 32.855
14 | 36.596
15 | 40.469


หมายเหตุ: สัญลักษณ์ {0,2} ที่ใช้ในคำสั่ง Console.WriteLine ในบรรทัดที่ 15 คือการกำหนดให้
ผลลัพธ์ในการพิมพ์ค่าในนิพจน์แรก (ซึ่งก็คือค่าในตัวแปร n) มีความยาวอย่างน้อยสองอักขระ เช่น หาก n
มีค่าเท่ากับ 3 ผลลัพธ์ที่พิมพ์ออกทางหน้าจอคือ ' 3' คือมีช่องว่างนำหน้าหนึ่งช่อง (ไม่รวมเครื่องหมาย
') ทำให้ผลลัพธ์โดยรวมมีความยาวสองอักขระ แต่ถ้า n มีค่าเท่ากับ 15 โปรแกรมจะแสดงผลลัพธ์ '15'
โดยไม่มีช่องว่างเนื่องจาก 15 มีความยาวสองอักขระอยู่แล้ว เหตุผลที่ต้องทำแบบนี้เพื่อให้เส้นตารางใน
ผลลัพธ์ดูสวยงาม ไม่เหลื่อมซ้อนกัน

ใบความรู้ที่ 6.1 ชนิดข้อมูลแบบอาเรย์

ใบความรู้ที่ 6.1
ชนิดข้อมูลแบบอาเรย์

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

1. การประกาศตัวแปรแบบอาเรย์

          ดังเช่นตัวแปรทั่ว ๆ ไป ตัวแปรแบบอาเรย์จะต้องมีการประกาศล่วงหน้าก่อนการใช้งาน โดยมี
รูปแบบดังต่อไปนี้

DataType[] ArrayName;

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

ตัวอย่างที่ 6.1 ส่วนของโปรแกรมต่อไปนี้เป็นการประกาศตัวแปรแบบอาเรย์สามตัวคือ score, grade
และ Name เพื่อเก็บข้อมูลประเภทจำนวนเต็ม อักขระ และสตริง ตามลำดับ ให้พิจารณาการประกาศตัวแปร
แบบอาเรย์เหล่านี้เทียบกับการประกาศตัวแปรตามปกติในตอนท้ายโดยดูความหมายจากคอมเมนต์ที่ท้ายแต่ละบรรทัด

int[] score;   // score refers to an array of integers
char[] grade;  // grade refers to an array of characters
string[] name; // Name refers to an array of strings



int s;    // s refers to an integer
char c;   // c refers to a character
string n; // n refers to a string

2. การสร้างอาเรย์

          ตัวแปรแบบอาเรย์ที่ถูกประกาศขึ้นมาตามรูปแบบข้างต้นนั้นสามารถนำไปใช้เพียงแค่อ้างถึงอาเรย์
ชนิดนั้นๆเท่านั้น อย่างไรก็ตาม ณ ขณะนี้เรายังไม่มีอาเรย์ที่แท้จริงที่จะอ้างถึง ดังนั้นขั้นตอนต่อไปจะเป็น
การสั่งให้คอมพิวเตอร์สร้างอาเรย์ขึ้นมาไว้ในหน่วยความจำของเครื่อง โดยคำสั่งที่เราจะใช้ในกระบวนการ
นี้คือคำสั่ง new ซึ่งมีรูปแบบการใช้งานดังนี้
    new DataType[num_elements]

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

ArrayName = new DataType[num_elements];

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

ตัวอย่างที่ 6.2 การประกาศตัวแปรแบบอาเรย์และการสร้างอาเรย์

   •  สร้างอาเรย์สำหรับเก็บจำนวนเต็ม 5 ตัว โดยอ้างอิงผ่านตัวแปรแบบอาเรย์ชื่อ scores
int[] scores;
scores = new int[5];

ตามที่ได้กล่าวไว้แล้วข้างต้น เราสามารถรวมเอาการประกาศตัวแปรแบบอาเรย์และการสร้างอาเรย์
ไว้ในคำสั่งเดียวกันดังนี้
int[] scores = new int[5];

   •  สร้างอาเรย์สำหรับเก็บชื่อนักเรียน 10 คน อ้างอิงผ่านตัวแปรแบบอาเรย์ชื่อ names
string[] names;
names = new string[10];

หรือ
string[] names = new string[10];

         นอกจากนี้อาเรย์ที่สร้างขึ้นมาใหม่ยังสามารถกำหนดค่าเริ่มต้นให้กับข้อมูลในอาเรย์ได้อีกด้วยโดย
อาศัยคำสั่งในรูปแบบต่อไปนี้
ArrayName = new DataType[num_elements] {
                   value0, value1,..., valueN-1};

            สิ่งที่เพิ่มขึ้นมาคือวงเล็บปีกกาหลังจากคำสั่ง new ที่ภายในมีค่าต่างๆ จำนวน num_elements
ค่า โดยค่า value0 จะถูกกำหนดเป็นค่าเริ่มต้นให้กับข้อมูลแรกสุดในอาเรย์ แล้วตามด้วย value1
สำหรับข้อมูลช่องถัดมาและไล่ต่อไปเรื่อยๆ จนถึงข้อมูลสุดท้าย

           หากมีการกำหนดค่าเริ่มต้นให้กับข้อมูลในอาเรย์แล้ว ภาษา C# ยอมให้เราละการระบุขนาดของ
อาเรย์ที่เราสร้างขึ้นมาได้ เนื่องจากขนาดของอาเรย์ถูกกำหนดไว้โดยจำนวนค่าเริ่มต้นที่ใส่ไว้ภายในวงเล็บปีกกาอยู่แล้ว ดังนั้นเราจึงสามารถใช้รูปแบบคำสั่งดังนี้ได้
    ArrayName = new DataType[] {value0, value1, ..., valueN-1};

สังเกตว่าเราได้ละส่วนที่เป็น num_elements ไว้ ยิ่งไปกว่านั้นคำสั่งข้างต้นยังสามารถเขียนให้สั้นลงได้
อีกโดยละคำสั่ง new ไว้ จึงเหลือแค่เพียง
   DataType[] ArrayName = {value0, value1, ..., valueN-1};

อย่างไรก็ตามการสร้างอาเรย์ในรูปแบบสุดท้ายนี้มีข้อจำกัดว่าจะต้องรวมอยู่ภายในคำสั่งเดียวกันกับการ
ประกาศตัวแปรแบบอาเรย์

ตัวอย่างที่ 6.3 สร้างอาเรย์ชื่อ scores เพื่อเก็บจำนวนเต็ม 5 จำนวนโดยมีค่าเริ่มต้นเท่ากับ 10, 50, 10, 55
และ 60 ตามลำดับ
int[] scores = new int[5] {10, 50, 10, 55, 60};

หรือ
int[] scores = new int[] {10, 50, 10, 55, 60};

หรือ
int[] scores = {10, 50, 10, 55, 60};


3. การอ้างถึงข้อมูลในอาร์เรย์

          เราสามารถเข้าถึงข้อมูลแต่ละจำนวนภายในอาเรย์ผ่านทางดัชนี (index) ที่สอดคล้องกับตำแหน่ง
ของข้อมูลนั้น ๆ โดยค่าดัชนีสำหรับข้อมูลตัวแรกสุดในอาเรย์ถูกำหนดให้เป็นดัชนีหมายเลข 0 ถัดมาเป็น
หมายเลข 1 เรื่อยไป ดังนั้นสำหรับอาเรย์ที่มีความยาว N แล้ว ค่าของดัชนีที่ใช้งานได้จึงเริ่มตั้งแต่ 0 ถึง N-1 ในภาษา C# ข้อมูล ณ ตำแหน่ง idx ภายในอาเรย์ชื่อ ArrayName จะถูกอ้างถึงในรูปแบบ
ArrayName[idx]

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

ตัวอย่างที่ 6.4 พิจารณาอาเรย์ scores ซึ่งประกอบด้วยจำนวนเต็ม 5 จำนวน

• กำหนดค่า 52 ให้กับข้อมูลตัวแรกของอาเรย์
scores[0] = 52;

• นำข้อมูลในตำแหน่งท้ายสุดของอาเรย์มาแสดงผลบนหน้าจอ
Console.WriteLine(scores[4]);

• กำหนดให้ค่าทุกค่าในอาเรย์มีค่าเท่ากับ 3
for (int i = 0; i < 5; i++)
   scores[i] = 3;

• คำนวณผลรวมของค่าทั้งหมดภายในอาเรย์
int sum = 0;
for (int i = 0; i < 5; i++)
   sum = sum + scores[i];

• นำค่าทั้งหมดในอาเรย์มาแสดงผลบนหน้าจอ
for (int i = 0; i < 5; i++)
   Console.WriteLine("Student {0}: {1}", i+1, scores[i]);