ผลต่างระหว่างรุ่นของ "การโปรแกรมภาษาซี สำหรับโปรแกรมเมอร์จาวาและซีชาร์ป"
Jittat (คุย | มีส่วนร่วม) |
Jittat (คุย | มีส่วนร่วม) |
||
แถว 84: | แถว 84: | ||
สังเกตว่าในตัวอย่างข้างต้นฟังก์ชัน <tt>scanf</tt> นั้นรับอาร์กิวเมนต์เป็นตำแหน่งของตัวแปร <tt>a</tt> และ <tt>b</tt> อย่างที่เกริ่นไว้ ถ้าเราไม่ได้ระบุชนิดข้อมูล (<tt>%d</tt> สำหรับ <tt>int</tt> หรือ <tt>%d</tt> สำหรับ <tt>float</tt>) ฟังก์ชัน <tt>scanf</tt> ก็จะไม่ทราบว่าจะจัดการกับข้อมูลที่อ่านเข้ามาอย่างไร | สังเกตว่าในตัวอย่างข้างต้นฟังก์ชัน <tt>scanf</tt> นั้นรับอาร์กิวเมนต์เป็นตำแหน่งของตัวแปร <tt>a</tt> และ <tt>b</tt> อย่างที่เกริ่นไว้ ถ้าเราไม่ได้ระบุชนิดข้อมูล (<tt>%d</tt> สำหรับ <tt>int</tt> หรือ <tt>%d</tt> สำหรับ <tt>float</tt>) ฟังก์ชัน <tt>scanf</tt> ก็จะไม่ทราบว่าจะจัดการกับข้อมูลที่อ่านเข้ามาอย่างไร | ||
+ | |||
+ | ในการอ่านข้อมูลด้วยฟังก์ชัน <tt>scanf</tt> นั้น ฟังก์ชันดังกล่าวจะ'''อ่านข้าม'''ช่องว่างและบรรทัดใหม่ให้เสมอทำให้สะดวกเวลาอ่านข้อมูลหลาย ๆ ตัว (แต่อาจมีปัญหาบ้างถ้าต้องการอ่าน string ที่มีช่องว่างอยู่ด้วย) | ||
ความผิดพลาดที่เกิดขึ้นบ่อยเวลาใช้ฟังก์ชัน <tt>scanf</tt> ก็คือการลืมใส่ <tt>&</tt> เพื่อระบุตำแหน่ง เช่นดังตัวอย่างด้านล่าง | ความผิดพลาดที่เกิดขึ้นบ่อยเวลาใช้ฟังก์ชัน <tt>scanf</tt> ก็คือการลืมใส่ <tt>&</tt> เพื่อระบุตำแหน่ง เช่นดังตัวอย่างด้านล่าง | ||
แถว 98: | แถว 100: | ||
scanf("%d", b); // b ชี้ไปที่ a | scanf("%d", b); // b ชี้ไปที่ a | ||
</geshi> | </geshi> | ||
+ | |||
+ | ด้านล่างเป็นตารางของ format ที่ใช้บ่อย ๆ (รวมทั้งตัวอย่างการระบุการเว้น) | ||
+ | |||
+ | <table> | ||
+ | <tr><td>'''format'''</td><td>'''ประเภทข้อมูล'''</td></tr> | ||
+ | <tr><td><tt>%d</tt></td><td><tt>int</tt></td></tr> | ||
+ | <tr><td><tt>%5d</tt></td><td>แสดง <tt>int</tt> แบบ 5 หลัก ชิดขวา</td></tr> | ||
+ | <tr><td><tt>%f</tt></td><td><tt>float</tt></td></tr> | ||
+ | <tr><td><tt>%5.2f</tt></td><td>แสดง <tt>float</tt> แบบ 5 หลักมีทศนิยม 2 ตำแหน่ง</td></tr> | ||
+ | <tr><td><tt>%lf</tt></td><td><tt>double</tt></td></tr> | ||
+ | <tr><td><tt>%s</tt></td><td>อ่าน string โดย string ดังกล่าวมีขอบเขตอยู่ที่ช่องว่างหรือบรรทัดใหม่</td></tr> | ||
+ | </table> | ||
== อาร์เรย์และพอยน์เตอร์ == | == อาร์เรย์และพอยน์เตอร์ == |
รุ่นแก้ไขเมื่อ 10:29, 12 กรกฎาคม 2552
เอกสารนี้เกี่ยวข้องกับการโปรแกรมภาษาซี โดยออกแบบสำหรับผู้มีความรู้พื้นฐานการโปรแกรมในภาษาตระกูล java และ c# มาแล้ว
<geshi lang="c">
- include <stdio.h>
main() {
printf("Hello, world.\n");
} </geshi>
เนื้อหา
พอยน์เตอร์ (Pointers)
โปรแกรมภาษาซีมองหน่วยความจำเป็นตาราง แต่ละหน่วยย่อยของหน่วยความจำจะมีตำแหน่งระบุอยู่ ไล่เรียงกันไป หน่วยย่อยสุดของการอ้างถึงหน่วยความจำคือไบต์
พอยน์เตอร์เป็นตัวแปรที่ใช้เก็บตำแหน่งในหน่วยความจำ หรือเรียกว่าตัวแปรพอยน์เตอร์ ชี้ ไปยังตำแหน่งที่มันเก็บอยู่
อย่างไรก็ตามเนื่องจากการชี้ไปยังหน่วยความจำตำแหน่งใด ๆ โดยไม่ระบุประเภทข้อมูลที่เก็บอยู่ที่จุดนั้นไม่เพียงพอในการประมวลผล โดยทั่วไปแล้วการประกาศพอยน์เตอร์จำเป็นจะต้องระบุประเภทข้อมูลที่ตัวแปรนั้นชี้ไปด้วย
การประกาศตัวแปรแบบพอยน์เตอร์ทำได้โดยการใส่ * หน้าชื่อตัวแปร เช่นการเขียน int *a; คือการประกาศให้ตัวแปร a เป็นตัวแปรพอยน์เตอร์ไปยังตำแหน่งข้อมูลที่เก็บข้อมูลประเภท int
เมื่อเรามีตัวแปรพอยน์เตอร์แล้ว การอ้างถึง ข้อมูล ที่ตัวแปรนั้นชี้อยู่ ทำได้โดยใช้ตัวดำเนินการ * ใส่ด้านหน้า ในทางกลับกัน การหาตำแหน่งในหน่วยความจำจากตัวแปร (หรือข้อมูล) ทำได้โดยใช้ตัวดำเนินการ & พิจารณาโปรแกรมด้านล่าง
<geshi lang="c">
- include <stdio.h>
main() {
int a = 10; int b = 20; int *c; printf("%d, %d\n",a,b); c = &a; *c = 30; printf("%d, %d\n",a,b); c = &b; *c = 40; printf("%d, %d\n",a,b);
} </geshi>
ให้ผลลัพธ์เป็น
10, 20 30, 20 30, 40
พอยน์เตอร์มีประโยชน์มากในการเขียนฟังก์ชันให้มีผลข้างเคียง (side effect) ตัวอย่างเช่นฟังก์ชัน swap ด้านล่าง
<geshi lang="c"> void swap(int *a, int *b) {
int tmp = *a; *a = *b; *b = tmp;
} </geshi>
เนื่องจากตัวแปรแบบพอยน์เตอร์เป็นตัวแปรที่อยู่ในหน่วยความจำ ตัวแปรเราจึงมีตัวแปรพอยน์เตอร์ที่ชี้ไปยังข้อมูลแบบพอยน์เตอร์ได้ พิจารณาส่วนของโปรแกรมต่อไปนี้
<geshi lang="c">
int a = 10, b = 20; int *c = &a; int **d = &c; *c = 30; // ตัวแปร a เปลี่ยนค่าเป็น 30 *d = &b; // ตอนนี้ c ชี้ไปที่ b *c = 100; // ตัวแปร b เปลี่ยนค่าเป็น 100 **d = 200; // **d = *(*d) = *c นั่นคือ หลังคำสั่งนี้ ตัวแปร b เปลี่ยนค่าเป็น 200
</geshi>
การอ่านและเขียนผลลัพธ์
คำสั่งพื้นฐานของภาษา C ในการอ่านและเขียนผลลัพธ์คือ scanf และ printf ซึ่งประกาศอยู่ในไฟล์หัว stdio.h
ในการอ่านและแสดงผลลัพธ์นั้น ฟังก์ชันทั้งสองจะพิจารณาข้อมูลและตัวแปรที่รับมาตามประเภทข้อมูลที่ระบุใน format string (ซึ่งระบุเป็นอาร์กิวเมนต์แรก)
พิจารณาส่วนของโปรแกรมต่อไปนี้
<geshi lang="c">
int a; float b; scanf("%d %f", &a, &b); printf("a plus 100 is %d. b divided by 2 is %f.\n", a+100, b/2);
</geshi>
สังเกตว่าในตัวอย่างข้างต้นฟังก์ชัน scanf นั้นรับอาร์กิวเมนต์เป็นตำแหน่งของตัวแปร a และ b อย่างที่เกริ่นไว้ ถ้าเราไม่ได้ระบุชนิดข้อมูล (%d สำหรับ int หรือ %d สำหรับ float) ฟังก์ชัน scanf ก็จะไม่ทราบว่าจะจัดการกับข้อมูลที่อ่านเข้ามาอย่างไร
ในการอ่านข้อมูลด้วยฟังก์ชัน scanf นั้น ฟังก์ชันดังกล่าวจะอ่านข้ามช่องว่างและบรรทัดใหม่ให้เสมอทำให้สะดวกเวลาอ่านข้อมูลหลาย ๆ ตัว (แต่อาจมีปัญหาบ้างถ้าต้องการอ่าน string ที่มีช่องว่างอยู่ด้วย)
ความผิดพลาดที่เกิดขึ้นบ่อยเวลาใช้ฟังก์ชัน scanf ก็คือการลืมใส่ & เพื่อระบุตำแหน่ง เช่นดังตัวอย่างด้านล่าง
<geshi lang="c">
int a; scanf("%d", a); // ถ้า a มีค่า 0, scanf จะพยายามเขียนข้อมูลลงในตำแหน่ง 0
</geshi>
อย่างไรก็ตาม ไม่ใช่ว่าเราจะใส่ & เสมอไป ตัวอย่างเช่น ส่วนของโปรแกรมด้านล่างอ่านข้อมูลเข้าไปที่ตัวแปร a ได้อย่างถูกต้อง
<geshi lang="c">
int a; int *b = &a; scanf("%d", b); // b ชี้ไปที่ a
</geshi>
ด้านล่างเป็นตารางของ format ที่ใช้บ่อย ๆ (รวมทั้งตัวอย่างการระบุการเว้น)
format | ประเภทข้อมูล |
%d | int |
%5d | แสดง int แบบ 5 หลัก ชิดขวา |
%f | float |
%5.2f | แสดง float แบบ 5 หลักมีทศนิยม 2 ตำแหน่ง |
%lf | double |
%s | อ่าน string โดย string ดังกล่าวมีขอบเขตอยู่ที่ช่องว่างหรือบรรทัดใหม่ |
อาร์เรย์และพอยน์เตอร์
โครงสร้าง (struct)
อาร์กิวเมนต์จาก command line
การประมวลผลสตริง
การคอมไพล์และลิงก์โปรแกรมที่อยู่ในหลายแฟ้ม
วิธีการคลาสสิกในการจัดการงานที่ใหญ่ ก็คือการแบ่งงานดังกล่าวเป็นส่วนย่อย ๆ การพัฒนาโปรแกรมก็เช่นเดียวกัน ถ้าโปรแกรมที่เราต้องการพัฒนามีขนาดใหญ่ การแบ่งโปรแกรมดังกล่าวออกเป็นส่วนย่อย ๆ ที่มีขนาดเล็กลงมักช่วยให้พัฒนาและทดสอบความถูกต้องได้ง่ายขึ้น นอกจากนี้ยังมีประโยชน์ที่ช่วยลดเวลาในการคอมไพล์อีกด้วย (โปรแกรมใหญ่ ๆ ถ้าคอมไพล์ทั้งหมดอาจใช้เวลานานมาก)