Quá trình tạo ra một chương trình và thực thi nó trên máy tính bao gồm các bước sau:
Hình 1.1 – Quá trình tạo ra và thực thi một chương trình C
- Bước 1: Sử dụng bộ soạn thảo (editor) để viết chương trình nguồn (source code). Tập tin lưu trữ mã nguồn sẽcó đuôi là .c hoặc .cpp
- Bước 2: Trình biên dịch (compiler) thực hiện biên dịch chương trình từ tập tin mã nguồn thành mã máy. Nếu chương trình có lỗi, thì lập trình viên phải sửa lỗi và thực hiện lệnh biên dịch lại cho đến khi thành công. Mã máy sau khi dịch thành công được lưu trong tập tin object có đuôi là .o hoặc .obj. - Bước 3: Tập tin object được liên kết với các tập tin trong thư viện C tạo
thành tập tin thực thi .exe. Nếu có lỗi xuất hiện trong quá trình liên kết thì phải sửa lỗi và biên dịch chương trình trở lại.
- Bước 4: Thực thi/chạy chương trình từ tập tin .exe và kết quả thu được sẽ
hiển thị trên màn hình người sử dụng. Nếu khi thực thi mà chương trình xuất hiện lỗi thì lập trình viên quay lại tìm lỗi, sửa lỗi, dịch và thực thi chương
trình.
Trong quá trình biên dịch và thực thi, chương trình có thể xuất hiện một số loại lỗi khác nhau như:
- Lỗi cú pháp (lỗi dịch): là loại lỗi thường xuyên gặp nhất, ví dụ như, biến
chưa được định nghĩa, thiếu dấu chấm phẩy, lỗi gọi hàm,… Trình biên dịch sẽ tìm ra những lỗi này và đưa ra các thông báo lỗi cụ thể.
Ví dụ: lỗi thiếu dấu ; cuối dòng lệnh
prinf(“Welcome to the world of C programming”)
- Lỗi liên kết: lỗi này xảy ra khi một tập tin cần thiết cho việc liên kết không tồn tại.
68
- Lỗi trong thời gian thực thi: đây là loại lỗi xảy ra khi đang thực thi (chạy)
chương trình, ví dụ biến chưa được cấp phát bộ nhớ, lỗi chia cho 0,…
Hiện nay có nhiều môi trường phát triển tích hợp (IDE - Integrated Development Environment) khác nhau hỗ trợ việc soạn thảo, biên dịch, và thực thi chương trình C
như Turbo C++, Borland C++, BloodShed Dev C++, Microsoft Visual Studio,
CodeLite, Code::Blocks, … Mỗi người có thể lựa chọn cho mình một IDE thích hợp
để lập trình tùy thuộc vào các tính năng mà chúng hỗ trợ, hoặc tính dễ sử dụng, dễ cài
đặt, …
BÀI TẬP CHƯƠNG 1
Bài 1. Cho biết định danh nào sau đây không hợp lệ, tại sao ?
a. emp code b. bas.sal c. 5ct
d. Gross_sal e. int
Bài 2. Cho biết giá trị của các biến khi thực hiện đoạn chương trình sau:
1. int a = 25, b = 40; 2. int kq1 = a%b; 3. int kq2 = a/b; 4. float kq3 = a/b; 5. float kq4 = (float)a/b; 6. int kq5 = a++; 7. int kq6 = ++b;
Bài 3. Cho biết giá trị của các biểu thức sau:
a. k = i >> 2, với i = 29
b. a += (a++) + (++b), với a = 5, b = 0
c. ((b > 15) && (c < 0 || a > 0)), với a = 5, b = 10, c = -6
d. 4 + 6 / 3 * 2 - 2 + 7 % 3 e. a += b -=a , với a = 1, b = 2
Bài 4. Cách sử dụng toán tửđiều kiện ? : nào sau đây là đúng?
a. a > b ? c = 30 : c = 40; b. a > b ? c = 30;
c. max = a > b ? a > c ? a : c : b > c ? b : c
69
Bài 5. Tìm lỗi trong đoạn chương trình sau đây :
1. const float N = 3.5; 2. integer a; 3. float b; 4. int c = 5, d = 0, m; 5. m = c/d; 6. N = 4;
Bài 6. Cho biết giá trị của biến a, b sau khi thực hiện đoạn chương trình sau :
1. int a = 5,b = 8;
2. a += b;
3. b = a - b;
4. a -= b;
Bài 7. Cho biết giá trị của biến a, b sau khi thực hiện đoạn chương trình sau :
1. int a = 15, b = 38;
2. int r = a%b;
3. a = b;
4. b = r;
Bài 8. Cho biết giá trị của biến min, max sau khi thực hiện đoạn chương trình sau :
1. int a = 20, b = 14;
2. int min = a > b ? b : a;
3. int max = a > b ? a : b;
Bài 9. Cho biết giá trị của biến a, b, c, d, s sau khi thực hiện đoạn chương trình sau : 1. int n = 1703; 2. int a = n%10; 3. int b = (n/10)%10; 4. int c = (n/100)%10; 5. int d = (n/1000)%10; 6. int s = a + b + c + d;
Bài 10. Cho biết giá trị của biến kq sau khi thực hiện đoạn chương trình sau :
1. int n = 294; 2. int a = n%10; 3. int b = (n/10)%10; 4. int c = (n/100)%10; 5. int m = a*100 + b*10 + c; 6. int kq = (n == m) ? 1 : 0;
70
Chương 2
NHẬP XUẤT DỮ LIỆU VÀ CÁC LỆNH ĐIỀU KHIỂN 2.1 Nhập xuất dữ liệu
Đọc dữ liệu đầu vào, xử lí nó và hiển thị kết quả là ba chức năng cơ bản của một
chương trình máy tính. Chương trình thường nhận dữ liệu đầu vào thông qua việc nhập từ bàn phím hoặc đọc từ tập tin, còn kết quả (còn gọi dữ liệu đầu ra) thu được từ chương trình sẽđược xuất ra màn hình hoặc được lưu trữ trên một tập tin bất kì.
Trong thư viện chuẩn của C hỗ trợ một số hàm cho phép nhập/xuất dữ liệu với các thiết bị nhập/xuất chuẩn là bàn phím và màn hình. Các hàm này có thể được chia ra làm 2 loại: hàm có định dạng và hàm không có định dạng. Sựkhác nhau cơ bản giữa
chúng chính là các hàm có định dạng cho phép đọc dữ liệu từ bàn phím hoặc xuất dữ
liệu ra màn hình theo các định dạng khác nhau được điều khiển bởi người dùng. Ngoài
ra, các hàm có định dạng được ứng dụng với tất cả các kiểu dữ liệu khác nhau, còn các
hàm không có định dạng thì chỉ làm việc với kí tự và chuỗi.
Hầu hết các hàm nhập/xuất chuẩn được định nghĩa trong tập tin tiêu đề stdio.h.
Vì vậy, khi cần sử dụng chúng, ta cần phải khai báo dòng #include <stdio.h> ởđầu
chương trình.
Hình 2.1 – Một số hàm nhập/xuất trong C
2.1.1Hàm xuất có định dạng
Thư viện C cung cấp hàm printf() dùng để xuất dữ liệu ra màn hình theo định dạng chỉđịnh. Cú pháp sử dụng hàm như sau:
printf(“chuỗi_định_dạng”, [danh_sách _đối _số]);
Trong đó, danh sách đối số là tùy ý, có thểkhông có đối số nào cả. Nếu có nhiều
71
hằng, hoặc biểu thức. Chuỗi định dạng có thể bao gồm: kí tựvăn bản, kí tựđiều khiển
và đặc tảđịnh dạng.
- Kí tự văn bản: Là kí tự được in ra giống y hệt như lúc viết trong chuỗi định dạng.
- Kí tựđiều khiển: Là kí tựđã được định nghĩa sẵn, mỗi kí tự sẽ có chức năng riêng và không được in ra. Ví dụ: \t, \n, \b, \a,…
- Đặc tả định dạng: mô tả cách thức hiển thị giá trị của các đối số trong phần
danh_sách_đối_số. Khi in ra màn hình thì vị trí của đặc tả sẽ được thay thế
bằng giá trị của các đối số. Đặc tảvà đối số phải tương thích với nhau về số lượng, thứ tự, và kiểu từ trái sang phải. Nếu đặc tả và đối số không phù hợp sẽ gây ra kết quảngoài mong đợi.
Dạng tổng quát của đặc tả:
%[cờ_hiệu][độ_rộng][.độ_chính_xác]kí_tự_định_kiểu
Lưu ý: Mỗi đặc tả định dạng đều bắt đầu bằng kí tự ‘%’ và kết thúc bởi kí_tự_định_ kiểu, còn các bổ từ nằm giữa chúng là tùy ý.
a. Kí tựđịnh kiểu
Là một kí tự xác định kiểu và dạng in ra cho các đối số tương ứng nằm trong
danh_sách_đối_số. Như vậy, cùng một giá trị có thể được in ra theo các dạng khác nhau. Bảng sau đây giới thiệu về một số kí tự định kiểu dùng trong C và ý nghĩa của chúng:
Kí tự định
kiểu Ý nghĩa Áp dụng cho kiểu dữ liệu
d, ld Số nguyên có dấu hệ 10 char / int / short , long
u, lu Số nguyên không dấu hệ 10 unsigned int / short, unsigned long o Số nguyên không dấu hệ 8 char / int / short / long
x Số nguyên không dấu hệ 16,
chữ thường af char / int / short / long X Số nguyên không dấu hệ 16,
chữ hoa AF char / int / short / long f, lf Số thực dạng dấu phẩy tĩnh float , double
e, le Số thực dạng dấu phẩy động float , double
c Kí tự char
s Chuỗi char*, char[ ]
72 Ví dụ: 1. #include <stdio.h> 2. #include <conio.h> 3. int main () 4. { 5. float flt = 10.234; 6. int no = 150;
7. printf("Ki tu: %c va %c\n",‘A’,‘B’);
8. printf("So thuc: %f \n", flt);
9. printf("So nguyen o he 10,8,16:%d,%o,%x\n",no,no,no);
10. getch();
11. return 0;
12. }
Kết quả của chương trình:
Ki tu: A va B
So thuc: 10.234000
So nguyen o he 10,8,16: 150,226,96
b. Bổ từ “Cờ hiệu”
Bổ từ cờ hiệu thường được dùng để canh chỉnh, thêm dấu cho số hoặc một số kí hiệu cần thiết cho dữ liệu. Sau đây là một vài cờ hiệu thường được dùng trong hàm
printf():
Cờ hiệu Ý nghĩa
nếu không có Mặc định dữ liệu được canh lề phải
- Dữ liệu sẽ được canh lề trái
+ In dữ liệu số với dấu tương ứng (+ hoặc -)
#
Phụ thuộc vào kí tự định kiểu, nếu: o : Chèn thêm 0 trước giá trị > 0
X, x : Chèn thêm 0X hoặc 0x trước số này
e, f : Luôn có dấu chấm thập phân kể cả khi không cần thiết
Bảng 2.2 – Một số cờ hiệu sử dụng trong hàm printf()
c. Bổ từ“Độ rộng”
Khi thực hiện in dữ liệu, C sẽ tựđộng xác định số vị trí cần thiết để hiển thị vừa
đủ nội dung của dữ liệu. Để trình bày dữ liệu đẹp hơn, người ta thường chèn thêm bổ
từđộ_rộng giúp xác định sốlượng vị trí tối thiểu cần cho việc hiển thị dữ liệu.
Nếu độ_rộng lớn hơn độ dài thực tế của dữ liệu thì các vị trí dư thừa sẽđược lấp
đầy bằng các khoảng trống hoặc số 0. Trong trường hợp không có độ_rông, hoặc
độ_rộng nhỏ hơn hoặc bằng độ dài thực tế của dữ liệu thì C sẽ dành ra số vị trí đúng
73
Độ rộng Ý nghĩa
n Dành ra tối thiểu n vị trí, điền khoảng trắng vào vị trí còn trống
0n Dành ra tối thiểu n vị trí, điền số 0 vào vị trí còn trống
* Số vị trí tối thiểu sẽ được xác định dựa vào đối số tương ứng
Bảng 2.3 – Cách thức đưa thêm bổ từđộ rộng vào hàm printf()
Chú ý rằng, khi sử dụng ‘*’ thì độ rộng không được chỉ rõ trong chuỗi định dạng. Vì thế, ta cần phải đưa thêm một đối số có kiểu số nguyên đứng trước đối số cần in
theo định dạng. Ví dụ: 1.#include <stdio.h> 2.#include <conio.h> 3.int main () 4.{ 5. int x = 55, y = 33;
6. printf("Gia tri 'x - y' in o cac dang khac nhau:\n");
7. printf("Do rong:5,canh phai\n %5d \n", x - y);
8. printf("Do rong:5,canh trai\n %-5d \n", x - y);
9. printf("Do rong:5,chen them so 0\n %05d \n",x - y);
10. printf("Do rong:10\n %*d \n",10, x - y);
11. printf("Gia tri o he 16: %-#7x \n",x - y);
12. printf("Gia tri o he 8 : %#7o \n",x - y);
13. getch();
14. return 0;
15. }
Kết quả của chương trình:
Gia tri 'x - y' in o cac dang khac nhau: Do rong:5,canh phai 22 Do rong:5,canh trai 22 Do rong:5,chen them so 0 00022 Do rong:10 22 Gia tri o he 16: 0x16 Gia tri o he 8 : 026 d. Bổ từ“Độ chính xác” Bổ từ độ_chính_xác được bắt đầu bằng dấu ‘.’ và phải là một số nguyên.
74
.Độ chính xác Ý nghĩa
.m
- d, ld, u, lu, o, x, X: chỉ ra số chữ số tổi thiểu cần in ra.
Nếu giá trị cần in có số chữ số nhỏ hơn m thì các số 0 được chèn thêm vào trước giá trị. Nếu m = 0, thì các giá trị là 0 sẽ không được in ra.
- e, f: chỉ ra số chữ số cần in ra sau dấu chấm thập phân. Độ chính xác mặc định là 6.
- s: chỉ ra số kí tự tối đa có thể in ra được của một chuỗi.
.* Độ chính xác dựa vào đối số tương ứng.
Bảng 2.4 – Cách thức đưa thêm bổ từđộ chính xác vào hàm printf()
Ví dụ: 1.#include <stdio.h> 2.#include <conio.h> 3.int main () 4.{ 5. float g = 13.246;
6. char str[] = "Hello you";
7. int num = 15;
8. printf("So thuc ban dau: %f \n",g);
9. printf("Lay 2 chu so thap phan: %.2f \n", g);
10. printf("Chuoi ban dau: %s \n",str);
11. printf("Lay 5 ki tu: %.5s \n",str);
12. printf("So nguyen ban dau: %d\n",num);
13. printf("Do chinh xac la 4: %.4d\n",num);
14. getch();
15. return 0;
16. }
Kết quả của chương trình:
So thuc ban dau: 13.246000 Lay 2 chu so thap phan: 13.25 Chuoi ban dau: Hello you
Lay 5 ki tu: Hello So nguyen ban dau: 15 Do chinh xác la 4: 0015
2.1.2Hàm nhập có định dạng
Nhập dữ liệu là cách đưa dữ liệu vào trong chương trình và lưu trữ nó tại một vị trí xác định trong bộ nhớ. Hàm scanf() cho phép thực hiện đọc các loại dữ liệu khác
nhau được nhập từ bàn phím theo định dạng nào đó. Cú pháp sử dụng của hàm như
sau:
75 Trong đó, các đối số trong danh_sách_đối_số phải là địa chỉ của các biến dùng
để lưu trữ dữ liệu khi nhập vào. Địa chỉ của một biến được lấy ra bằng cách sử dụng toán tử lấy địa chỉ ‘&’ và đặt trước tên biến. Ví dụ, ta nhập vào giá trịlà 5 và lưu trữ
vào biến a thì đối số sẽ viết là &a. Việc quên dấu ‘&’ phía trước tên biến là một lỗi rất phổ biến mà người dùng hay mắc phải. Trình biên dịch cũng không tìm ra được lỗi này.
Chuỗi_định_dạng trong hàm scanf() để xác định khuôn dạng của các dữ liệu nhập vào. Nó có thể chứa các thành phần: kí tự trắng, kí tự khác trắng và đặc tảđịnh dạng.
- Kí tự trắng: Bao gồm các kí tự khoảng trắng (‘ ‘), kí tự tab (‘\t’), kí tự xuống dòng (‘\n’). Nếu trong chuỗi_định_dạng có một hoặc nhiều kí tự trắng liên tiếp thì hàm scanf() sẽ bỏ qua và chờcho đến khi đọc được kí tự khác trắng tiếp theo.
Ví dụ: scanf(“%d \n“, &a);
Ở ví dụ này, sau khi nhập một sốnguyên đểlưu vào biến a thì hàm scanf() sẽ
chờ ta nhập một kí tự khác trắng thì mới kết thúc. Kí tự khác trắng này sẽ
nằm trong bộ nhớđệm và sẽđược đọc bởi hàm scanf() hoặc gets() tiếp theo. Vì vậy, ta cần phải chú ý khi sử dụng kí tự trắng để tránh trường hợp dữ liệu
được đọc và lưu trữ không chính xác.
- Kí tự khác trắng: Là kí tự bất kì ngoại trừ kí tự trắng hoặc là kí tự nằm trong
đặc tả định dạng. Nếu kí tự khác trắng có trong chuỗi_định_dạng thì kí tự
tiếp theo mà hàm scanf() đọc được phải đúng là kí tự khác trắng đó.
Ví dụ: scanf(“%d,%d”, &a, &b);
Sau khi đọc một số nguyên và lưu vào biến a thì hàm scanf() sẽ phải đọc
được dấu ‘,’. Nếu kí tự tiếp theo được nhập dấu ‘,’ thì hàm sẽ đọc nhưng không lưu vào bộ nhớ, sau đó sẽ chờ để đọc đến số nguyên kế tiếp rồi lưu
vào biến b. Ngược lại, nếu không gặp dấu ‘,’ thì hàm sẽ kết thúc và biến b nhận giá trịkhông xác định.
- Đặc tả định dạng: xác định cách thức dò đọc các kí tự được nhập vào, chuyển đổi chúng thành những giá trị có kiểu xác định và gán nó cho các đối sốtương ứng. Mỗi đối số sẽứng với một đặc tả, vì vậy sốđặc tả phải bằng số đối số. Dạng tổng quát của đặc tả:
%[*][độ_rộng]kí_tự_định_kiểu
Đặc tả định dạng là chuỗi bắt đầu bằng dấu ‘%’ và kết thúc bởi kí_tự_định_kiểu.
Ngoài ra còn có thể có các bổ từ tùy chọn như độ_rộng hoặc ‘*’.
a. Kí tựđịnh kiểu
Là thành phần quan trọng nhất trong chuỗi đặc tả. Nó xác định những kí tự nào sẽđược đọc vào, được chuyển đổi và lưu trữtrong đối số.
76
Bảng dưới đây liệt kê một số kí tựđịnh kiểu được sử dụng trong hàm scanf():
Kí tự
định kiểu Ý nghĩa Các kí tự hợp lệ
d, ld Số nguyên có dấu hệ 10 (int,