warning

รวมข้อควรระวังและข้อแนะนำในการเขียนโปรแกรม

การใช้ #define

หลีกเลี่ยงการใช้ #define ให้ได้มากที่สุด โดยเฉพาะการกำหนดค่าคงที่ ใช้ const แทน

  1. นายโบ๊ต (นามสมมุติ) กำหนดค่า INF โดย #define INF -1u/2 (อ่านสารพัดค่า INF หากไม่เข้าใจ) เนื่องจาก -1u/2 เป็น unsigned จึงไม่สามารถติดลบได้ เมื่อเขาเรียกใช้ -INF จึงทำให้เกิดโศกนาฏกรรมขึ้น ทั้งๆที่ถ้าเขาใช้ const int INF = -1u/2; ก็จะไม่เกิดโศกนาฏกรรมแล้วแท้ๆ
  2. มาโคร #define MAX(_a,_b) ((_a > _b) ? _a : _b) ทำงานได้ดีเยี่ยมมาโดยตลอด จนกระทั่งเมื่อมีคนเรียกใช้ MAX(10, rand()) โค้ดจะเปลี่ยนจาก MAX(10, rand()) ไปเป็น ((10 > rand()) ? 10 : rand()) สมมุติว่าครั้งแรก rand() ออกมาได้ 11 และครั้งที่สอง rand() ออกมาได้ 9 จึงกลายเป็นว่าค่ามากสุดของ 10 และ 11 คือ 9 ??? อันที่จริงสำหรับ abs, max, min แนะนำให้ใช้ STL algorithm แทน

ค่าของ infinity

ควรใช้ค่า INF เป็น 109 + 21 เนื่องจากโจทย์ส่วนใหญ่บนโลกนี้ใช้ค่ามากสุดคือ 109 หรือ 109 + 7 ค่านี้จึงน่าจะมากพอที่จะเป็น INF ได้ ไม่ควรให้ INF = 231 - 1 ยกเว้นจำเป็นจริงๆ ตรวจสอบ datatype ของค่า INF ให้ดี และแนะนำให้ใช้ const กำหนดค่า INF

  1. ตัวอย่างเดิมของนายโบ๊ต (นามสมมุติ) กรุณาตรวจสอบให้ดีว่าค่า INF มี datatype ที่เหมาะสม
  2. ให้ INF = 231 - 1 หลังจากเขียน Floyd–Warshall algorithm เสร็จ ก็พบว่าโค้ดรันแล้วผิด เพราะบรรทัด

d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

ได้ค่า d[i][j] เพี้ยน หลังจากวิเคราะห์จึงพบว่า d[i][k] = INF และ d[k][j] = INF ทำให้ d[i][k] + d[j][k] เกินค่าพิสัย int เกิด integer overflow และกลายเป็นค่าติดลบแทน !!! จากที่ d[i][j] ควรจะบ่งบอกว่าไม่มีทางจาก i ไป j เลยกลายเป็นมีค่าที่บอกว่ามีเส้นทาง(ที่น่าไปมากๆ) T^T

รับอักขระ

หลีกเลี่ยงการรับอักขระด้วย scanf "%c" ไปใช้ "%s" แทน

  1. %c รับทุกๆอย่างบนโลกใบนี้ ทั้ง '\n', ' ', EOF และทุกอย่างที่อยู่ขวางหน้ามัน จึงเป็นไปได้สูงมากๆที่การใช้ scanf "%c" จะได้ค่าไม่พึงประสงค์ออกมา ดังนั้นใช้ "%s" แทน "%c" ในทุกๆกรณี

STL list และ size()

ฟังก์ชั่น size() ใช้เวลา $O(n)$ นะ ไม่ใช่ $O(1)$ (อันที่จริง compiler บางตัวก็ $O(1)$ นะ)

เปรียบเทียบจำนวนจริง

หากจะเปรียบเทียบว่าจำนวนจริงสองตัวเท่ากันหรือไม่ (รวมถึง $\le$ และ $\ge$ ด้วย) แนะนำให้เขียนฟังก์ชั่นขึ้นมา

const double EPS = 1e-9;
inline bool f_equal(double a, double b){ return abs(a - b) < EPS; }

โดย EPS คือค่าที่น้อยมากๆที่น้อยกว่าความแตกต่างที่น้อยที่สุดที่อาจเกิดขึ้นได้จากการเขียนโปรแกรมของเรา แต่ยังมากกว่ากว่าความผิดพลาดจากการแทนค่าจำนวนจริง
  1. 0.3 + 0.6 == 0.9 ?? คำตอบคือไม่ วิธีการแทนค่าจำนวนจริงทำให้ 0.3, 0.6, 0.9 คลาดเคลื่อนเล็กน้อย ดังนั้นเมื่อนำมาเปรียบเทียบกันจึงอาจไม่เท่ากัน
  2. 1/1000000000 != 1/2000000000 ??? คำตอบคือไม่ หากมี a, b, c, d ที่เป็นจำนวนเต็มหมด และต้องการเปรียบเทียบ a/b กับ c/d ว่าอะไรน้อยกว่า (หรือมากกว่า หรือเท่ากัน) ให้ใช้การคูณไขว้ ระวังการคูณไขว้เกิด integer overflow ด้วย
typedef long long ll;
inline bool cmp(int a, int b, int c, int d) return ll(a) * ll(d) < ll(b) * ll(c);
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License