Bài 6:Nhập và Xuất trong C [Lý Thuyết]
Mục tiêu:
Kết thúc bài học này,
bạn có thể:
Ø Hiểu các hàm nhập xuất có định dạng scanf() và
printf()
Ø Sử dụng các hàm nhập xuất ký tự getchar() và
putchar().
Giới thiệu
Trong bất kỳ ngôn ngữ
lập trình nào, việc nhập giá trị cho các biến và in chúng ra sau khi xử lý có
thể được làm theo hai cách:
1. Thông qua phương tiện nhập/xuất
chuẩn (I / O).
2. Thông qua những tập tin.
Trong phần này ta sẽ nói
về chức năng nhập và xuất cơ bản. Nhập và xuất (I/O) luôn là các thành phần
quan trọng của bất kỳ chương trình nào. Ðể tạo tính hữu ích, chương trình của
bạn cần có khả năng nhập dữ liệu vào và hiển thị lại những kết quả của nó.
Trong C, thư viện chuẩn
cung cấp những thủ tục cho việc nhập và xuất. Thư viện chuẩn có những hàm quản
lý các thao tác nhập/xuất cũng như các thao tác trên ký tự và chuỗi. Trong bài
học này, tất cả những hàm nhập dùng để đọc dữ liệu vào từ thiết bị nhập chuẩn
và tất cả những hàm xuất dùng để viết kết quả ra thiết bị xuất chuẩn. Thiết bị
nhập chuẩn thông thường là bàn phím. Thiết bị xuất chuẩn thông thường là màn
hình (console). Nhập và xuất ra có thể được định hướng đến tập tin hay từ tập
tin thay vì thiết bị chuẩn. Những tập tin có thể được lưu trên đĩa hay trên bất
cứ thiết bị lưu trữ nào khác. Dữ liệu đầu ra cũng có thể được gửi đến máy in.
6.1
Tập tin tiêu đề <stdio.h>
Trong các ví dụ trước,
ta đã từng viết dòng mã sau:
#include <stdio.h>
Ðây là lệnh tiền xử lý (preprocessor
command). Trong C chuẩn, ký hiệu # nên đặt tại cột đầu tiên. stdio.h là
một tập tin và được gọi là tập tin tiêu đề (header). Nó chứa
các macro cho nhiều hàm nhập và xuất được dùng trong C. Hàm printf(), scanf(), putchar() và getchar() được thiết kế theo cách gọi các macro trong tập
tin stdio.h để thực thi các công việc tương ứng.
6.2
Nhập và xuất trong C (Input and Output)
Thư viện chuẩn trong C
cung cấp hai hàm để thực hiện các yêu cầu nhập và xuất có định dạng. Chúng là:
·
printf() – Hàm xuất có định dạng.
·
scanf() – Hàm nhập có định dạng.
Những hàm này gọi là
những hàm được định dạng vì chúng có thể đọc và in dữ liệu ra theo các định
dạng khác nhau được điều khiển bởi người dùng. Bộ định dạng qui định dạng
thức mà theo đó giá trị của biến sẽ được nhập vào và in ra.
6.2.1 printf()
Chúng ta đã quen thuộc với hàm này qua các phần trước. Ở đây, chúng ta sẽ xem chúng chi tiết hơn. Hàm printf() được dùng để hiển thị dữ liệu trên thiết bị xuất chuẩn – console (màn hình). Dạng mẫu chung của hàm này như sau:
printf("control string", argument list);
Danh sách tham số
(argument list) bao gồm các hằng, biến, biểu thức hay hàm và được phân cách
bởi dấu phẩy. Cần phải có một lệnh định dạng nằm trong chuỗi điều khiển (control
string) cho mỗi tham số trong danh sách. Những lệnh định dạng
phải tương ứng với danh sách các tham số về số lượng, kiểu dữ liệu và thứ tự.
Chuỗi điều khiển phải luôn được đặt bên trong cặp dấu nháy kép“”, đây
là dấu phân cách (delimiters). Chuỗi điều khiển chứa một hay nhiều hơn
ba thành phần dưới đây :
§ Ký tự văn bản (Text characters) – Bao gồm các ký tự có thể in ra được và
sẽ được in giống như ta nhìn thấy. Các khoảng trắng thường được dùng trong việc
phân chia các trường (field) được xuất ra.
§ Lệnh định dạng - Định nghĩa cách thức các mục dữ liệu trong danh
sách tham số sẽ được hiển thị. Một lệnh định dạng bắt đầu với một ký hiệu % và
theo sau là một mã định dạng tương ứng cho mục dữ liệu. Dấu % được
dùng trong hàm printf() để chỉ ra các đặc tả chuyển đổi. Các
lệnh định dạng và các mục dữ liệu tương thích nhau theo thứ tự và kiểu từ trái
sang phải. Một mã định dạng thì cần thiết cho mọi mục dữ liệu cần in ra.
§ Các ký tự không in được – Bao gồm phím tab, dấu khoảng trắng và
dấu xuống dòng.
Mỗi lệnh định dạng gồm
một hay nhiều mã định dạng. Một mã định dạng bao gồm ký hiệu % và một bộ định kiểu. Bảng 6.1 liệt kê các mã định dạng khác
nhau được hỗ trợ bởi câu lệnh printf():
Ðịnh
dạng
|
printf()
|
scanf()
|
Ký tự đơn (Single Character)
|
%c
|
%c
|
Chuỗi (String)
|
%s
|
%s
|
Số nguyên có dấu (Signed decimal
integer)
|
%d
|
%d
|
Số thập phân có dấu chấm động
(Floating point)
|
%f
|
%f hoặc %e
|
Số thập phân có dấu chấm động -
Biểu diễn phần thập phân
|
%lf
|
%lf
|
Số thập phân có dấu chấm động -
Biểu diễn dạng số mũ
|
%e
|
%f hoặc %e
|
Số thập phân có dấu chấm động
(%f hoặc %e, con số nào ít hơn)
|
%g
|
|
Số nguyên không dấu (Unsigned
decimal integer)
|
%u
|
%u
|
Số thập lục phân không dấu (Dùng
“ABCDEF”)
(Unsigned hexadecimal integer)
|
%x
|
%x
|
Số bát phân không dấu (Unsigned
octal integer)
|
%o
|
%o
|
Bảng 6.1: Mã định dạng trong printf ()
Trong bảng trên, c,
d, f, lf, e, g, u, s, o và x là bộ định kiểu.
Các quy ước in cho các
mã định dạng khác nhau được tổng kết trong Bảng 6.2:
Mã
định dạng
|
Quy
ước in ấn
|
%d
|
Các con
số trong số nguyên.
|
%f
|
Phần số nguyên của số sẽ được in
nguyên dạng. Phần thập phân sẽ chứa 6 con số. Nếu phần thập phân của con số
ít hơn 6 số, nó sẽ được thêm các số không (0) bên phải hay gọi là làm tròn
phía bên phải.
|
%e
|
Một con số bên trái dấu chấm thập
phân và 6 con số bên phải giống như %f.
|
Bảng 6.2: Quy ước in
Bởi vì các ký hiệu %,\
và “ được dùng đặc biệt
trong chuỗi điều khiển, nếu chúng ta cần in các ký hiệu này lên màn hình, chúng
phải được dùng như trong Bảng 6.3:
\\
|
In
ký tự \
|
\ “
|
In
ký tự “
|
%%
|
In
ký tự %
|
Bảng 6.3: Các ký tự đặc biệt trong chuỗi điều khiển
Bảng dưới đây đưa ra vài
ví dụ sử dụng chuỗi điều khiển và mã định dạng khác nhau.
Số
|
Câu
lệnh
|
Chuỗi
điều khiển
|
Nội
dung mà chuỗi điều khiển chứa đựng
|
Danh
sách tham số
|
Giải
thích danh sách tham số
|
Hiển
thị trên màn hình
|
1.
|
printf("%d", 300);
|
%d
|
Chỉ chứa lệnh định dạng
|
300
|
Hằng
số
|
300
|
2.
|
printf("%d", 10+5);
|
%d
|
Chỉ chứa lệnh định dạng
|
10
+ 5
|
Biểu
thức
|
15
|
3.
|
printf("Good Morning
Mr. Lee.");
|
Good
Morning Mr. Lee.
|
Chỉ là các ký tự văn bản
|
Không
có (Nil)
|
Không
có
|
Good
Morning Mr. Lee.
|
4.
|
int count =
100;
printf("%d", count);
|
%d
|
Chỉ chứa lệnh định dạng
|
Count
|
Biến
|
100
|
5.
|
printf("\nhello");
|
\nhello
|
Chỉ là các ký tự văn bản và ký tự
không in được.
|
Không
có
|
Không
có
|
Hello
(Trên
dòng mới)
|
6.
|
#define str "Good
Apple"
……..
printf("%s", str);
|
%s
|
Chỉ chứa lệnh định dạng
|
Str
|
Hằng
chuỗi
|
Good
Apple
|
7.
|
……..
int count,stud_num;
count = 0;
stud_num = 100;
printf("%d %d\n",
count, stud_num);
|
%d
%d
|
Chỉ chứa lệnh định dạng và trình
tự thoát ra
|
count,
stud_num
|
Hai
biến
|
0,
100
|
Bảng 6.4 : Chuỗi điều khiển và mã định dạng
Ví dụ 6.1 :
Ðây là một chương trình
đơn giản dùng minh họa cho một chuỗi có thể được in theo lệnh định dạng. Chương
trình này cũng hiển thị một ký tự đơn, số nguyên và số thực (a single
character, integer, và float).
#include
<stdio.h>
#include
<conio.h>
main()
{
int a = 10;
float b = 24.67892345;
char ch = 'A';
printf("\nInteger
data = %d", a);
printf("\nFloat Data = %f", b);
printf("\nCharacter = %c", ch);
printf("\nThis prints the string");
printf("%s", "\nThis also prints a string");
getch();
}
Kết quả chương trình như sau:
Ø Bổ từ (Modifier) cho các lệnh định dạng trong
printf()
Các lệnh định dạng có
thể có bổ từ (modifier), để thay đổi các đặc tả chuyển đổi gốc. Sau đây
là các bổ từ được chấp nhận trong câu lệnh printf(). Nếu có nhiều bổ từ được
dùng thì chúng tuân theo trình tự sau :
Bổ từ ‘-‘
Dữ liệu sẽ được canh
trái bên trong không gian dành cho nó, chúng sẽ được in bắt đầu từ vị trí ngoài
cùng bên trái.
Bổ từ xác định độ rộng
Chúng có thể được dùng
với kiểu: float, double
hay char array (chuỗi-string). Bổ từ xác định độ rộng là một số nguyên
xác định độ rộng nhỏ nhất của trường dữ liệu. Các dữ liệu có độ rộng nhỏ hơn sẽ
cho kết quả canh phải trong trường dữ liệu. Các dữ liệu có kích thước lớn hơn
sẽ được in bằng cách dùng thêm những vị trí cho đủ yêu cầu.Ví dụ, %10f là lệnh định dạng cho các mục dữ liệu kiểu số thực với độ
rộng trường dữ liệu thấp nhất là 10.
Bổ từ xác định độ chính
xác
Chúng có thể được dùng
với kiểu float, double hay mảng ký tự (char array, string). Bổ từ xác định độ rộng chính xác được
viết dưới dạng .m với m là một số nguyên.
Nếu sử dụng với kiểu float và double, chuỗi số chỉ ra số con
số tối đa có thể được in ra phía bên phải dấu chấm thập phân.
Nếu phần phân số của các
mục dữ liệu kiểu float hay double vượt quá độ rộng con số chỉ trong bổ
từ, thì số đó sẽ được làm tròn. Nếu chiều dài chuỗi vượt quá chiều
dài chỉ định thì chuỗi sẽ được cắt bỏ phần dư ra ở phía cuối. Một
vài số không (0) sẽ được thêm vào nếu số con số thực sự trong một mục dữ liệu
ít hơn được chỉ định trong bổ từ. Tương tự, các khoảng trắng sẽ được thêm vào
cho chuỗi ký tự. Ví dụ, %10.3f là lệnh định dạng cho mục dữ liệu kiểu float, với độ rộng tối thiểu cho trường dữ liệu là 10 và 3 vị trí sau
phần thập phân.
Bổ từ ‘0’
Theo mặc định, việc thêm
vào một trường được thực hiện với các khoảng trắng. Nếu người dùng muốn thêm
vào trường với số không (0), bổ từ này phải được dùng.
Bổ từ ‘l’
Bổ từ này có thể được
dùng để hiển thị số nguyên như: long
int hay một tham số kiểu double. Mã định dạng tương ứng cho nó là %ld.
Bổ từ ‘h’
Bổ từ này được dùng để
hiện thị kiểu short integer. Mã định dạng tương ứng cho nó là %hd.
Bổ từ ‘*’
Bổ từ này được dùng khi
người dùng không muốn chỉ trước độ rộng của trường mà muốn chương trình xác
định nó. Nhưng khi đi với bổ từ này, một tham số được yêu cầu phải chỉ ra độ
rộng trường cụ thể.
Chúng ta hãy xem những
bổ từ này hoạt động thế nào. Ðầu tiên, chúng ta xem xét tác động của nó đối với
những dữ liệu kiểu số nguyên.
Ví dụ 6.2:
/* Chương trình này
trình bày cách dùng bổ từ trong printf() */
#include
<stdio.h>
#include
<conio.h>
main()
{
printf("The number 555 in various forms:\n");
printf("Without any modifier: \n");
printf("[%d]\n", 555);
printf("With - modifier:\n");
printf("[%-d]\n", 555);
printf("With digit string 10 as modifier:\n");
printf("[%10d]\n", 555);
printf("With 0 as modifier: \n");
printf("[%0d]\n", 555);
printf("With 0 and digit string 10 as modifiers:\n");
printf("[%010d]\n", 555);
printf("With -, 0 and digit string 10 as
modifiers:\n");
printf("[%-010d]\n", 555);
getch();
}
Kết quả như dưới đây:
Chúng ta đã dùng ký hiệu
‘[‘ và ‘]’ để chỉ ra nơi trường
bắt đầu và nơi kết thúc. Khi chúng ta dùng %d mà không có bổ từ, chúng ta thấy rằng nó dùng cho một trường
có cùng độ rộng với số nguyên. Khi dùng %10d chúng ta thấy rằng nó dùng 10 khoảng trắng cho
trường và số được canh lề phải theo mặc định. Nếu ta dùng bổ từ –, số sẽ
được canh trái trong trường đó. Nếu dùng bổ từ 0, chúng ta thấy rằng số sẽ thêm
vào 0 thay vì là khoảng trắng.
Bây giờ chúng ta hãy xem
bổ từ dùng với số thực.
Ví dụ 6.3:
/* Chương trình này
trình bày cách dùng bổ từ trong printf() */
#include
<stdio.h>
#include <conio.h>
main()
{
printf("The number 555.55 in various forms:\n");
printf("In float form without
modifiers:\n");
printf("[%f]\n", 555.55);
printf("In exponential form without any modifier:\n");
printf("[%e]\n", 555.55);
printf("In float form with - modifier:\n");
printf("[%-f]\n", 555.55);
printf("In float form with digit string 10.3 as modifier\n");
printf("[%10.3f]\n", 555.55);
printf("In float form with 0 as
modifier:\n");
printf("[%0f]\n", 555.55);
printf("In float form with 0 and
digit string 10.3");
printf("as modifiers:\n");
printf("[%010.3f]\n", 555.55);
printf("In float form with -, 0 ");
printf("and digit string 10.3 as
modifiers:\n");
printf("[%-010.3f]\n", 555.55);
printf("In exponential form with
0");
printf("and digit string 10.3 as
modifiers:\n");
printf("[%010.3e]\n", 555.55);
printf("In exponential form with -,
0");
printf("and digit string 10.3 as
modifiers:\n");
printf("[%-010.3e]\n\n", 555.55);
getch();
}
Kết quả như sau:
Theo mặc định cho %f, chúng ta có thể thấy
rằng có 6 con số cho phần thập phân và mặc định cho %e là một con số tại
phần nguyên và 6 con số phần bên phải dấu chấm thập phân. Chú ý cách thể hiện 2
số cuối cùng trong ví dụ trên, số các con số bên phải dấu chấm thập phân là 3,
dẫn đến kết quả không được làm tròn.
Bây giờ, chúng ta hãy
xem bổ từ dùng với chuỗi số. Chú ý cách mở rộng trường để chứa toàn bộ chuỗi.
Hơn nữa, chú ý cách đặc tả độ chính xác .4 trong việc giới hạn
số ký tự được in.
Ví dụ 6.4:
/* Chương trình trình
bày cách dùng bổ từ với chuỗi*/
#include
<stdio.h>
#include <conio.h>
main()
{
printf("A string in various forms:\n");
printf("Without any format command:\n");
printf("Good day Mr. Lee. \n");
printf("With format command but without any modifier:\n");
printf("[%s]\n", "Good day Mr. Lee.");
printf("With digit string 4 as modifier:\n");
printf("[%4s]\n", "Good day Mr. Lee.");
printf("With digit string 19 as modifier: \n");
printf("[%19s]\n", "Good day Mr. Lee.");
printf("With digit string 23 as modifier: \n");
printf("[%23s]\n", "Good day Mr. Lee.");
printf("With digit string 25.4 as modifier: \n");
printf("[%25.4s]\n", "Good day Mr.Lee.");
printf("With - and digit string 25.4 as modifiers:\n");
printf("[%-25.4s]\n", "Good day Mr.shroff.");
getch();
}
Kết quả như sau:
Những ký tự ta nhập tại
bàn phím không được lưu ở dạng các ký tự. Thật sự chúng lưu theo dạng các số
dưới dạng mã ASCII (Bộ mã chuẩn Mỹ cho việc trao đổi thông tin -
American Standard Code for Information Interchange). Các giá trị của một
biến được thông dịch dưới dạng ký tự hay một số tùy vào kiểu của biến đó. Ví dụ
sau mô tả điều này:
Ví dụ 6.5:
#include
<stdio.h>
#include <conio.h>
main()
{
int a = 80;
char b= 'C';
printf("\nThis is the number stored in 'a' %d",a);
printf("\nThis is a character interpreted from 'a' %c",a);
printf("\nThis is also a character stored in 'b' %c",b);
printf("\nHey! The character of 'b' is printed as a number! %d", b);
getch();
}
Kết quả như dưới đây:
Kết quả này mô tả việc
dùng các đặc tả định dạng và việc thông dịch của mã ASCII. Mặc dù các biến a và b đã
được khai báo là các biến kiểu int và char, nhưng chúng đã được in như là ký tự và số nhờ vào việc dùng các
bộ định dạng khác nhau. Ðặc điểm này của C giúp việc xử lý dữ liệu được linh
hoạt.
6.2.2 scanf()
Hàm scanf() được sử dụng để nhập dữ liệu. Khuôn dạng chung của hàm scanf() như sau:
scanf(<Chuỗi
các định dạng>, <Danh sách các tham số>);
Ðịnh dạng được sử dụng
bên trong câu lệnh printf() cũng được sử dụng cùng cú pháp trong các câu
lệnh scanf().
Những lệnh định dạng,
bao gồm bổ từ và danh sách tham số được bàn luận cho printf() thì cũng hợp lệ cho scanf(), chúng tuân theo một số
điểm khác biệt sau:
Ø Sự khác nhau trong danh sách tham số giữa
printf() và scanf()
Hàm printf() dùng các tên biến, hằng số, hằng chuỗi và
các biểu thức, nhưng scanf() sử dụng những con trỏ tới các biến. Một con trỏ
tới một biến là một mục dữ liệu chứa đựng địa chỉ của nơi mà biến được cất giữ
trong bộ nhớ. Những con trỏ sẽ được bàn luận chi tiết ở chương sau. Khi sử
dụng scanf() cần tuân theo những quy tắc cho danh sách tham
số:
- Nếu ta muốn nhập giá trị cho
một biến có kiểu dữ liệu cơ bản, gõ vào tên biến cùng với ký hiệu & trước
nó.
- Khi nhập giá trị cho một biến
thuộc kiểu dữ liệu dẫn xuất (không phải thuộc bốn kiểu cơ bản char,
int, float, double),
không sử dụng & trước
tên biến.
Ø Sự khác nhau trong lệnh định dạng giữa
printf() và scanf()
1. Không
có tùy chọn %g.
2. Mã
định dạng %f và %e có cùng hiệu quả tác động. Cả hai nhận một ký
hiệu tùy chọn, một chuỗi các con số có hay không có dấu chấm thập phân và một
trường số mũ tùy chọn.
Cách thức hoạt động của
scanf()
scanf() sử dụng những ký tự không được in như ký tự
khoảng trắng, ký tự phân cách (tab), ký tự xuống dòng để quyết định khi nào một
trường nhập kết thúc và bắt đầu. Có sự tương ứng giữa lệnh định dạng với những
trường trong danh sách tham số theo một thứ tự xác định, bỏ qua những ký tự
khoảng trắng bên trong. Do đó, đầu vào có thể được trải ra hơn một dòng, miễn
là chúng ta có ít nhất một ký tự phân cách, khoảng trắng hay hàng mới giữa các
trường nhập vào. Nó bỏ qua những khoảng trắng và ranh giới hàng để thu được dữ
liệu.
Ví dụ 6.6:
/*Chương trình sau mô
tả việc dùng hàm scanf()*/
#include
<stdio.h>
#include <conio.h>
main()
{
int
a;
float d;
char ch, name[40];
printf("Please enter the data\n");
scanf("%d %f %c %s", &a, &d, &ch, name);
printf("\nThe values accepted are: %d, %f, %c, %s", a, d, ch, name);
getch();
}
Dữ liệu đầu vào có thể
là:
12 67.9 F MARK
hoặc như:
12 67.9 F MARK
cũng được nhận vào các
biến a, d, ch, và name.
Xem ví dụ khác:
Ví dụ 6.7:
#include <stdio.h>
#include <conio.h>
main()
{
int i;
float x;
char c;
scanf("%3d %5f %c", &i, &x, &c);
printf("%d, %f, %c",i,x,c);
getch();
printf("%d, %f, %c",i,x,c);
getch();
}
Kết quả như sau:
Nếu dữ liệu nhập vào là:
21 10.345 F
Khi chương trình
được thực thi, thì 21 sẽ gán tới i, 10.34 sẽ gán tới x và ký tự 5 sẽ được gán
cho c. Còn lại là đặc tính F sẽ bị bỏ qua.
Khi ta chỉ rõ một chiều
rộng trường bên trong scanf(), thí dụ %10s, rồi sau đó scanf() chỉ thu nhận tối
đa 10 ký tự hoặc tới ký tự khoảng trắng đầu tiên (bất cứ ký tự nào đầu tiên).
Ðiều này cũng áp dụng cho các kiểu int, float và double.
Ví dụ dưới đây mô tả
việc sử dụng hàm scanf() để nhập vào một chuỗi gồm có những ký tự viết HOA và
khoảng trắng. Chuỗi sẽ có chiều dài không xác định nhưng nó bị giới hạn trong
79 ký tự (thật ra, 80 ký tự bao gồm ký tự trống (null) được thêm vào nơi cuối
chuỗi).
Ví dụ 6.8:
#include <stdio.h>
#include <conio.h>
main()
{
char line[80]={}; /* line[80] là một
mảng lưu 80 ký tự */
scanf("%[ ABCDEFGHIJKLMNOPQRSTUVWXYZ]", line);
printf("%s",line);
printf("%s",line);
getch();
}
Mã khuôn dạng %[]
có nghĩa những ký tự được
định nghĩa bên trong [] có thể được chấp nhận như những ký tự chuỗi hợp lệ. Nếu chuỗi DIEN TU MAY TINH được nhập vào từ thiết bị nhập chuẩn, khi chương trình được thực
thi, toàn bộ chuỗi sẽ được gán cho mảng một khi chuỗi chỉ toàn là ký tự viết
hoa và khoảng trắng:
Nếu chuỗi được viết là DIEN Tu may tinh, chỉ có chuỗi ký tự DIEN T được gán cho mảng, khi đó thì ký tự viết thường đầu tiên (trong trường hợp này là ‘u’) được thông dịch như ký tự đầu tiên bên ngoài chuỗi:
Nếu chuỗi được viết là DIEN Tu may tinh, chỉ có chuỗi ký tự DIEN T được gán cho mảng, khi đó thì ký tự viết thường đầu tiên (trong trường hợp này là ‘u’) được thông dịch như ký tự đầu tiên bên ngoài chuỗi:
Ðể chấp nhận bất kỳ ký
tự nào đến khi gặp ký tự xuống dòng, chúng ta sử dụng mã định dạng %[^\n], điều này ngụ ý rằng chuỗi đó sẽ chấp nhận bất
kỳ ký tự nào trừ “\n” (ký tự xuống dòng).
Dấu mũ (^) ngụ ý rằng tất cả các ký tự trừ những ký tự nằm sau dấu mũ đó sẽ được chấp nhận như ký tự hợp lệ.
Dấu mũ (^) ngụ ý rằng tất cả các ký tự trừ những ký tự nằm sau dấu mũ đó sẽ được chấp nhận như ký tự hợp lệ.
Ví dụ 6.9:
#include <stdio.h>
#include <conio.h>
main()
{
char line[80];
scanf("%[^.]", line);
printf("%s",line);
getch();
printf("%s",line);
getch();
Khi hàm scanf() được thực thi, chỉ có chuỗi dientumaytinh được gán vào mảng, ký tự '.' đầu tiên sẽ được coi là kết thúc một chuỗi.
Bổ từ * cho
kết quả khác nhau trong scanf(). Dấu * được dùng để chỉ rằng một trường sẽ được bỏ qua
luôn hay tạm bỏ qua.
Ví dụ xét chương trình:
#include
<stdio.h>
#include <conio.h>
main()
{
char item[20];
int partno;
float cost;
.........
scanf("%s %*d %f", item, &partno, &cost);
.........
}
Nếu các mục dữ
liệu tương ứng là:
battery 12345 0.05
thì battery sẽ
được gán cho item và 0.05 sẽ
được gán cho cost nhưng 12345 sẽ không
được gán cho partno bởi vì dấu * ngăn chặn việc gán.
Bất cứ ký tự khác trong scanf() mà không là mã định dạng
trong chuỗi điều khiển phải được nhập vào chính xác nếu không sẽ phát sinh lỗi.
Ðặc điểm này được dùng để chấp nhận dấu phân cách phẩy (,).
Ví dụ chuỗi dữ liệu
10,
15, 17
và lệnh nhập vào
scanf(“%d,
%f, %c”, &intgr, &flt, &ch);
Chú ý rằng dấu phẩy
trong chuỗi chuyển đổi tương ứng dấu phẩy trong chuỗi nhập và vì vậy nó sẽ có
chức năng như dấu phân cách.
Ký tự khoảng trắng trong
chuỗi điều khiển thường được bỏ qua mặc dù nó sẽ phát sinh trở ngại khi dùng
với mã định dạng %c. Nếu chúng ta dùng bộ định dạng %c thì một
khoảng trắng được xem như là một ký tự hợp lệ.
Xét đoạn mã sau:
int
x, y;
char ch;
scanf(“%2d %c %d”,&x, &ch, &y);
printf(“%d
%d %d\n”,x, ch, y);
ta nhập vào:
14 c 5
14 sẽ được gán cho x, ký tự ch
nhận ký tự khoảng trắng (số 32 trong hệ thập phân), do vậy y được gán
giá trị của ký tự ‘c’ tức là số 99 trong hệ thập phân.
Xét đoạn mã sau:
#include
<stdio.h>
#include <conio.h>
main()
{
char c1, c2, c3;
…………..
scanf(“%c%c%c”,&c1, &c2, &c3);
………………..
}
Nếu dữ liệu nhập vào là:
a b c
(với khoảng trắng giữa
các ký tự), thì kết quả của phép gán:
c1 =
a, c2 = <Khoảng
trắng>,
c3 = b
Ở đây chúng ta có thể
thấy c2 chứa một khoảng trắng vì chuỗi nhập có chứa ký tự khoảng trắng.
Ðể bỏ qua các ký tự khoảng trắng này và đọc ký tự tiếp theo không phải là ký tự
khoảng trắng, ta nên dùng tập chuyển đổi %1s.
scanf(“%c%1s%1s”,&c1,
&c2, &c3);
Khi đó kết quả sẽ khác
đi với cùng dữ liệu nhập vào như trước và kết quả đúng như ý định của ta:
c1 =
a, c2 =
b,
c3 = c
6.3
Bộ nhớ đệm Nhập và Xuất (Buffered I/O)
Ngôn ngữ C bản thân nó
không định nghĩa các thao tác nhập và xuất. Tất cả thao tác nhập và xuất
được thực hiện bởi các hàm có sẵn trong thư viện hàm của C. Thư viện hàm C chứa
một hệ thống hàm riêng mà nó điều khiển các thao tác này. Ðó là:
o
Bộ nhớ đệm Nhập và Xuất
– được dùng để đọc và viết các ký tự ASCII
Một vùng đệm là nơi lưu
trữ tạm thời, nằm trên bộ nhớ máy tính hoặc trên thẻ nhớ của bộ điều khiển
thiết bị (controller card). Các ký tự nhập vào từ bàn phím được đưa vào bộ nhớ
và đợi đến khi người dùng nhấn phím return hay enter thì
chúng sẽ được thu nhận như một khối và cung cấp cho chương trình.
Bộ nhớ đệm nhập và xuất
có thể được phân thành:
§ Thiết bị nhập/xuất chuẩn (Console I/O)
§ Tập tin đệm nhập/xuất (Buffered File I/O)
Thiết bị nhập/xuất chuẩn liên quan đến những hoạt động của bàn phím
và màn hình của máy tính. Tập tin đệm nhập/xuất liên quan đến
những hoạt động thực hiện đọc và viết dữ liệu vào tập tin. Chúng ta sẽ nói về Thiết
bị nhập/xuất.
Trong C, Thiết
bị nhập/xuất chuẩn là một thiết bị luồng. Các hàm trong Thiết bị
nhập/xuất chuẩn hướng các thao tác đến thiết bị nhập và xuất chuẩn của hệ
thống.
Các hàm đơn giản nhất
của Thiết bị nhập/xuất chuẩn là:
§ getchar() – Ðọc một và chỉ một ký tự từ bàn phím.
§ putchar() – Xuất một ký tự đơn ra màn hình.
6.3.1 getchar()
Hàm getchar() được dùng để đọc dữ liệu
nhập vào, chỉ một ký tự tại một thời điểm từ bàn phím.Trong hầu hết việc thực
thi của C, khi dùng getchar(), các ký tự nằm trong vùng đệm cho đến khi người dùng nhấn phím
xuống dòng. Vì vậy nó sẽ đợi cho đến khi phím Enter được gõ. Hàm getchar() không có tham số, nhưng
vẫn phải có cặp dấu ngoặc đơn. Nó đơn giản lấy về ký tự tiếp theo và sẵn sàng
đưa ra cho chương trình. Chúng ta nói rằng hàm này trả về một giá trị có kiểu
ký tự.
Chương trình sau trình bày
cách dùng hàm getchar().
Ví dụ 6.10:
/* Chương trình trình
bày cách dùng getchar() */
#include
<stdio.h>
#include <conio.h>
main()
{
char letter;
printf("\nPlease enter any character: ");
letter = getchar();
printf("\nThe character entered by you is %c. ", letter);
getch();
}
Trong chương trình trên
‘letter’ là một biến được khai báo là kiểu char do vậy nó sẽ nhận vào ký tự.
Một thông báo:
Please enter any character:
sẽ xuất hiện trên màn
hình. Ta nhập vào một ký tự, trong ví dụ là S, qua bàn phím và nhấn Enter. Hàm getchar() nhận ký tự đó và gán cho biến có tên là letter.
Sau đó nó được hiển thị trên màn hình và ta có được thông báo.
The character entered by you is S.
6.3.2
putchar()
putchar() là hàm xuất ký tự trong C, nó sẽ xuất một
ký tự lên màn hình tại vị trí con trỏ màn hình. Hàm này yêu cầu một tham số.
Tham số của hàm putchar() có thể thuộc các loại sau:
· Hằng ký tự
đơn
· Ðịnh dạng
(Escape sequence)
· Một biến ký
tự.
Nếu tham số là một hằng
nó phải được bao đóng trong dấu nháy đơn. Bảng 6.5 trình bày vài tùy chọn cho putchar() và tác động của chúng.
Tham
số
|
Hàm
|
Tác
dụng
|
Biến ký tự
|
putchar(c)
|
Hiện thị nội dung của biến ký tự c
|
Hằng biến ký tự
|
putchar(‘A’)
|
Hiển thị ký tự A
|
Hằng số
|
putchar(‘5’)
|
Hiển thị con số 5
|
Ðịnh dạng (escape sequence)
|
putchar(‘\t’)
|
Chèn một ký tự khoảng cách (tab)
tại vị trí con trỏ màn hình
|
Ðịnh dạng (escape sequence)
|
putchar(‘\n’)
|
Chèn một mã xuống dòng tại vị trí
con trỏ màn hình
|
Bảng 6.5: Những tùy chọn cho putchar() và tác dụng của chúng
Chương trình sau trình
bày về hàm putchar():
Ví dụ 6.11:
/* Chương trình này
trình bày việc sử dụng hằng và định dạng trong hàm putchar() */
#include
<stdio.h>
#include <conio.h>
main()
{
putchar('H'); putchar('\n');
putchar('\t');
putchar('E'); putchar('\n');
putchar('\t'); putchar('\t');
putchar('L'); putchar('\n');
putchar('\t'); putchar('\t'); putchar('\t');
putchar('L'); putchar('\n');
putchar('\t'); putchar('\t'); putchar('\t');
putchar('\t');
putchar('O');
getch();
}
Kết quả như sau:
Khác nhau giữa getchar() và putchar() là putchar() yêu cầu một tham số trong khi getchar() thì không.
Ví dụ 6.12:
/* Chương trình trình
bày getchar() và putchar() */
#include
<stdio.h>
#include <conio.h>
main()
{
char letter;
printf("You can enter a character now: ");
letter = getchar();
putchar(letter);
getch();
}
Kết quả như sau:
Tóm tắt bài học
Ø Trong C, Nhập và Xuất được thực hiện bằng cách
dùng các hàm. Bất cứ chương trình nào trong C đều có quyền truy cập tới ba tập
tin chuẩn. Chúng là tập tin nhập chuẩn (stdin), tập tin xuất chuẩn (stdout)
và bộ lỗi chuẩn (stderr). Thông thường tập tin nhập chuẩn là bàn phím (keyboard),
tập tin xuất chuẩn là màn hình (screen) và tập tin lỗi chuẩn cũng
là màn hình.
Ø Tập tin tiêu đề <stdio.h> chứa
các macro của nhiều hàm nhập và xuất (input/output function) được dùng
trong C.
Ø Thiết bị nhập/xuất chuẩn (Console I/O) liên quan đến
những hoạt động của bàn phím và màn hình của máy tính. Nó chứa các hàm định
dạng và không định dạng.
Ø Hàm nhập xuất định dạng là printf() và scanf().
Ø Hàm nhập xuất không định dạng là getchar() và putchar().
Ø Hàm scanf() được dùng cho dữ
liệu nhập vào có định dạng, trong khi hàm printf() được dùng
để xuất ra dữ liệu theo một định dạng cụ thể.
Ø Chuỗi điều khiển của printf() và scanf() phải
luôn tồn tại bên trong dấu nháy kép “”. Chuỗi này sẽ chứa một tập
các lệnh định dạng. Mỗi lệnh định dạng chứa ký hiệu %, một tùy chọn
các bổ từ và các dạng kiểu dữ liệu xác định.
Ø Sự khác nhau chính giữa printf() và scanf() là
hàm scanf() dùng địa chỉ của biến chứ không phải là tên biến.
Ø Hàm getchar() đọc một ký tự từ
bàn phím.
Ø Hàm putchar(ch) gởi ký tự ch ra
màn hình.
Ø Sự khác nhau giữa getchar() và putchar() là putchar() có
một tham số trong khi getchar() thì không.
Kiểm tra tiến độ học tập
1. Các
hàm nhập và xuất có định dạng là _________ và ________.
A. printf() và scanf()
|
B. getchar() và putchar()
|
C. puts() và gets()
|
D. Không câu nào đúng
|
2. Hàm scanf() dùng
_________ tới các biến chứ không dùng tên biến.
A. Hàm
|
B. Con trỏ
|
C. Mảng
|
D. Không câu nào đúng
|
3. ___________ xác
định định dạng cho các giá trị của biến sẽ được nhập và in.
A. Văn bản
|
B. Bộ định dạng
|
C. Tham số
|
D. Không câu nào đúng
|
4. _______
được dùng bởi hàm printf() để xác định các đặc tả chuyển đổi.
A. %
|
B. &
|
C. *
|
D. Không câu nào đúng
|
5. getchar() là
một hàm không có bất cứ tham số
nào.
(True/False)
6. Một
___________ là một nơi lưu trữ tạm trong bộ nhớ.
A. ROM (Bộ nhớ chỉ đọc)
|
B. Thanh ghi
|
C. Vùng đệm
|
D. Không câu nào đúng
|
7. Ðịnh
dạng (Escape sequence) có thể được đặt bên ngoài chuỗi điều khiển của printf().
(True/False)
Bài tập tự làm
1. A. Hãy dùng câu lệnh printf() để
:
a) Xuất
ra giá trị của biến số nguyên sum.
b) Xuất
ra chuỗi văn bản "Welcome", tiếp theo là một dòng mới.
c) Xuất
ra biến ký tự letter.
d) Xuất
ra biến số thực discount.
e) Xuất
ra biến số thực dump có 2 vị trí phần thập phân.
1. B. Dùng câu lệnh scanf() và
thực hiện:
a) Ðọc giá trị
thập phân từ bàn phím vào biến số nguyên sum.
b) Ðọc một giá trị số thực vào biến discount_rate.
2 Viết
một chương trình xuất ra giá trị ASCII của các ký tự ‘A’ và ‘b’.
3. Xét
chương trình sau:
#include <stdio.h>
#include <conio.h>
main()
{
int
breadth;
float
length, height;
scanf(“%d%f%6.2f”, breadth, &length, height);
printf(“%d
%f %e”, &breadth, length, height);
getch();
}
Sửa lỗi chương trình
trên.
4. Viết
một chương trình nhập vào name, basic, daper (phần
trăm của D.A), bonper (phần trăm lợi tức) và loandet (tiền
vay bị khấu trừ) cho một nhân viên.
Tính lương như sau:
salary = basic + basic *
daper/100 + bonper * basic/100 - loandet
Bảng dữ liệu:
name
|
basic
|
daper
|
bonper
|
loandet
|
MARK
|
2500
|
55
|
33.33
|
250.00
|
Tính salary và xuất ra
kết quả dưới các đầu đề sau (Lương được in ra gần dấu đôla ($)):
Name
Basic
Salary
5. Viết
một chương trình yêu cầu nhập vào tên, họ của bạn và sau đó xuất ra tên, họ
theo dạng là họ, tên.
0 nhận xét:
Đăng nhận xét