Thứ Bảy, 6 tháng 4, 2024

7.Nhập xuất dữ liệu- Printf và Scanf

Hãy hình dung một vài tình huống quen thuộc:
  • Bạn dùng bàn phím để Nhập văn bản, bài viết...vào chương trình Microsoft Word, sau đó bạn bấm lệnh Print để Xuất văn bản, bài viết đó ra máy in và in nó ra giấy.
  • Bạn dùng điện thoại iPhone để Nhập tin nhắn, sau đó bạn bấm Send để Xuất tin nhắn qua máy của người thân, bạn bè.
  • Bạn đăng nhập vào Facebook bằng cách Nhập tên và mật khẩu, Facebook sẽ Xuất ra trả lời là sai mật khẩu nếu bạn nhập sai mật khẩu, hoặc Xuất ra màn hình chính của Facebook nếu bạn đăng nhập thành công.
  • Bạn chơi games Candy Crush bằng cách Nhập một vị trí mới của các viên kẹo, chương trình sẽ Xuất ra màn hình kết quả tiếp theo.

Việc nhập xuất dữ liệu là công việc đầu tiên cần thành thạo khi bạn học một ngôn ngữ lập trình bất kỳ, phần này chúng ta sẽ phân tích cách sử dụng hàm printf scanf trong C để thực hiện 2 công việc nhập và xuất dữ liệu.
Dù mới trải qua phần làm quen, cưỡi ngựa xem hoa, nhưng chúng ta đã kịp "vọc" khá nhiều với hàm printf từ chương trình Hello World! cho tới "chương trình tào lao" của chúng ta.

Nhắc lại về hàm:  Hàm là tập hợp những đoạn mã dùng để thực hiện một nhiệm vụ nào đó. Có những hàm được viết sẵn, có những hàm chúng ta cần phải viết. Muốn sử dụng hàm viết sẵn, ta phải dùng các lệnh tiền xử lý để gọi thư viện có chứa hàm đó.

Xuất dữ liệu:

Để in dữ liệu hay hiển thị kết quả ra màn hình bạn cần sử dụng hàm printf trong thư viện stdio.h

Cú pháp : printf("Chuỗi định dạng", Đối số);

Trong đó :

    Chuỗi định dạng Đó là một chuỗi chỉ định dữ liệu sẽ được in vì vậy nó luôn luôn nằm giữa hai dấu ngoặc kép (" "). Nó cũng có thể chứa một bộ xác định định dạng (Format Specifiers) để in giá trị của bất kỳ biến nào, chẳng hạn như ký tự và số nguyên.
    Đối số : Đây là các tên biến tương ứng với bộ xác định định dạng.

    Dấu phẩy (,) luôn phải có để ngăn cách chuỗi nằm giữa hai dấu ngoặc kép (" ") và đối số.


Khi bạn in ra giá trị của các biến số ra màn hình thì bạn cần truyền Format Specifiers của nó vào phần chuỗi định dạng và tên biến vào phần đối số, sử dụng kí tự "\n" khi bạn muốn xuống dòng.  

Khi "quậy" với chương trình tào lao của chúng ta chúng ta đã dùng chuỗi định dạng %d để in đối số int so; và chúng ta dùng chuỗi định dạng %s để in đối số char namtoi[]...

Cùng ngắm lại đứa con tinh thần "chương trình tào lao"

 

/* Đây là chương trình tào lao */

#include <stdio.h>

int main()
{

    int so = 2024; // Đây là biến số

    char namtoi[] = "Năm 2025";  // Đây là biến chuỗi

 
    printf("Xin Chào ! \n");
    printf("Rất vui gặp bạn!");
    printf("Năm nay là %d \n", so);
    printf("Năm tới là %s", namtoi);


    return 0;
}

 

Tóm lại: 

  • Nếu không có nhu cầu in ra mà hình một đối số hay một biến nào đó, chúng ta đơn giản cho chuỗi mà chúng ta muốn in vào giữa hai dấu ngoặc kép (" "), sau đó dùng lệnh printf để in, ví dụ lệnh printf đầu tiên và thứ hai trong chương trình tào lao.  
  • Nếu có nhu cầu in một đối số hay một biến nào đó ta cần truyền Format Specifiers của nó vào phần chuỗi định dạng, thả chuỗi định dạng vào giữa hai dấu ngoặc kép (" "), dùng dấu phẩy để ngăn cách và nhập đối số hay biến tương ứng vào, ví dụ lệnh thứ ba và thứ tư trong chương trình tào lao.

Chú ý : Khi in ra giá trị của số thực float double, chúng ta sẽ có yêu cầu in ra kết quả với một vài chữ số phần thập phân. Xác định định dạng của float là %f và của double là %lf, cú pháp để in ra x chữ số sau dấu phẩy đối với float và double ta sử dụng xác định định dạng %.xf hoặc %.xlf (lưu ý dấu chấm sau dấu %)

Chúng ta sẽ mần thử luôn với chương trình tào lao của chúng ta.

Ta sẽ thêm hai biến float và double

float a = 8.3462326543;
double b = 10.8745634535333;


Sau đó ta thêm hai lệnh in hai biến đó:

printf("In 4 chữ số sau dấu phẩy : %.4f\n", a);
printf("In 5 chữ số sau dấu phẩy : %.5lf\n", b);


Chương trình tào lao sau khi rờ tút lại sẽ có hình dáng sau: 


/* Đây là chương trình tào lao */

#include <stdio.h>

int main()
{

    int so = 2024; // Đây là biến số

    char namtoi[] = "Năm 2025";  // Đây là biến chuỗi

    float a = 8.3462326543;
    double b = 10.8745634535333;


 
    printf("Xin Chào ! \n");
    printf("Rất vui gặp bạn!");
    printf("Năm nay là %d \n", so);
    printf("Năm tới là %s", namtoi);

    printf("In 4 chữ số sau dấu phẩy : %.4f\n", a);
    printf("In 5 chữ số sau dấu phẩy : %.5lf\n", b);
 


    return 0;
}

Bấm Run để chạy thử chương trình (chúng ta vẫn sử dụng IDE online), ta sẽ thấy kết quả đúng như mong muốn.


Đất Việt Lập Trình


Nhập dữ liệu:

Hàm scanf nhận giá trị của biến từ bàn phím.

Cú pháp : scanf("Xác định định dạng", &biến);

Khi bạn nhập giá trị cho 1 biến từ bàn phím bạn cần truyền xác định định dạng của nó vào phần chuỗi định dạng, kèm theo dấu & trước tên biến. Dấu & này thể hiện địa chỉ của biến trong bộ nhớ, hiểu đơn giản là mỗi khi bạn nhập giá trị cho biến từ bàn phím thì hàm scanf sẽ tìm đến địa chỉ của biến đó trong bộ nhớ để gán cho nó giá trị mà bạn đã nhập từ bàn phím.

Mỗi khi nhập xong giá trị cho 1 biến bạn ấn enter thì giá trị này mới thật sự được gán cho biến tương ứng, có nghĩa là nếu chưa ấn enter, biến chưa được gán.

Chúng ta tiếp tục xào nấu chương trình tào lao.

  • Chúng ta thêm một biến kiểu dữ liệu int tên là n: int n;
  • Sau đó chúng ta in dòng chữ "Hãy nhập một số từ 1-100:" : printf("Hãy nhập một số từ 1-100:  ");
  • Tiếp theo là lệnh scanf,  vì biến n có kiểu dữ liệu int nên xác định định dạng sẽ là %d, khi chương trình chạy đến đây, nó sẽ dừng lại đợi người dùng nhập giá trị và ấn enter, nếu người dùng không làm gì chúng ta sẽ chỉ thấy dòng chữ "Hãy nhập một số từ 1-100". Nói cách khác chương trình sẽ không kết thúc: scanf("%d", &n);
  • Cuối cùng ta sẽ in ra kết quả: printf("Gía trị của n là : %d\n", n);

Đây là hình dáng của chương trình sau khi thêm các lệnh trên.

 

/* Đây là chương trình tào lao */

#include <stdio.h>

int main()
{

    int so = 2024; // Đây là biến số

    char namtoi[] = "Năm 2025";  // Đây là biến chuỗi

    float a = 8.3462326543;
    double b = 10.8745634535333;

    int n;

 
    printf("Xin Chào ! \n");
    printf("Rất vui gặp bạn!");
    printf("Năm nay là %d \n", so);
    printf("Năm tới là %s", namtoi);

    printf("In 4 chữ số sau dấu phẩy : %.4f\n", a);
    printf("In 5 chữ số sau dấu phẩy : %.5lf\n", b);
   
printf("Hãy nhập một số từ 1-100:  ");

    scanf("%d", &n);

    printf("Gía trị của n là : %d\n", n);

 
    return 0;
}

 

Bấm Run để chạy, ta sẽ thấy con trỏ nhấp nháy sau dòng chữ "Hãy nhập một số từ 1-100" 

 


 

Chúng ta cần nhập một số vào, ví dụ 9, ấn Enter, khi đó chương trình mới cho ra kết quả và kết thúc




Chạy lại chương trình một lần nữa, tại vị trí con trỏ nhấp nháy bạn thử nhập một chữ cái thay vì con số, ví dụ a, bạn sẽ thấy kết quả là 0, dùng bạn có nhập a hay b hay c....thì kết quả đều là 0

Chú Ý Khi Nhập Một Ký Tự

Để nhập một ký tự từ bàn phím bạn có thể dùng hàm scanf hoặc getchar(), khi chúng ta để nguyên chương trình tào lao và nhập ký tự a,c hay c...ta sẽ không được kết quả mong muốn vì ta đã quên sửa Xác định định dạng. Ta cần xác định định dạng là %c chứ không phải %d. Đồng thời biến để hàm scanf gán giá trị cũng phải đổi từ int sang char.

Ta sẽ thêm một biến kiểu char và "xào nấu" tiếp chương trình tào lao của chúng ta. Sau khi xào nấu, chương trình sẽ như sau

/* Đây là chương trình tào lao */

#include <stdio.h>

int main()
{

    int so = 2024; // Đây là biến số

    char namtoi[] = "Năm 2025";  // Đây là biến chuỗi

    float a = 8.3462326543;
    double b = 10.8745634535333;

    int n;

    char kitu;

 
    printf("Xin Chào ! \n");
    printf("Rất vui gặp bạn!");
    printf("Năm nay là %d \n", so);
    printf("Năm tới là %s", namtoi);

    printf("In 4 chữ số sau dấu phẩy : %.4f\n", a);
    printf("In 5 chữ số sau dấu phẩy : %.5lf\n", b);
   
printf("Hãy nhập một số từ 1-100:  ");

    scanf("%d", &n);

    printf("Gía trị của n là : %d\n", n);

    printf("Nhap mot ki tu : ");

     scanf("%c", &kitu);
    printf("Ký tự là : %c\n", kitu);

 
    return 0;
}

 

 

Tuy nhiên, đời không như là mơ, chương trình vẫn chạy ngon lành, nhưng chỉ lệnh scanf đầu tiên hoạt động. Chương trình bỏ qua lệnh scanf thứ hai.

 

Để hiểu rõ vấn đề, chúng ta thử chuyển kiểu dữ liệu của ký tự thành int thay vì char. Lưu ý thay %c thành %d.

Chương trình sẽ như thế này

/* Đây là chương trình tào lao */

#include <stdio.h>

int main()
{

    int so = 2024; // Đây là biến số

    char namtoi[] = "Năm 2025";  // Đây là biến chuỗi

    float a = 8.3462326543;
    double b = 10.8745634535333;

    int n;

    int kitu;

 
    printf("Xin Chào ! \n");
    printf("Rất vui gặp bạn!");
    printf("Năm nay là %d \n", so);
    printf("Năm tới là %s", namtoi);

    printf("In 4 chữ số sau dấu phẩy : %.4f\n", a);
    printf("In 5 chữ số sau dấu phẩy : %.5lf\n", b);
   
printf("Hãy nhập một số từ 1-100:  ");

    scanf("%d", &n);

    printf("Gía trị của n là : %d\n", n);

    printf("Nhap mot ki tu : ");

     scanf("%d", &kitu);
    printf("Ký tự là : %d\n", kitu);

 
    return 0;
}

Bấm Run để chạy, chương trình chạy ngon lành! Có nghĩa là nếu hai lệnh scanf ("%d",...) thì không có vấn đề, nhưng nếu sau lệnh scanf ("%d",...) là lệnh scanf ("%s",...) thì sẽ có vấn đề...?


 

Thật ra lỗi này không thể dùng cách thông thường kiểu như "loại trừ" để tìm ra được vì nó liên quan đến hiểu biết về hoạt động của hàm scanf.

Nếu bạn thay câu lệnh 

scanf("%c", &kitu);

Bằng câu lệnh (thêm một khoảng trắng phía trước %c)

scanf(" %c", &kitu);

Thì mọi chuyện được giải quyết! Bấm Run, chương trình sẽ chạy trơn tru!

 

Ta biết rằng lệnh scanf đi kèm với xác định định dạng bắt đầu bằng dấu %.

Có ba sự việc xảy ra khiến ta bị lỗi trong chương trình tào lao:

  • Khi ta nhập một số nào đó, ví dụ 8, sau đó ấn Enter scanf("%d") sẽ hiểu là số 8, nhưng việc ấn phím enter phát sinh ra ký tự "newline" trong bộ đệm
  • Tất cả các khoảng trắng trước bộ xác định định dạng, tức là trước dấu %, đều bị hàm scanf()  bỏ qua, ngoại trừ "%c", "%n" và "%[".
  • Nếu lệnh scanf() tiếp theo là đọc số nguyên int, thì ký tự newline bị bỏ qua, nhưng nếu đó là scanf("%c") thì lệnh scanf("%c") sẽ coi ký tự newline là ký tự nhập vào.


Có nghĩa là sau khi ta nhập số 8, ấn Enter, scanf("%d") sẽ hiểu là số 8 và cho kết quả đúng mong đợi. Tuy nhiên, việc ấn phím Enter phát sinh ra ký tự "newline" trong bộ đệm, vì scanf("%c") có nhiệm vụ đọc "ký tự" nên scanf("%c") sẽ ngay lập tức đọc ký tự dòng mới (newline) này và sau đó chương trình sẽ chuyển sang lệnh tiếp theo.

Nếu sau khi đọc ký tự newline, tiếp theo là khoảng trắng (whitespace) thì scanf("%c") sẽ hiểu là cần phải đợi! Đây không phải là cách tốt nhất, tuy nhiên chúng ta tạm dừng ở đây.
 

Đây là một bài khá dài, tuy nhiên hy vọng bạn sẽ thu nhập được nhiều kiến thức bổ ích. Bạn hãy cố gắng thực hành thật nhiều với hàm printf scanf . Chúng ta sẽ tiếp tục trong phần tiếp theo.


Phần tiếp theo

Phần trước

Không có nhận xét nào:

Đăng nhận xét