Thao tác Input / Output trong C
- 15-04-2022
- Toanngo92
- 0 Comments
Tại sao lại đưa bài tao tác input output lên trước các bài khái niệm tiếp theo ? Vì để dễ dàng thực hành trong quá trình lmà bài tập tập, mình sẽ đi tới input/output và giới thiệu cách nhập xuất cơ bản trước, mặc dù chúng ta chưa hiểu rõ khái niệm về hàm, nhưng cứ xài nó trước đi đã, rồi đi vào khái niệm sau.
Chương trình C cung cấp một bộ thư viện chuẩn để làm việc với các hàm nhập xuất, nhập là đưa dữ liệu từ thiết bị ngoại vi vào, trong ngữ cảnh ngôn ngữ lập trình C là bàn phím, xuất là đưa dữ liệu từ máy tính ra, ngữ cảnh này là in ra màn hình.
Mục lục
Output – In ra màn hình với hàm printf()
Trong lập trình C, printf() là một trong những hàm xuất in dữ liệu ra màn hình chính. Hàm này được định nghĩa trong thư viện có tên <stdio.h>, để sử dụng nó chúng ta đưa thư viện chuẩn vào theo cú pháp
#include stdio.h
Ví dụ
#include stdio.h
int main()
{
// in dòng hello world ra màn hình
printf("hello world");
return 0;
}
Kết quả được in ra màn hình:
hello world
Luồng chạy chương trình:
- Đưa thư viện stdio.h vào
- Khi thực thi mã nguồn, chương trình C gọi hàm main để thực thi
- Trong hàm main gọi tới (thực thi) hàm printf (in ra màn hình dòng chữ hello world)
- return 0 để kết thúc chương trình.
Tại sao lại return 0 cuối hàm main ? sẽ được đề cập trong bài viết khái niệm hàm. Trong ngữ cảnh này, chúng ta khai báo hàm main kiểu dữ liệu int, vì vậy cuối hàm cần return 0 để trả về giá trị cho hệ điều hành và kết thúc chương trình. Nếu không muốn return 0 ở cuối chương trình, khai báo kiểu dữ liệu void cho hàm main()
Cú pháp hàm printf()
printf("control string",argument list);
// controlstring: chuỗi điều khiển
// argument list: danh sách tham số
Định dạng dữ liệu (Format Sepcifier)
Xét ví dụ dưới là câu lệnh in dữ liệu số ra màn hình
#include
int main()
{
int testInteger = 5;
printf("Number = %d", testInteger);
return 0;
}
Kết quả:
Number = 5
Input – Nhập dữ liệu với hàm scanf()
Trong ngôn ngữ C, hàm scanf được dùng để nhận dữ liệu mà người dùng nhập vào từ bàn phím. Hàm này sẽ đọc dữ liệu từ bàn phím nhập vào theo đúng định dạng mà lập trình viên quy ước tương tự cấu trúc định dạng chu ta đã tiếp cận ở hàm printf.
Cú pháp hàm scanf()
scanf("format specifier list",argument list);
// format specifier list: chuỗi bộ định dạng
// argument list: danh sách tham số
Xem ví dụ dưới đây:
#include
int main()
{
int testInteger;
printf("Enter an integer: ");
scanf("%d", &testInteger);
printf("Number = %d",testInteger);
return 0;
}
Giả sử bạn nhập số 4 thì kết quả có dạng như sau:
Enter an integer: 4
Number = 4
Ở đây mình sử dụng format là %d vì mong muốn dữ liệu nhập vào là một số nguyên.
Ví dụ: Float và Double Input/Output
#include
int main()
{
float num1;
double num2;
printf("Enter a number: ");
scanf("%f", &num1);
printf("Enter another number: ");
scanf("%lf", &num2);
printf("num1 = %fn", num1);
printf("num2 = %lf", num2);
return 0;
}
Kết quả:
Enter a number: 12.523
Enter another number: 10.2
num1 = 12.523000
num2 = 10.200000
Chúng ta sử dụng %f và %fl để định dạng cho kiểu float và double.
Ví dụ: Character
#include
int main()
{
char chr;
printf("Enter a character: ");
scanf("%c",&chr);
printf("You entered %c.", chr);
return 0;
}
Kết quả:
Enter a character: g
You entered g
Khác biệt giữa printf() và scanf()
Danh sách tham số
Sự khác biệt rõ ràng giữa hàm printf và scanf là cách sử dụng danh sách tham số, với printf chúng ta truyền danh sách tham số vào bằng tên biến, còn với scanf chúng ta cần bổ sung thêm ký tự & đằng trước tên biến, đây là khái niệm vị trí vùng nhớ (memory address) sẽ được đề cập chi tiết ở bài con trỏ. ( Ở bài viết đó mình cũng sẽ giải thích thêm lý do vì sao riêng trường hợp %s trong scanf thể truyền trực tiếp tên biến làm tham số mà không cần dùng & mà vẫn hợp lệ)
Lệnh định dạng
- Scanf không có tùy chọn %g.
- Lệnh định dạng %c và %e có hiệu lực như nhau
- Không cần sử dụng thêm bổ từ cho scanf
Cách hoạt động của scanf
scanf() sử dụng các ký tự không in được như trống, tab, dòng mới để quyết định khi nào một trường đầu vào kết thúc và feld đầu vào bắt đầu. Nó khớp các lệnh định dạng với các trường trong danh sách đối số theo cùng thứ tự mà chúng được chỉ định, bỏ qua các ký tự khoảng trắng ở giữa. Do đó, đầu vào có thể được trải rộng trên nhiều dòng, miễn là chúng ta có ít nhất một tab, khoảng trắng hoặc dòng mới giữa mỗi trường đầu vào. Nó bỏ qua các khoảng trắng và ranh giới dòng để lấy dữ liệu.
Nhập xuất nhiều dữ liệu cùng lúc thông qua danh sách tham số ( argument list)
Bạn có thể nhập xuất nhiều dữ liệu cùng lúc bằng cách truyền thêm tham số vào hai hàm printf và scanf, và đương nhiên định dạng format bạn cũng phải nhập đầy đủ tương đương, khớp cả về thứ tự, số lượng, và kiểu dữ liệu của biến tham số.
Xem ví dụ sau, mình đã dùng hàm scanf và hàm printf để in hai biến cùng lúc.
#include
int main()
{
int a;
float b;
printf("Enter integer and then a float: ");
// Taking multiple inputs
scanf("%d%f", &a, &b);
printf("You entered %d and %f", a, b);
return 0;
}
Kết quả:
Enter integer and then a float: -3
3.4
You entered -3 and 3.400000
Lưu ý: khi sử dụng hàm scanf, chuỗi bộ định dạng được viết liền kề nhau, không có khoảng trắng, hằng số chuỗi ở giữa, ví dụ:
scanf("%s %d",&a,&b) // sai
scanf("%s va %d",&a,&b) // sai
scanf("%s%d",&a,&b) // đúng
Bảng lệnh định dạng dữ liệu (format specifier)
Định dạng | printf() | scanf() |
Ký tự (char) | %c | %c |
Số nguyên (decimal) | %d | %d |
Số thực (float) | %f | %f |
Số thực (double) | %lf | %f |
mảng ký tự/chuỗi (array character/string) | %s | %s |
Số thập phân với dấu chấm động | %e | %e hoặc %f |
Số nguyên không dấu (unsign) | %u | %u |
Số thập lục phân không dấu (unsign hexadecimal integer) | %x | %x |
Số bát phân không dấu (unsign octal integer) | %o | %o |
Trong bảng trên c, d, f, lf, e, g, u, s, o và x là các chỉ định kiểu.
Trong khuôn khổ học tập này, chúng ta chủ yếu sử dụng %d, %f, %s, %c.
Vì %, \ và * có những cách sử dụng đặc biệt trong chuỗi điều khiển (control string) nên nếu muốn in chúng như một phần của chuỗi văn bản và được in trên console, chúng phải được sử dụng như trong bảng dưới:
\\ | In ký tự \ |
\” | In ký tự “ |
%% | In ký tự % |
Bổ từ (Modifiers) cho lệnh định dạng Format Commands trong printf()
Các lệnh định dạng có thể có các bổ từ, sử dụng để sửa đổi các thông số chuyển đổi cơ bản cho phù hợp.
Sau đây là các công cụ sửa đổi hợp lệ được chấp nhận trong câu lệnh printf. Nếu sử dụng nhiều hơn một công cụ sửa đổi, thì chúng phải theo thứ tự như dưới đây.
Bổ từ “-“
Mục dữ liệu sẽ được căn đều trong trường của nó; mục sẽ được in bắt đầu từ vị trí ngoài cùng bên trái của trường của nó.
Bổ từ độ rộng trường (Field Width Modifier)
Chúng có thể được sử dụng với kiểu float, double char array(string). Bổ từ độ rộng của trường, là một số nguyên, xác định độ rộng trường tối thiểu cho mục dữ liệu. Các mục dữ liệu có chiều rộng nhỏ hơn sẽ được xuất ra căn phải trong trường. Dữ liệu lớn hơn các mục sẽ được in bằng cách sử dụng nhiều vị trí bổ sung theo yêu cầu. ví dụ: %10f là lệnh định dạng cho mục dữ liệu kiểu float có độ rộng trường tối thiểu là 10.
Bổ từ chính xác (Precision Modifier)
Công cụ sửa đổi này có thể được sử dụng với kiểu float, double hoặc mảng char (chuỗi). Công cụ sửa đổi được viết là .m trong đó m là một số nguyên. Nếu được sử dụng với kiểu dữ liệu float hoặc double, chuỗi chữ số cho biết số chữ số tối đa được in ở bên phải số thập phân. Khi được sử dụng với một chuỗi, nó cho biết số ký tự tối đa được in.
Nếu phần phân số của mục dữ liệu kiểu float hoặc double vượt quá bổ từ chính xác, thì số đó sẽ được làm tròn. Nếu chiều dài chuỗi vượt quá độ dài quy định thì chuỗi sẽ bị cắt bớt (cắt ở cuối). Việc đệm bằng số 0 xảy ra đối với các số khi số chữ số thực tế trong một mục dữ liệu ít hơn số được chỉ định bởi bổ từ. Các khoảng trống tương tự được đệm cho các chuỗi. ví dụ: %5.3f là lệnh định dạng cho mục dữ liệu kiểu float, với trường tối thiểu có 6 ký tự và 3 vị trí đằng sau dấu . thập phân.
Bổ từ ‘0’
Phần đệm (khoảng trống) mặc định trong trường được thực hiện bằng khoảng trắng. Nếu người dùng muốn điền vào phần trống bằng số 0, bổ từ này được sử dụng.
Bổ từ ‘l’
Bổ từ này có thể được sử dụng để hiển thị số nguyên long int hoặc đối số chính xác kép. Mã định dạng tương ứng là %ld.
Bổ từ ‘h’
Bổ từ này được sử dụng để hiển thị số nguyên short. Mã định dạng tương ứng là %hd.
Bổ từ ‘*’
Công cụ sửa đổi này được sử dụng nếu người dùng không muốn chỉ định trước độ rộng của trường mà muốn chương trình chỉ định nó. Nhưng cùng với công cụ sửa đổi này, một đối số được yêu cầu để kiểm tra độ rộng của trường.
Ví dụ:
void exampleprecisionmodifier(){
float a = 10.444444;
printf("Float data Modifier = %.2f \n", a);
char b[30] = "chuoikytu";
printf("String Modifier = %.4s \n", b);
printf("String Modifier = %s \n", b);
}
void modifierexample1(){
int a = 10;
int i =2005;
float b = 24.67892345;
char ch = 'A';
printf("Integer \"\" data = %d \n", a);
printf("Float Data %cf = %f\n",'%',b);
printf("Float Data %ce = %e\n",'%',b);
printf("Float Data %cg = %g\n",'%',b);
printf("Memory addresss = %x\n",&b);
printf("So 10 hexa = %x\n",15000);
printf("Character = %c\n",ch);
printf("This prints the string\n");
printf("%s","This also prints a string\n");
printf("Integer data in hexa = %x \n", i); // hexa
printf("Integer data in octal = %o \n", i); // he bat phan
printf("Print %%");
}
void examplemodifieralignleft(){
// co can left nhung khong co min width
printf("In float form with - modifier:\n");
printf("[%-f]\n",555.55);
printf("In float form with - modifier:\n");
printf("[%f]\n",555.55);
// co can left nhung khong co min width
printf("In float form with - modifier:\n");
printf("[%-20f]\n",555.55);
//ko co can left
printf("In float form with - modifier:\n");
printf("[%20s]\n",555.555);
}
void modifierexample3(){
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);
}
void modifierexample2(){
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);
printf("With - and digit string 10 as modifiers: \n");
printf("[%-10d]\n",555);
}
void modifierexample4(){
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("118. [%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.Lee.");
printf("With * modifier :\n");
printf("[%*s]\n",30,"Good day Mr.Lee."); // %30s
}
int main()
{
examplemodifieralignleft();
exampleprecisionmodifier();
modifierexample1();
modifierexample2();
modifierexample3();
modifierexample4();
vietputchar();
return 0;
}
Bộ đệm I/O (Buffered I/O)
Ngôn ngữ C không tự định nghĩa các hoạt động đầu vào và đầu ra. Tất cả các thao tác nhập xuất được thực hiện bởi các hàm có sẵn trong thư viện hàm (library function) C. Thư viện hàm C chứa một hệ thống thường trình riêng biệt xử lý các hoạt động này. Đó là:
Buffered I/O – được sử dụng để đọc và viết các ký tự ASCII
Bộ đệm là vùng lưu trữ tạm thời, trong bộ nhớ của thiết bị. Trong bộ đệm I/O, các ký tự được nhập vào bàn phím được thu thập cho đến khi người dùng nhấn phím retum hoặc phím enter, khi các ký tự được cung cấp cho chương trình, dưới dạng một khối.
Buffered I/O được chia thành:
- Console I/O
- Buffered File I/O
Console IO đề cập đến các hoạt động xảy ra ở bàn phím và màn hình máy tính của bạn. Buffered File I/O đề cập đến các hoạt động được thực hiện để đọc và ghi dữ liệu vào một tệp. Với nội dung bài học này, chúng ta sẽ tìm hiểu Console I/O trước.
Console I/O
Trong C, console được coi là một thiết bị truyền phát. Các chức năng Console I/O hướng hoạt động của chúng đến đầu vào và đầu ra tiêu chuẩn của hệ thống (ở khuôn khổ bài học, chúng ta coi nó là màn hình đen command line).
Giới thiệu hàm getchar()
Hàm getchar() Được sử dụng để đọc dữ liệu đầu vào, một ký tự tại một thời điểm từ bàn phím. Trong hầu hết các triển khai của C, getchar() đệm các ký tự cho đến khi người dùng nhập ký tự xuống dòng. Do đó, nó đợi cho đến khi nhấn phím return hoặc enter. Hàm getchar() không có đối số, nhưng vẫn phải có dấu ngoặc đơn. Nó chỉ đơn giản là tìm nạp ký tự tiếp theo và cung cấp ký tự đó cho chương trình. Chúng ta nói rằng hàm trả về một giá trị, đó là một ký tự.
Ví dụ:
#include <stdio.h>
int main(){
char c;
printf("Vui long nhap lieu ky tu ban muon:");
c = getchar();
printf("Ky tu ban vua nhap la %c",c);
// output:
//Vui long nhap lieu ky tu ban muon:g
//Ky tu ban vua nhap la g
}
Giới thiệu hàm putchar()
putchar() là hàm xuất ký tự trong C, dùng để hiển thị một ký tự trên màn hình tại vị trí con trỏ chờ. Chức năng này yêu cầu một đối số. Đối số của hàm putchar() có thể là một trong các giá trị sau:
- Một ký tự hằng
- Một escape sequence
- biến ký tự
Trong đối số là hằng thì phải đặt trong dấu nháy đơn (‘A’). Chúng ta xem bảng dưới để hiểu rõ hơn:
Đối số | Hàm | Kết quả |
Biến ký tự | putchar(c) | In ra nội dung ký tự biến c |
Hằng ký tự | putchar (‘A’) | In ra ký tự A |
hằng số | putchar(‘3’) | In ra ký tự 3 |
Escape sequence | putcha(‘\t’) | In ra dấu tab (khoảng cách xa hơn space) |
Escape sequence | putchar(‘\n’) | In ra ký tự xuống dòng (sử dụng khi muốn xuống dòng trong văn bản) |
Ví dụ:
int 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');
return 0;
}
Bài tập
1. Viết chương trình in ra giá trị số(ASCII) của ký tự 'A' và 'B'
2. Viết chương trình nhập vào thông tin nhân sụ bao gồm:
- Tên (char array).
- Tuổi (integer).
- Lương (float).
- Hạng (char).
Ten | Tuoi | Luong | Hang |
ABC | 18 | 1500.5 | A |
Sau đó, in ra màn hình thông tin của nhân sự, thành bảng như hình:
Cho biết cách khai báo biến char array như sau:
char[10] name = ""; // sử dụng dấu nháy đôi cho giá trị chuỗi.
Để nhập và xuất cho kiểu dữ liệu char array, sử dụng bổ từ %s.
Một cách khác để lấy dữ liệu chuỗi người dùng nhập vào là:
gets(name);
3. Sửa lỗi chương trình sau:
4. Viết chương trình nhập vào và tính trung bình cộng cộng ba số.
5. Viết chương trình nhập vào là một số thực (floating). Con số này đại diện cho centimet. In ra số feet tương đương với feet và inch
Giả sử 2,54 cm trên inch và 12 inch trên foot
Nếu giá trị đầu vào là 333,3, định dạng đầu ra phải là:
333,3 cm là 10,9 feet
393,33 cm là 131,2 inch
6. Viết chương trình tính diện tích và chu vi hình chữ nhật.
7. Viết chương trình tính lương ròng của một nhân viên với các ràng buộc sau:
Lương cơ bản = cho người dùng nhập liệu
DA: 12% Lương cơ bản
Nhân sự: $150
TA:$120
Khác : $450
Trừ thuế:
a) PF 14% lương cơ bản
b) IT: 15% lương cơ bản
Lương thực nhận = Lương cơ bản + DA+ HRA+ TA + Khác — (PF + IT)