C โครงสร้างโปรแกรมและ printf



มาดูโปรแกรม C ทีละส่วนอย่างละเอียด

#include <stdio.h>

// นี่คือคอมเมนต์บรรทัดเดียว

/* คอมเมนต์
   หลายบรรทัด */

int main(void)
{
    int age = 30;
    printf("อายุ %d ปี\n", age);
    return 0;
}

#include

#include <stdio.h>

บอก preprocessor ให้ “แปะ” เนื้อหาของไฟล์ stdio.h ตรงนี้ ก่อนคอมไพล์จริง ไฟล์ .h (header) ส่วนใหญ่มีการ ประกาศ ฟังก์ชัน — บอกว่า printf รับอะไร คืนอะไร โดยไม่มีโค้ดจริง (โค้ดจริงอยู่ใน libc ที่ link ทีหลัง) header ยังใส่ #define มาโคร, typedef/struct/enum, และ static inline function ได้ด้วย (บทที่ 26)

  • #include <...> — header ของระบบ/ไลบรารีมาตรฐาน คอมไพเลอร์หาในที่ที่ติดตั้งไว้
  • #include "..." — header ของเราเอง คอมไพเลอร์หาในโฟลเดอร์เดียวกับไฟล์ก่อน

header มาตรฐานที่เจอบ่อย: <stdio.h> (I/O), <stdlib.h> (malloc, exit, atoi), <string.h> (strlen, strcpy), <math.h> (sqrt, pow)

ฟังก์ชัน main

int main(void)
{
    return 0;
}
  • ทุกโปรแกรม C เริ่มรันที่ main — OS เรียกมันให้
  • int ข้างหน้า = main คืนค่าเป็นจำนวนเต็ม ให้ OS
  • void ในวงเล็บ = ไม่รับ argument (แบบรับ argument คือ int main(int argc, char *argv[]) — บทที่ 24)
  • { } ครอบ ตัวฟังก์ชัน (function body)

return จาก main

return 0;

ค่าที่ main คืนคือ exit status ของโปรแกรม:

  • 0 = สำเร็จ
  • ไม่ใช่ 0 = มีข้อผิดพลาด (โปรแกรม CLI ใช้เลขต่างกันบอกชนิด error)

เช็คใน shell ได้:

./hello
echo $?          # พิมพ์ exit status ของคำสั่งล่าสุด

<stdlib.h> มีค่าคงที่ EXIT_SUCCESS (0) และ EXIT_FAILURE (มักเป็น 1) ใช้แทนตัวเลขดิบได้

ถ้าไม่เขียน return ใน main (เฉพาะ main เท่านั้น) C จะถือว่า return 0; ให้ — แต่เขียนให้ชัดดีกว่า

printf กับ format specifier

printf = “print formatted” สตริงแรกคือ format string ที่มี placeholder ขึ้นต้นด้วย % — ค่าจริงตามหลังมาตามลำดับ

#include <stdio.h>

int main(void)
{
    int count = 5;
    double price = 19.99;
    char grade = 'A';

    printf("จำนวน: %d\n", count);
    printf("ราคา: %.2f บาท\n", price);
    printf("เกรด: %c\n", grade);
    printf("%d ชิ้น ราคารวม %.2f\n", count, price * count);
    return 0;
}
จำนวน: 5
ราคา: 19.99 บาท
เกรด: A
5 ชิ้น ราคารวม 99.95

specifier ที่ใช้บ่อย

specifierใช้กับตัวอย่างผล
%dint42
%uunsigned int42
%ldlong100000
%ffloat / double3.140000
%.2fทศนิยม 2 ตำแหน่ง3.14
%cchar (ตัวเดียว)A
%sสตริง (char *)hello
%xเลขฐาน 162a
%ppointer (ที่อยู่)0x7ffe...
%%เครื่องหมาย % ตรง ๆ%

ปรับความกว้าง/การจัดชิด:

printf("%5d\n", 42);       // "   42"  (กว้าง 5 ชิดขวา)
printf("%-5d|\n", 42);     // "42   |" (ชิดซ้าย)
printf("%05d\n", 42);      // "00042"  (เติม 0)
printf("%8.2f\n", 3.14);   // "    3.14"

จับคู่ specifier กับชนิดให้ถูก

นี่คือกับดักใหญ่ของ C — printf ไม่ตรวจ ว่า specifier ตรงกับชนิดของค่าไหม ผิดแล้วได้ค่าขยะหรือโปรแกรมพัง:

double x = 3.14;
printf("%d\n", x);         // ❌ %d คาดหวัง int แต่ให้ double — undefined behavior (ไม่ใช่แค่ค่าเพี้ยน)
printf("%f\n", x);         // ✅ ถูก

-Wall จับกรณีนี้ได้: warning: format '%d' expects argument of type 'int', but argument 2 has type 'double'

putchar และ puts

พิมพ์แบบง่ายเมื่อไม่ต้อง format:

puts("บรรทัดนี้มี \\n ให้อัตโนมัติ");   // เติม \n ท้ายให้เอง
putchar('X');                            // พิมพ์ตัวอักษรตัวเดียว
putchar('\n');

เรื่องที่คนมักพลาด

  • specifier ไม่ตรงชนิด%d กับ double, %f กับ int, %s กับ int — ผลลัพธ์เพี้ยนหรือ crash เปิด -Wall ให้จับ
  • ลืม \n — output ติดกันหมด หรือไม่โผล่จนกว่าโปรแกรมจบ (เพราะ buffering)
  • %s กับตัวแปรที่ไม่ใช่สตริงที่ปิดด้วย '\0'printf อ่านต่อไปเรื่อย ๆ จนเจอ 0 หรือ segfault
  • จำนวน argument ไม่ตรงกับ %printf("%d %d\n", 5) อ่าน argument ตัวที่สองจากขยะบน stack
  • ใช้ // คอมเมนต์ในโค้ดที่ต้อง compile ด้วย -std=c89// เพิ่มมาใน C99 ถ้าใช้ c17 ไม่มีปัญหา
  • 'A' (single quote) กับ "A" (double quote) ต่างกัน'A' เป็น character constant ชนิด int ใน C (ค่า 65) เก็บลง char ได้; "A" คือสตริง 2 ไบต์ ('A' + '\0')

สรุป

  • #include <header.h> ดึงการประกาศฟังก์ชันเข้ามา (<> ระบบ, "" ของเรา)
  • int main(void) { ... return 0; } — จุดเริ่ม, return = exit status (0 = สำเร็จ)
  • printf("format", args...)%d int, %f/.2f double, %c char, %s string, %p pointer
  • specifier ต้องตรงชนิดของค่าเป๊ะ — printf ไม่ตรวจให้ ใช้ -Wall ช่วย
  • puts() / putchar() สำหรับพิมพ์ง่าย ๆ

บทถัดไปว่าด้วยตัวแปรและชนิดข้อมูลพื้นฐาน — int, char, float, double, sizeof และการรับค่าจากผู้ใช้