1.2 ตัวดำเนินการและการคำนวณ
มีตัวแปรแล้ว ต่อไปคือคำนวณ เครื่องหมายบวก ลบ คูณ หาร เรียกรวมว่า ตัวดำเนินการ (operator) ส่วนข้อความที่เอาตัวแปร ตัวเลข และตัวดำเนินการมาต่อกัน เช่น width * height เรียกว่า นิพจน์ (expression) หน้านี้มีสองเรื่องที่ต่างจากคณิตศาสตร์ในห้องเรียน คือการหารจำนวนเต็ม และเครื่องหมาย % สองเรื่องนี้ใช้ในโจทย์แข่งขันบ่อยมาก
ห้าตัวดำเนินการพื้นฐาน
#include <stdio.h>
int main()
{
int a = 17, b = 5;
printf("%d + %d = %d\n", a, b, a + b);
printf("%d - %d = %d\n", a, b, a - b);
printf("%d * %d = %d\n", a, b, a * b);
printf("%d / %d = %d\n", a, b, a / b);
printf("%d %% %d = %d\n", a, b, a % b);
return 0;
}
17 + 5 = 22
17 - 5 = 12
17 * 5 = 85
17 / 5 = 3
17 % 5 = 2
| ตัวดำเนินการ | ความหมาย | 17 กับ 5 |
|---|---|---|
+ | บวก | 22 |
- | ลบ | 12 |
* | คูณ ใช้ดอกจัน ไม่ใช่ตัว x | 85 |
/ | หาร ถ้าทั้งสองข้างเป็นจำนวนเต็ม จะได้แค่ส่วนที่เป็นจำนวนเต็ม | 3 |
% | เศษจากการหาร อ่านว่า mod | 2 |
สังเกตบรรทัดที่ 10 ใน printf เครื่องหมาย % มีหน้าที่พิเศษอยู่แล้ว (เช่น %d) ถ้าอยากให้พิมพ์ % ออกมาเฉยๆ ต้องเขียนสองตัวเป็น %%
หารจำนวนเต็ม กับเศษ
17 หารด้วย 5 ในชีวิตจริงได้ 3.4 แต่ในภาษา C ถ้าทั้งสองข้างเป็น int ผลก็เป็น int ส่วนทศนิยมจะถูก ตัดทิ้ง ไม่ปัดขึ้น ได้ 3 ส่วนที่หายไปหาคืนได้ด้วย %
17 = 5 * 3 + 2
17 / 5 = 3 (ได้กี่รอบ)
17 % 5 = 2 (เหลือเศษเท่าไร)
ถ้านึกไม่ออก ให้นึกถึงลูกอม 17 เม็ดแบ่งให้เพื่อน 5 คน ได้คนละ 3 เม็ด เหลือ 2 เม็ด / คือได้คนละเท่าไร % คือเหลือเท่าไร
สองตัวนี้ใช้คู่กันบ่อยมาก ตัวอย่างที่จะเจอซ้ำๆ
n % 2ได้ 0 ถ้า n เป็นเลขคู่ ได้ 1 ถ้าเป็นเลขคี่n % 10คือหลักหน่วยของ nn / 10คือ n ที่ตัดหลักหน่วยทิ้งn / 60กับn % 60แปลงนาทีเป็นชั่วโมงกับนาที
ถ้าเป็นเลขติดลบ
#include <stdio.h>
int main()
{
int a = -17, b = 5;
printf("%d %d\n", a / b, a % b);
printf("%d %d\n", 17 / -5, 17 % -5);
return 0;
}
-3 -2
-3 2
ภาษา C ตัดทศนิยมทิ้งไปทาง 0 เสมอ -3.4 จึงกลายเป็น -3 ไม่ใช่ -4 และเศษจาก % มีเครื่องหมายตามตัวตั้ง ตอนนี้ยังไม่ต้องจำ แค่รู้ไว้ว่าเลขติดลบกับ % ต้องระวัง เมื่อไรเจอโจทย์ที่มีเลขติดลบ ให้ลองรันดูก่อนเชื่อ
ลำดับการคำนวณ
เหมือนคณิตศาสตร์ คูณหารทำก่อนบวกลบ
*/%ทำก่อน+-ทำทีหลัง- ถ้าลำดับเท่ากัน ทำจากซ้ายไปขวา
- อยากให้อะไรทำก่อน ใส่วงเล็บ
#include <stdio.h>
int main()
{
printf("%d\n", 2 + 3 * 4);
printf("%d\n", (2 + 3) * 4);
printf("%d\n", 20 / 2 * 5);
printf("%d\n", 20 / (2 * 5));
printf("%d\n", 7 + 10 % 4);
return 0;
}
14
20
50
2
9
บรรทัดที่ 7 ทำ 20 / 2 ได้ 10 ก่อน แล้วค่อยคูณ 5 เพราะลำดับเท่ากันเลยทำจากซ้ายไปขวา บรรทัดที่ 9 % อยู่ระดับเดียวกับคูณหาร จึงทำ 10 % 4 ได้ 2 ก่อนบวก 7
ไม่แน่ใจ ใส่วงเล็บ
วงเล็บเกินไม่ทำให้โปรแกรมช้าลง และทำให้คนอ่านไม่ต้องนั่งนึกลำดับ (a * b) + c อ่านง่ายกว่าให้คนอ่านไปจำกฎเอง
ตัวย่อ += และ ++
การเอาค่าเดิมของตัวแปรมาคำนวณแล้วเก็บกลับที่เดิม อย่าง coins = coins + 5; เกิดบ่อยจนภาษา C มีตัวย่อให้
| เขียนย่อ | เหมือนกับ |
|---|---|
x += 5; | x = x + 5; |
x -= 5; | x = x - 5; |
x *= 5; | x = x * 5; |
x /= 5; | x = x / 5; |
x %= 5; | x = x % 5; |
x++; | x = x + 1; |
x--; | x = x - 1; |
#include <stdio.h>
int main()
{
int coins = 10;
coins += 5;
printf("%d\n", coins);
coins -= 3;
printf("%d\n", coins);
coins *= 2;
printf("%d\n", coins);
coins++;
printf("%d\n", coins);
coins--;
printf("%d\n", coins);
return 0;
}
15
12
24
25
24
++ กับ -- จะได้ใช้เยอะมากตอนเรียนวนซ้ำในบทที่ 4 ตอนนี้ให้ใช้เป็นคำสั่งเดี่ยวๆ ในบรรทัดของมันเองแบบในตัวอย่าง อย่าเอาไปผสมในนิพจน์อื่น เหตุผลอยู่ในส่วนลองทำให้พังท้ายหน้า
แปลงนาทีเป็นชั่วโมง
หนังเรื่องหนึ่งยาว 135 นาที คิดเป็นกี่ชั่วโมงกี่นาที หนึ่งชั่วโมงมี 60 นาที จำนวนชั่วโมงคือ 135 หารด้วย 60 แบบตัดเศษ ส่วนนาทีที่เหลือคือเศษ
#include <stdio.h>
int main()
{
int total_minutes;
scanf("%d", &total_minutes);
int hours = total_minutes / 60;
int minutes = total_minutes % 60;
printf("%d hours %d minutes\n", hours, minutes);
return 0;
}
135
2 hours 15 minutes
ประกาศตัวแปรตรงกลางโปรแกรมได้ ไม่จำเป็นต้องอยู่บรรทัดแรกของ main ประกาศตรงที่เริ่มใช้จะอ่านง่ายกว่า
วิธีเดียวกันใช้กับหน่วยอื่นได้ทุกแบบ เช่น วินาทีเป็นนาที เซนติเมตรเป็นเมตร วันเป็นสัปดาห์ ลองเปลี่ยนโปรแกรมนี้ให้แปลงวันเป็นกี่สัปดาห์กี่วันดู
แยกหลักของตัวเลข
โจทย์แนว "หาผลรวมของเลขโดด" หรือ "กลับหลักตัวเลข" ต้องแยกตัวเลขออกเป็นหลักๆ ก่อน ใช้ / กับ % ด้วย 10 ตามตารางนี้ ถ้า n คือ 472
| นิพจน์ | ได้ | ความหมาย |
|---|---|---|
n % 10 | 2 | หลักหน่วย |
n / 10 | 47 | ตัดหลักหน่วยทิ้ง |
n / 10 % 10 | 7 | หลักสิบ ตัดหลักหน่วยทิ้งก่อน แล้วเอาหลักขวาสุด |
n / 100 | 4 | หลักร้อย |
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
int hundreds = n / 100;
int tens = n / 10 % 10;
int ones = n % 10;
printf("%d %d %d\n", hundreds, tens, ones);
printf("sum = %d\n", hundreds + tens + ones);
return 0;
}
472
4 7 2
sum = 13
จำหลักไว้สองข้อ % 10 หยิบหลักขวาสุด / 10 ตัดหลักขวาสุดทิ้ง ตอนนี้โปรแกรมทำได้แค่เลขที่รู้จำนวนหลักล่วงหน้า พอเรียนวนซ้ำในบทที่ 4 จะใช้สองข้อนี้ซ้ำไปเรื่อยๆ จนแยกเลขกี่หลักก็ได้
ลองทำให้พัง
แบบที่ 1 ลืมวงเล็บ
หาค่าเฉลี่ยของคะแนนสองวิชา 80 กับ 90 คำตอบที่ถูกคือ 85
#include <stdio.h>
int main()
{
int math = 80, science = 90;
printf("%d\n", math + science / 2);
return 0;
}
125
compiler ไม่เตือนอะไรเลย เพราะโค้ดถูกไวยากรณ์ทุกอย่าง แค่ไม่ใช่สิ่งที่เราตั้งใจ หารทำก่อนบวก จึงได้ 80 + 45 = 125 แก้เป็น (math + science) / 2 จะได้ 85 ความผิดพลาดแบบนี้อันตรายกว่า error เพราะไม่มีอะไรบอก ต้องลองคิดคำตอบด้วยมือแล้วเทียบเอง
แบบที่ 2 หารด้วยศูนย์
โปรแกรมแบ่งลูกอม รับจำนวนลูกอมกับจำนวนคน แล้วพิมพ์ว่าได้คนละกี่เม็ด ส่วนสำคัญคือสองบรรทัดนี้
scanf("%d %d", &total, &people);
printf("%d\n", total / people);
คอมไพล์ผ่านโดยไม่มีคำเตือน เพราะตอนคอมไพล์ยังไม่รู้ว่า people จะเป็น 0 แต่พอรันแล้วป้อน 10 0 โปรแกรมปิดตัวทันทีโดยไม่พิมพ์อะไร Code::Blocks ขึ้นว่า
Process returned -1073741676 (0xC0000094)
ปกติเลขหลัง Process returned คือ 0 ถ้าเห็นเลขติดลบแปลกๆ แปลว่าโปรแกรมพังกลางทาง 0xC0000094 คือรหัสของ Windows ที่แปลว่าหารจำนวนเต็มด้วยศูนย์ ถ้าส่งโปรแกรมแบบนี้ให้ grader ข้อนั้นจะได้ผลว่า runtime error ใช้ % ด้วย 0 ก็พังแบบเดียวกัน
แบบที่ 3 ใช้ ++ กับตัวแปรเดียวกันซ้ำ
int count = 5;
count = count++;
count.c:6:11: warning: operation on 'count' may be undefined [-Wsequence-point]
6 | count = count++;
| ~~~~~~^~~~~~~~~
บรรทัดนี้ทั้งกำหนดค่าให้ count และเพิ่มค่า count ในคำสั่งเดียว มาตรฐานภาษา C ไม่ได้กำหนดว่าอะไรต้องเกิดก่อน (undefined แปลว่าไม่ได้กำหนด) compiler แต่ละตัวจึงให้ผลต่างกันได้ บนเครื่องที่เขียนเอกสารนี้พิมพ์ count ออกมาได้ 5 ไม่ใช่ 6 อย่างที่หลายคนคาด ถ้าต้องการเพิ่มค่าหนึ่ง เขียน count++; อย่างเดียวพอ
สรุป
+ - * / %คือบวก ลบ คูณ หาร เศษint / intตัดทศนิยมทิ้ง%ให้เศษที่ถูกตัด% 10หยิบหลักขวาสุด/ 10ตัดหลักขวาสุดทิ้ง- คูณหารก่อนบวกลบ ลำดับเท่ากันทำจากซ้ายไปขวา ไม่แน่ใจใส่วงเล็บ
x += 5คือx = x + 5และx++คือเพิ่มหนึ่ง ใช้เป็นคำสั่งเดี่ยวๆ- หารหรือ mod ด้วย 0 ทำให้โปรแกรมพังตอนรัน