2.1 แสดงผลด้วย printf
ในการแข่งขัน grader ที่รู้จักในหน้า 0.3 เทียบผลลัพธ์ของเรากับคำตอบทีละตัวอักษร ทศนิยมเกินมาหนึ่งหลัก หรือเว้นวรรคผิดหนึ่งช่อง ก็ได้ศูนย์คะแนนในชุดนั้นทันที printf คือเครื่องมือที่ทำให้เราคุมได้ทุกตัวอักษร บทที่ 1 ใช้ไปแล้วสามสี่แบบ หน้านี้รวมทุกแบบที่โจทย์ระดับ TOI Zero ต้องใช้ ทั้งชนิดข้อมูล จำนวนทศนิยม และตัวอักษรพิเศษอย่างเครื่องหมายคำพูด
ตัวกำหนดรูปแบบทั้งหมด
ข้อความแรกใน printf เรียกว่า format string (ข้อความแม่แบบ) ตัวอักษรธรรมดาในนั้นพิมพ์ออกมาตรงตัว ส่วนที่ขึ้นต้นด้วย % เรียกว่า format specifier (ตัวกำหนดรูปแบบ) เป็นช่องที่รอค่ามาเติม ค่าที่อยู่หลังข้อความจะเติมลงช่องตามลำดับ อย่างที่เห็นในหน้า 1.1
| ตัวกำหนด | ใช้พิมพ์ | เจอครั้งแรก |
|---|---|---|
%d | int | 1.1 |
%lld | long long | 1.3 |
%f | double | 1.4 |
%c | char ตัวอักษรหนึ่งตัว | 1.4 |
%s | ข้อความ (string) | หน้านี้ |
%% | เครื่องหมาย % หนึ่งตัว | 1.2 |
#include <stdio.h>
int main()
{
int score = 45;
long long views = 3500000000;
double height = 158.5;
char grade = 'B';
printf("%s got %d points, grade %c\n", "Mali", score, grade);
printf("height %f cm\n", height);
printf("views %lld\n", views);
printf("progress 75%%\n");
return 0;
}
Mali got 45 points, grade B
height 158.500000 cm
views 3500000000
progress 75%
- บรรทัดที่ 9 มีช่องสามช่อง
%s%d%cค่าสามค่าเติมตามลำดับ ชนิดของค่าต้องตรงกับช่อง %sใช้กับข้อความในเครื่องหมายคำพูดคู่ ตอนนี้ยังไม่มีตัวแปรที่เก็บข้อความ จะได้เริ่มใช้ในหน้า 2.3 และเรียนเต็มๆ ในบทที่ 6- บรรทัดที่ 12 ไม่มีค่าให้เติมเลย
%%ไม่ใช่ช่อง แค่บอกให้พิมพ์%หนึ่งตัว
กำหนดจำนวนทศนิยมด้วย %.Nf
%f พิมพ์ทศนิยม 6 ตำแหน่งเสมอ แต่โจทย์มักสั่งว่า "ตอบเป็นทศนิยม 2 ตำแหน่ง" ถ้าพิมพ์ 6 ตำแหน่งไป ผลไม่ตรงกับคำตอบ ก็ไม่ได้คะแนน วิธีกำหนดคือใส่จุดกับตัวเลขไว้ระหว่าง % กับ f เช่น %.2f แปลว่าทศนิยม 2 ตำแหน่ง
ใช้โปรแกรม BMI จากหน้า 1.4 พิมพ์ค่าเดียวกันหลายแบบ
#include <stdio.h>
int main()
{
double weight, height;
scanf("%lf %lf", &weight, &height);
double bmi = weight / (height * height);
printf("%f\n", bmi);
printf("%.3f\n", bmi);
printf("%.2f\n", bmi);
printf("%.1f\n", bmi);
printf("%.0f\n", bmi);
return 0;
}
60 1.70
20.761246
20.761
20.76
20.8
21
printfปัดเศษ ไม่ได้ตัดทิ้ง ค่าจริงคือ 20.7612456... พอเหลือ 1 ตำแหน่ง หลักถัดไปคือ 6 จึงปัดขึ้นเป็น 20.8 พอเหลือ 0 ตำแหน่ง ก็ปัดขึ้นเป็น 21%.0fไม่พิมพ์จุดทศนิยมเลย- การปัดเกิดตอนพิมพ์เท่านั้น ค่าใน
bmiยังเป็น 20.7612456... เหมือนเดิม
printf ปัด แต่ cast ตัด
%.0f กับ 20.76 ได้ 21 แต่ (int)20.76 ได้ 20 เพราะ cast ตัดทศนิยมทิ้งตามที่เห็นในหน้า 1.4 โจทย์ที่สั่งให้ "ปัดเศษ" ใช้ %.0f ได้ ส่วนโจทย์ที่สั่งให้ "ตัดเศษทิ้ง" ใช้ cast
printf ไม่มีแบบ %lf ที่ต่างจาก %f เขียน %lf ใน printf ก็ได้ผลเหมือนกัน แต่ใน scanf ต้องเป็น %lf เท่านั้น ดูเหตุผลในหน้า 2.3
ปัดเศษไม่ได้ตรงอย่างที่คิดทุกครั้ง
2.675 ปัดเป็นทศนิยม 2 ตำแหน่ง คิดในใจได้ 2.68 แต่ลองรันดู
#include <stdio.h>
int main()
{
printf("%.2f\n", 2.675);
printf("%.20f\n", 2.675);
return 0;
}
2.67
2.67499999999999982236
บรรทัดที่สองเฉลยว่าทำไม 2.675 เก็บในฐานสองแบบลงตัวไม่ได้ เรื่องเดียวกับ 0.1 + 0.2 ในหน้า 1.4 ค่าที่เก็บจริงน้อยกว่า 2.675 นิดเดียว หลักที่สามจึงเป็น 4 และปัดลง
ไม่ต้องกลัวเรื่องนี้ในการแข่งขัน คนตั้งโจทย์รู้ปัญหานี้ และเลือกข้อมูลไม่ให้คำตอบตกตรงขอบของการปัดเศษ แต่ถ้าคำนวณเองแล้วได้ต่างจากตัวอย่างเฉพาะหลักสุดท้าย ให้นึกถึงเรื่องนี้ก่อนจะคิดว่าสูตรผิด
เลขที่ตกตรงครึ่งพอดี ต่างกันตามระบบ
เลขอย่าง 0.25 กับ 2.5 เก็บในฐานสองได้ลงตัวพอดี พอปัดตรงครึ่ง ระบบแต่ละแบบเลือกไม่เหมือนกัน วัดบนเครื่องที่เขียนเอกสารนี้ ฝั่ง Windows 11 ใช้ GCC 14.2 ของ Code::Blocks ฝั่ง Linux ใช้ Debian ใน WSL กับ GCC 16.2
| คำสั่ง | Windows | Linux |
|---|---|---|
printf("%.1f\n", 0.25); | 0.3 | 0.2 |
printf("%.2f\n", 0.125); | 0.13 | 0.12 |
printf("%.0f\n", 2.5); | 3 | 2 |
grader อาจไม่ได้ใช้ระบบเดียวกับเครื่องเรา โจทย์ที่ดีจึงเลี่ยงตัวเลขพวกนี้ แบบฝึกหัดในเว็บนี้ก็เลี่ยงเหมือนกัน
ตัวอักษรพิเศษที่ขึ้นต้นด้วย backslash
บางตัวอักษรพิมพ์ลงในข้อความตรงๆ ไม่ได้ การขึ้นบรรทัดใหม่กด Enter กลางข้อความไม่ได้ เครื่องหมาย " ก็ใส่ตรงๆ ไม่ได้เพราะ compiler จะคิดว่าข้อความจบแล้ว ภาษา C จึงให้เขียนเป็นสองตัวอักษรที่ขึ้นต้นด้วย \ (backslash) เรียกว่า escape sequence
| เขียน | ได้ |
|---|---|
\n | ขึ้นบรรทัดใหม่ (newline) |
\t | tab กระโดดไปคอลัมน์ถัดไป |
\" | เครื่องหมายคำพูด " |
\\ | backslash \ หนึ่งตัว |
สองแถวล่างคือวิธีเดียวกับในคำใบ้ของข้อ เครื่องหมายคำพูด ในบทที่ 0 ใครยังไม่ได้ทำข้อนั้น อ่านหน้านี้จบแล้วกลับไปลองได้
#include <stdio.h>
int main()
{
printf("Teacher said \"save it in C:\\code\"\n");
printf("Name\tScore\n");
printf("Mali\t85\n");
printf("Somchai\t92\n");
return 0;
}
Teacher said "save it in C:\code"
Name Score
Mali 85
Somchai 92
\t ไม่ได้แปลว่าเว้นกี่ช่องตายตัว แต่แปลว่าเลื่อนไปจุดหยุดถัดไป ในหน้าต่างดำของ Windows จุดหยุดอยู่ทุก 8 ตัวอักษร (กล่องผลลัพธ์ในเว็บนี้แสดงแคบกว่านั้น) Mali ยาว 4 ตัว กับ Somchai ยาว 7 ตัว จึงไปหยุดที่ตำแหน่งเดียวกัน ตัวเลขเลยตรงกัน ถ้าชื่อยาวตั้งแต่ 8 ตัวขึ้นไปจะเกิดอะไร ดูในหน้า 2.2
ลองทำให้พัง
แบบที่ 1 ใส่ค่าไม่ครบช่อง
มีช่อง %d สองช่อง แต่ส่งค่าไปตัวเดียว
int math = 78, science = 91;
printf("math = %d, science = %d\n", math);
scores.c:6:35: warning: format '%d' expects a matching 'int' argument [-Wformat=]
6 | printf("math = %d, science = %d\n", math);
| ~^
| |
| int
scores.c:5:20: warning: unused variable 'science' [-Wunused-variable]
5 | int math = 78, science = 91;
| ^~~~~~~
expects a matching 'int' argument แปลว่าช่องนี้รอ int มาเติม แต่ไม่มีให้ คำเตือนที่สองบอกว่า science ประกาศไว้แต่ไม่ได้ใช้ ซึ่งเป็นเบาะแสเดียวกัน รันต่อได้ แต่ช่องที่ไม่มีค่าจะได้ค่าขยะ บนเครื่องที่เขียนเอกสารนี้ได้ math = 78, science = -1910617456
แบบที่ 2 ใช้ backslash ตัวเดียว
พิมพ์ path ของไฟล์โดยลืมว่า \ ต้องเขียนสองตัว
#include <stdio.h>
int main()
{
printf("C:\code\new.c\n");
return 0;
}
path.c:5:29: warning: unknown escape sequence: '\c'
5 | printf("C:\code\new.c\n");
| ^
C:code
ew.c
compiler เตือนแค่ \c ที่ไม่มีความหมาย แล้วทิ้ง backslash ไปเหลือแค่ c แต่ \n หน้าคำว่า new เป็น escape sequence ที่ถูกต้อง compiler จึงไม่เตือนอะไร และกลายเป็นการขึ้นบรรทัดใหม่ ตัว n หายไปด้วย ถ้าข้อความมี \ ให้เขียน \\ ทุกครั้ง
สรุป
%d%lld%f%c%sใช้กับintlong longdoublecharและข้อความ%%พิมพ์%%.2fคือทศนิยม 2 ตำแหน่งprintfปัดเศษ แต่ cast ตัดทิ้ง- ทศนิยมที่เก็บไม่ลงตัวอาจปัดผิดจากที่คิดในหลักสุดท้าย
\nขึ้นบรรทัด\ttab\"เครื่องหมายคำพูด\\backslash- จำนวนช่องกับจำนวนค่าต้องเท่ากัน ชนิดต้องตรงกัน ถ้าไม่ตรง
-Wallมักเตือน