STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • Bình luận
    • Sao chép

    Nhập Xuất Cơ Bản trong C

    Tìm hiểu về thao tác nhập xuất cơ bản trong C.

    Rye Nguyen

    28/07/2015
    11/09/2020
    7 phút đọc
    Nhập Xuất Cơ Bản trong C

    Trong bất cứ một ngôn ngữ lập trình nào, việc tương tác trực tiếp với máy tính là rất quan trọng và cần thiết. Một chương trình được viết ra cần có khả năng nhận dữ liệu từ người dùng và hiển thị những kết quả thu được sau tính toán. Do đó việc thành thạo trong việc nhập/xuất dữ liệu là điều không thể thiếu đối với mỗi lập trình viên. Bài viết này sẽ giúp hiểu rõ hơn về thao tác nhập/xuất dữ liệu thông qua phương tiện nhập xuất chuẩn.

    Tổng quan

    Trong C hay bất cứ ngôn ngữ lập trình nào khác, việc nhập, xử lý và xuất dữ liệu có thể được thực hiện theo hai cách:

    • Thông qua phương tiện nhập/xuất chuẩn (Standard Input/Output).
    • Thông qua tập tin (File)

    Bài viết này sẽ chỉ đề cập đến Standard Input/Output.

    Thư viện nhập xuất chuẩn trong C là <stdio.h>, do đó các lập trình viên cần khai báo thư viện này trước khi thực hiện việc nhập xuất dữ liệu bằng chỉ thị #include.

    <stdio.h> cung cấp cho hai hàm nhập và xuất dữ liệu có định dạng:

    • printf(): Hàm xuất có định dạng.
    • scanf(): Hàm nhập có định dạng.

    Output với printf

    Hàm printf trong C có nguyên mẫu của hàm (prototype) như sau:

    int printf(“<chuỗi định dạng>”, <danh sách tham số>);

    Trong đó, int là kiểu trả về của hàm, là giá trị đại diện cho hàm sau khi hết phạm vi của hàm. Chuỗi định dạng (Format string) có nhiệm vụ định dạng dữ liệu xuất ra màn hình. Danh sách tham số có thể bao gồm biến, hằng số, biểu thức và hàm (function) và được phân cách bằng dấu “,”.

    Chuỗi định dạng

    Chuỗi định dạng phải tương ứng với danh sách tham số về số lượng, kiểu dữ liệu và thứ tự. Chuỗi định dạng luôn được đặt bên trong cặp dấu “” và bao gồm một hoặc nhiều thành phần sau:

    • Ký tự văn bản (Text characters): là những ký tự in được, bao gồm các chữ cái, chữ số và các ký tự đặc biệt trong bảng mã ASCII.
    • Các ký tự không in được: bao gồm một số ký tự điều khiển như tab (\t), xuống dòng (\n), khoảng trắng, … Khoảng trắng thường được sử dụng để phân cách các trường (field) dữ liệu được xuất ra.
    • Lệnh định dạng: là các lệnh quy định cách mà dữ liệu được xuất ra màn hình.

    Lệnh định dạng có cấu trúc như sau:

    %[flags][width][.precision][length]specifier

    Trong đó, flags, width, .precision, length là một số bổ từ tùy chọn để thay đổi đặc tả gốc cho phù hợp với mong muốn của lập trình viên.

    Specifier là đặc tả cho kiểu dữ liệu. Một số đặc tả thường dùng:

    d, i Số nguyên có dấu
    u Số nguyên không dấu
    f Số thực
    c Ký tự
    s Chuỗi ký tự


    Ngoài ra còn một số bổ từ và lệnh định dạng khác đề cập đến.

    #include <stdio.h>
    
    int main ()
    {
        printf ("String only\n"); //'\n' isn't shown
        printf ("%s\n", "Also string");    
        printf ("int, float, char: %d, %f, %c\n", 7411, 3.14, 'R');
        printf ("Preceding with blanks: d\n", 7411);
        printf ("float rounding: %.2f\n", 3.1415929);
    
        return 0;
    }

    Input với scanf

    Prototype của hàm scanf trong C như sau:

    int scanf(“<chuỗi định dạng>”, <danh sách tham số>);

    Tương tự như hàm printf, danh sách tham số của scanf cũng được phân cách bằng dấu “,”. Tuy nhiên, tham số phải được truyền vào dưới dạng tham chiếu, tức truyền vào địa chỉ của biến. Tham chiếu của các kiểu dữ liệu cơ bản (primitive data type) như int, float, char, … là & (address-of operator) cùng với tên biến. Đối với các kiểu dữ liệu dẫn xuất (ví dụ như chuỗi ký tự), tham chiếu đơn giản là tên biến.

    Chuỗi định dạng

    Chuỗi định dạng của hàm scanf có thể bao gồm những thành phần sau:

    • Whitespace character: bao gồm khoảng trắng, ký tự xuống dòng và tab. Hàm scanf sẽ tự động bỏ qua bất kỳ whitespace character nào có mặt trong chuỗi định dạng.
    • Lệnh định dạng: có chức năng định dạng dữ liệu nhập vào từ bàn phím. Nó sẽ quyết định nhận lượng dữ liệu bao nhiêu cho biến tương ứng.
    • Các ký tự khác: dùng để phân cách các lệnh định dạng. Các ký tự này dùng để nhập vào dữ liệu một cách có định dạng (ví dụ như ngày tháng năm). Khi nhập bắt buộc phải nhập đúng theo định dạng đó. Do đó chỉ nên sử dụng trong một số trường hợp đơn giản, quen thuộc và phải có chú thích để người sử dụng không bị nhầm lẫn.

    Tương tự như hàm printf, chuỗi định dạng của scanf có cấu trúc như sau:

    %[*][width][length]specifier

    Hiện thực ví dụ sau để nắm được cách sử dụng hàm scanf cũng như các lệnh định dạng thông dụng:

    #include <stdio.h>
    
    int main ()
    {
        printf ("Welcome to Stdio!\n");
    
        int a;
        float b;
        printf ("Enter an integer and a float: ");
        scanf ("%d   %f", &a, &b);
        printf ("The integer you've entered is %d\nThe float you've entered is %f\n", a, b);
    
        char *s = new char[100];
        printf ("Enter a string: ");
        scanf ("%s", s);
        printf ("The string you've entered is %s\n", s);
        delete[] s;
    
        int dd, mm, yyyy;
        printf ("Enter a date: "); //Format: dd/mm/yyyy
        scanf ("%d/%d/%d", &dd, &mm, &yyyy);
        printf ("The date you've entered is %2d/%2d/%4d\n", dd, mm, yyyy);
    
        return 0;
    }

    Một số vấn đề thường gặp

    Không truyền tham chiếu vào hàm scanf

    Đây là lỗi thường gặp nhất. Với những project nhỏ thì lỗi này có thể phát hiện được dễ dàng. Tuy nhiên, khi làm việc với những dự án lớn, việc phát hiện và khắc phục lỗi này là cực kỳ khó khăn, vì đây không phải là lỗi trong quá trình Build nên không xác định được vị trí dòng code bị lỗi. Do đó lỗi này là đặc biệt nghiêm trọng và cần được khắc phục trong quá trình học tập.

    Cách khắc phục: thêm toán tử & vào trước tên biến (primitive data type).

    Undeclared variables/Uninitialize variables

    Sử dụng biến mà không khai báo hoặc quên khởi tạo giá trị ban đầu cho biến. Đây không phải là lỗi nghiêm trọng và rất dễ khắc phục, tuy nhiên nó cho thấy sự thiếu cẩn thận trong công việc, hãy cố gắng khắc phục sớm.

    Trôi dòng lệnh khi xử lý chuỗi

    Trong C, dòng (stream) vào tiêu chuẩn là stdin. Các hàm như scanf, gets, getchar, … đều nhận dữ liệu từ stdin. Khi trên stdin không còn dữ liệu, các hàm nhập dữ liệu sẽ yêu cầu người dùng nhập vào từ bàn phím. Các hàm trên chỉ nhận đủ dữ liệu mà chúng yêu cầu (trong trường hợp này, scanf chỉ nhận chuỗi không có khoảng trắng), do đó một phần dữ liệu còn sót lại trên stdin, có thể là ký tự \n hoặc phần dữ liệu sau khoảng trắng. Điều này ảnh hưởng đến các hàm nhập dữ liệu phía sau.

    Có thể khắc phục bằng cách làm rỗng bộ đệm stdin trước mỗi hàm nhập để đảm bảo độ chính xác của chương trình. Câu lệnh như sau:

    fflush(stdin);

    Hàm fflush() nằm trong thư viện <stdio.h> nên có thể dễ dàng sử dụng mà không phải include thêm thư viện khác.

    Error C4996 trong Visual Studio 2012 về sau

    Từ Visual Studio 2012 về sau, một số hàm đã được Microsoft loại bỏ hoặc thay thế bởi những hàm tương tự. Lý do là những hàm này không còn an toàn nữa.

    Có khá nhiều cách khắc phục lỗi này, xin hướng dẫn một vài cách như sau:

    • Sử dụng các hàm được khuyến nghị bởi Microsoft. Các hàm này được hiển thị trong thông báo lỗi (scanf_s thay cho scanf, printf_s thay cho printf, …)
    • Khai báo thêm một cờ (flag) nhằm bỏ qua các cảnh báo này ở đầu chương trình. Khai báo như sau: #define _CRT_SECURE_NO_WARNINGS
    • Một cách khác nữa là tắt cảnh báo trực tiếp trong project. Vào Project Properties → Configuration Properties → C/C++ > Preprocessor. Tại dòng Preprocessor Definitions, chọn Edit và thêm dòng _CRT_SECURE_NO_WARNINGS. Nhấn OK để thay đổi có hiệu lực.

    Đọc thêm Compiler Warning C4996 và C Run-time Library hay _CRT_SECURE_NO_WARNINGS (CRT).

    Modern C++

    Modern C++

    STDIO Training - Đào Tạo Lập Trình C++.

    Phù hợp cho bạn

    Đề xuất

    Nhập Xuất Cơ Bản trong C++

    Nhập Xuất Cơ Bản trong C++

    Cung cấp các kiến thức cơ bản về nhập xuất chuẩn (standard input/output) ...

    Modern C++C++98

    03/08/2015

    Nhập Xuất Cơ Bản trong C/C++

    Nhập Xuất Cơ Bản trong C/C++

    Bài viết là tiền đề giúp cho người đọc làm quen các thao tác cơ bản với ...

    Modern C++C++98

    18/03/2016

    Khám phá thêm

    Thao Tác Với Chuỗi Trong C/C++

    Thao Tác Với Chuỗi Trong C/C++

    Kiến thức cơ bản trong thao tác xử lý chuỗi trong C++.

    Modern C++C++98

    28/07/2015

    9 Tính Năng Quan Trọng Trong C++11

    9 Tính Năng Quan Trọng Trong C++11

    C++11 là một phiên bản cải tiến và nâng cấp từ C++98 (hay các bạn vẫn ...

    Modern C++C++0x

    13/08/2015

    Xây Dựng Hàm có Tham Số Tuỳ Ý trong C

    Xây Dựng Hàm có Tham Số Tuỳ Ý trong C

    Hướng dẫn xây dựng hàm có tham số tuỳ ý trong C.

    Modern C++C++98

    03/08/2015

    Đọc Ghi File Cơ Bản Trong C#

    Đọc Ghi File Cơ Bản Trong C#

    Hướng dẫn đọc và ghi file cơ bản sử dụng đối tượng File trong C#. Nhờ có ...

    Bùi Trung Hiếu

    07/04/2016

    Sử Dụng Mảng Trong C++

    Sử Dụng Mảng Trong C++

    Tìm hiểu những kiến thức cơ bản về mảng dữ liệu và cách sử dụng mảng ...

    Modern C++C++98

    29/07/2015

    Bản Chất Của Biến Trong C/C++

    Bản Chất Của Biến Trong C/C++

    Tìm hiểu về bản chất của biến trong C++.

    Modern C++C++98

    16/01/2015

    std::thread trong C++

    std::thread trong C++

    Bài viết giúp người dùng nắm được cơ bản về thread, cách thức sử dụng ...

    Modern C++C++0x

    19/09/2017

    Định Dạng Ảnh Bitmap - Giới Thiệu và Các Thao Tác Cơ Bản

    Định Dạng Ảnh Bitmap - Giới Thiệu và Các Thao Tác Cơ Bản

    Trong đời thường, bạn sẽ gặp các file ảnh có định dạng .PNG, .JPG, .TGA, ...

    Phan Tấn Phúc

    13/09/2017

    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020