Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม C

ทำไม C Compiler ไม่อ่าน String หลัง Integer? (scanf Buffer Issue)


ปัญหา

หลัง scanf("%d", &num) แล้ว ใช้ gets() หรือ scanf("%s", str) อ่าน String → **ข้ามการอ่าน String ไปเลย**

สาเหตุ

  1. User พิมพ์เลข เช่น 42 แล้วกด Enter
  2. scanf("%d") อ่าน 42 แต่ **ทิ้ง \n (Newline) ไว้ใน Input Buffer**
  3. gets() / scanf("%s") อ่านเจอ \n ทันที → คิดว่าเป็น String ว่าง → จบการอ่าน

วิธีแก้ไข

วิธีที่ 1: ใช้ scanf("%c") อ่านทิ้ง Newline (Quick Fix)


int num;
char name[50], dummy;

scanf("%d", &num);
scanf("%c", &dummy); // อ่าน \n ทิ้ง
printf("Enter name: ");
fgets(name, sizeof(name), stdin);

วิธีที่ 2: ใช้ Space ใน Format String (แนะนำสำหรับ scanf)


scanf("%d", &num);
scanf(" %s", name); // Space นำหน้า %s → ข้าม Whitespace ทั้งหมด

วิธีที่ 3: ใช้ fgets() ทั้งหมด + sscanf() (Best Practice)


char line[100];
int num;
char name[50];

fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &num);

fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = '\0'; // ลบ \n

ตัวอย่างโปรแกรมที่แก้ไขแล้ว

#include <stdio.h>
#include <string.h>

struct Student {
    int roll;
    char name[50];
};

int main() {
    struct Student s;
    
    printf("Enter roll number: ");
    scanf("%d", &s.roll);
    
    // วิธีแก้: อ่าน \n ทิ้ง
    getchar(); // หรือ scanf("%*c");
    
    printf("Enter name: ");
    fgets(s.name, sizeof(s.name), stdin);
    s.name[strcspn(s.name, "\n")] = '\0'; // ลบ newline
    
    printf("\n--- Student Info ---\n");
    printf("Roll: %d\n", s.roll);
    printf("Name: %s\n", s.name);
    
    return 0;
}

ผลลัพธ์:


Enter roll number: 3
Enter name: TutorialsPoint

--- Student Info ---
Roll: 3
Name: TutorialsPoint

สรุปวิธีแก้

วิธีCodeข้อดีข้อเสีย
getchar()getchar() หลัง scanfง่ายอ่านทิ้งแค่ 1 Char
Space in formatscanf(" %s", str)สั้น กระชับใช้ได้กับ %s %c %[...] เท่านั้น
fgets + sscanffgets → sscanfปลอดภัยที่สุด ควบคุมได้ดีโค้ดยาวกว่า

⚠️ ห้ามใช้ gets()

gets() ถูก Deprecated และลบออกจาก C11** เพราะไม่มี Bounds Checking → Buffer Overflow Vulnerability

ใช้ fgets() แทนเสมอ