Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Lập Trình C

Nhập/Xuất chuỗi (String) trong C: scanf, gets, fgets, puts

Chuỗi trong C

Chuỗi là mảng ký tự kết thúc bằng ký tự null '\0' (ASCII 0).

Các hàm nhập/xuất chính

Hàm Header Đặc điểm Đọc khoảng trắng?
scanf("%s", s)stdio.hĐọc đến khoảng trắng/nullKhông
gets(s)stdio.hĐọc cả dòng, KHÔNG AN TOÀN (đã xóa C11)Có
fgets(s, n, stdin)stdio.hĐọc n-1 ký tự, an toàn, giữ newlineCó
puts(s)stdio.hIn chuỗi + tự thêm newline-
printf("%s", s)stdio.hIn chuỗi, không thêm newline-

Chương trình 1: scanf() - Chỉ đọc từ đơn

#include <stdio.h>

int main() {
    char ten[30];
    
    printf("Nhap ten: ");
    scanf("%s", ten);  // Dừng ở khoảng trắng
    
    printf("Ten ban: %s\n", ten);
    
    return 0;
}

Kết quả

Nhap ten: Nguyen Van A
Ten ban: Nguyen

→ Chỉ đọc được "Nguyen", phần "Van A" bị bỏ qua.

Chương trình 2: gets() - CẢNH BÁO: KHÔNG NÊN DÙNG

#include <stdio.h>

int main() {
    char ten[30];
    
    printf("Nhap ten: ");
    gets(ten);  // ĐỘC HẠI: không kiểm tra giới hạn buffer!
    
    printf("Ten ban: %s\n", ten);
    return 0;
}

Lý do không dùng gets(): Không kiểm tra độ dài → Buffer overflow → Lỗ hổng bảo mật nghiêm trọng. Đã bị xóa khỏi chuẩn C11.

Chương trình 3: fgets() - KHUYẾN NGHỊ (An toàn)

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

int main() {
    char ten[30];
    
    printf("Nhap ten: ");
    fgets(ten, sizeof(ten), stdin);  // Đọc tối đa 29 ký tự + '\0'
    
    // fgets giữ lại '\n' nếu còn chỗ, cần xóa nó
    ten[strcspn(ten, "\n")] = '\0';
    
    printf("Ten ban: %s\n", ten);
    
    return 0;
}

Kết quả

Nhap ten: Nguyen Van A
Ten ban: Nguyen Van A

Chương trình 4: puts() vs printf()

#include <stdio.h>

int main() {
    char s[] = "Hello World";
    
    printf("printf: ");
    printf("%s", s);      // Không tự xuống dòng
    printf(" <- het\n");
    
    printf("puts:   ");
    puts(s);              // Tự thêm '\n'
    printf(" <- het\n");
    
    return 0;
}

Kết quả

printf: Hello World <- het
puts:   Hello World
 <- het

Bảng so sánh chi tiết

Tiêu chí scanf("%s") gets() fgets()
Đọc khoảng trắngKhôngCóCó
Kiểm tra bufferKhông (nếu không dùng %29s)KhôngCó (tham số size)
Giữ newlineKhôngKhông (tự bỏ)Có (nếu đủ chỗ)
An toànTrung bìnhRất kémTốt
Chuẩn CC89C90 (xóa C11)C89

Best Practice

// Hàm helper đọc chuỗi an toàn
void docChuoi(char *buf, int size) {
    if (fgets(buf, size, stdin)) {
        buf[strcspn(buf, "\n")] = '\0';  // Xóa newline
    }
}

// Sử dụng
char ten[50];
docChuoi(ten, sizeof(ten));

Luôn dùng fgets() + xóa newline cho nhập chuỗi an toàn, chuyên nghiệp.