Giáo trình Lập trình căn bản (Phần 2) - Nghề: Kỹ thuật sửa chữa, lắp ráp máy tính - Trình độ: Cao đẳng liên thông - Trường Cao đẳng nghề Vĩnh Long

pdf 34 trang Gia Huy 17/05/2022 2240
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Lập trình căn bản (Phần 2) - Nghề: Kỹ thuật sửa chữa, lắp ráp máy tính - Trình độ: Cao đẳng liên thông - Trường Cao đẳng nghề Vĩnh Long", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_can_ban_phan_2_nghe_ky_thuat_sua_chua_l.pdf

Nội dung text: Giáo trình Lập trình căn bản (Phần 2) - Nghề: Kỹ thuật sửa chữa, lắp ráp máy tính - Trình độ: Cao đẳng liên thông - Trường Cao đẳng nghề Vĩnh Long

  1. 44 CHƯƠNG 4: HÀM Mục tiêu − Trình bày được khái niệm hàm; − Trình bày được qui tắc xây dựng hàm, thủ tục và vận dụng khi thiết kế xây dựng chương trình; − Phân biệt được cách sử dụng tham số, tham biến; − Sử dụng được các lệnh kết thúc và lấy giá trị trả về của hàm − Thực hiện các thao tác an toàn cho máy. Nội dung 1. Khái niệm chương trình con Hàm là một đoạn chương trình có tên và có chức năng giải quyết một số vấn đề chuyên biệt cho chương trình chính, nó có thể được gọi nhiều lần với các tham số khác nhau và trả lại một giá trị nào đó cho chương trình gọi nó. Hàm thường được sử dụng khi: - Nhu cầu tái sử dụng: có một số công việc được thực hiện ở nhiều nơi (cùng một chương trình hoặc ở nhiều chương trình khác nhau), bản chất không đổi nhưng giá trị các tham số cung cấp khác nhau ở từng trường hợp. - Nhu cầu sửa lỗi và cải tiến: giúp phân đoạn chương trình để chương trình được trong sáng, dễ hiểu và do đó rất dễ dàng phát hiện lỗi cũng như cải tiến chương trình. 1.1. Cú pháp Trong đó: - : là bất kỳ kiểu dữ liệu nào của C như char, int, long, float hay double Nếu hàm đơn thuần chỉ thực hiện một số câu lệnh mà không cần trả về cho chương trình gọi nó thì kiểu trả về này là void. - : là tên gọi của hàm và được đặt theo quy tắc đặt tên/định danh. - : xác định các đối số sẽ truyền cho hàm. Các tham số này giống như khai báo biến và cách nhau bằng dấu phẩy. Hàm có thể không có đối số nào. - : là các câu lệnh sẽ được thực hiện mỗi khi hàm được gọi. - : là giá trị trả về cho hàm thông qua câu lệnh return. Ví dụ: Hàm sau đây có tên là Tong, nhận vào hai đối số kiểu nguyên và trả về tổng của hai số nguyên đó. /* Hàm tên tổng
  2. 45 Nhận vào hai số nguyên và trả về một số nguyên */ int Tong(int a, int b){ return a + b; } Hàm sau đây có tên là Xuat, nhận vào một đối số kiểu nguyên và xuất số nguyên đó ra màn hình. Hàm này không trả về gì cả. void Xuat(int n){ printf(“%d”, n); } Hàm sau đây có tên là Nhap, không nhận đối số nào cả và trả về giá trị số nguyên người dùng nhập vào. int Nhap(){ int n; printf(“Nhap mot so nguyen: ”); scanf(“%d”, &n); return n; } 1.2. Một số lưu ý Hàm phải được khai báo và định nghĩa trước khi sử dụng và thường đặt ở trên hàm chính (hàm main). int Tong(int a, int b){ return a + b; } void main(){ int a = 2912, b = 1706; int sum = Tong(a, b); // Loi goi ham } Thông thường, trước hàm main ta chỉ xác định tên hàm, các tham số và giá trị trả về của hàm để thông báo cho các hàm bên dưới biết cách sử dụng của nó còn phần định nghĩa hàm sẽ được đưa xuống dưới cùng. Phần ở trên này được gọi là nguyên mẫu hàm (function prototype). Nguyên mẫu hàm chính là tiêu đề hàm được kết thúc bằng dấu chấm phẩy. int Tong(int a, int b); // prototype hàm Tong void main(){ int a = 2912, b = 1706; int sum = Tong(a, b); // Lời gọi hàm } int Tong(int a, int b) // Mô tả hàm tổng {
  3. 46 return a + b; } Trên thực tế, nguyên mẫu hàm không cần thiết phải giống tuyệt đối tiêu đề hàm. Tên tham số có thể khác hoặc bỏ luôn miễn là cùng kiểu. Tuy nhiên, không nên để chúng khác nhau vì như vậy sẽ gây rối cho chương trình. Ví dụ sau cho thấy có thể bỏ hẳn tên tham số: int Tong(int, int); // prototype ham Tong 2. Cấu trúc chương trình có sử dụng chương trình con Ví dụ 1 Kết quả in ra màn hình Giải thích chương trình - Dòng 8 đến dòng 14: định nghĩa hàm line, hàm này không trả về giá trị, thực hiện công việc in ra 19 dấu sao.
  4. 47 - Dòng 5: khai báo prototype, sau tên hàm phải có dấu chấm phẩy. - Trong hàm line có sử dụng biến i, biến i là biến cục bộ chỉ sử dụng được trong phạm vi hàm line. - Dòng 18 và 20: gọi thực hiện hàm line. Trình tự thực hiện chương trình Không có dấu chấm phẩy sau tên hàm, phải có cặp dấu ngoặc ( ) sau tên hàm nếu hàm không có tham số truyền vào. Phải có dấu chấm phẩy sau tên hàm khai báo prototype. Nên khai báo prototype cho dù hàm được gọi nằm trước hay sau câu lệnh gọi nó. Ví dụ 2
  5. 48 Kết quả in ra màn hình 2 mu 2 = 4. 2 mu 3 = 8. _ Giải thích chương trình - Hàm power có hai tham số truyền vào là ix, in có kiểu int và kiểu trả về cũng có kiểu int. - Dòng 13: return ip: trả về giá trị sau khi tính toán. - Dòng 18: đối mục 2 và 3 có kiểu trả về là int sau khi thực hiện gọi power. - Hai tham số ix, in của hàm power là dạng truyền tham trị. Thực hiện chương trình Quy tắc đặt tên hàm giống tên biến, hằng Mỗi đối số cách nhau = dấu phẩy kèm theo kiểu dữ liệu tương ứng. Ví dụ 3
  6. 49 - Hàm time có hai tham số truyền vào là ix, in có kiểu int. 2 tham số này có toán tử địa chỉ & đi trước cho biết 2 tham số này là dạng truyền tham biến. Trình tự thực hiện chương trình 3. Các hàm trong ngôn ngữ lập trình Muốn hàm thực hiện thì trong hàm gọi nó phải thực hiện lời gọi hàm. Việc này được thực hiện bằng cách gọi tên của hàm đó đồng thời truyền biến hoặc trị cho các tham số mà chương trình con đã khai báo, các biến hoặc trị này cách nhau bằng dấu phẩy. Ví dụ 1: chương trình sau định nghĩa thủ tục XuatSo cho phép xuất các số từ a đến b ra màn hình (a và b được truyền vào hàm). Các tham số đều là tham trị. #include void XuatSo(int a, int b); void main(){ XuatSo(5, 20); // Goi ham lan 1 int x = 5; XuatSo(x, x + 5); // Goi ham lan 2 } void XuatSo(int a, int b){ for (int i = a; i <= b; i++)
  7. 50 printf(“%d\n”, i); } Ví dụ 2: chương trình sau định nghĩa hàm HoanVi cho phép hoán vị giá trị của 2 số a và b truyền vào thủ tục. Các tham số đều là tham chiếu. #include void HoanVi(int &x, int &y); void main(){ int a, b; printf(“Nhap 2 so a va b: ”); scanf(“%d%d”, &a, &b); printf(“Truoc: a = %d, b = %d”, a, b); HoanVi(1, 5); HoanVi(a, b); printf(“Sau: a = %d, b = %d”, a, b); } void HoanVi(int &x, int &y){ int tam = x; x = y; y = tam; } Nhập a = 1, b = 5. Sau khi gọi hàm HoanVi(a, b) giá trị của a = 5, b = 1. Cách gọi HoanVi(1, 5) sai do phải là biến. 4. Tham trị và tham biến Tham số trong hàm là kiểu đối số mà chương trình chính truyền khi gọi hàm. Có hai cách truyền tham số sau đây: 4.1. Tham trị - Truyền đối số cho hàm ở dạng giá trị. - Được sử dụng khi ta không có nhu cầu thay đổi giá trị của tham số sau khi thực hiện hàm. 4.2 Tham biến - Truyền đối số cho hàm ở dạng địa chỉ. - Tham chiếu được bắt đầu bằng ký hiệu & trong khai báo. Ví dụ 1: void thamtri(int n); // Truyền giá trị void thambien(int &n); // Truyền dạng địa chỉ Ví dụ 2:
  8. 51 void thamtri(int ix, int iy) { ix += 1; iy += 1; } void thambien(int &ix, int &iy) { ix += 1; iy += 1; } void main(void){ Kết quả in ra: int ia=5,ib=5; thamtri(ia,ib); printf("a=%d,b=%d",ia,ib); a = 5, b = 5 thambien(ia, ib); printf("a=%d,b=%d",ai,ib); a = 6, b = 6 } 5. Biến toàn cục và biến địa phương Biến toàn cục là những biến được sử dụng mọi nơi trong chương trình. Còn biến địa phương chỉ có giá trị trong thời gian hoạt động, sau khi hàm kết thúc thì những biến khai báo bên trong hàm đó cũng như các tham số của nó cũng kết thúc. 5.1. Biến toàn cục Ví dụ: Dòng File Edit Search Run Compile Debug Project Option Window Help 1 #include 2 #include 3 4 // khai báo prototype 5 void oddeven(); 6 void negative(); 7 8 //khai báo biến toàn cục 9 int inum; 10 11 void main(void)
  9. 52 12 { 13 printf("Nhap vao 1 so nguyen : "); 14 scanf("%d", &inum); 15 oddeven(); 16 negative(); 17 getch(); 18 } 19 20 // hàm kiểm tra chẳn lẻ 21 void oddeven() 22 { 23 if (inum % 2) 24 printf("%d la so le.\n", inum); 25 else 26 printf("%d la sochan.\n", inum); 27 } 28 29 //Hàm kiểm tra số âm 30 void negative() 31 { 32 if (inum < 0) 33 printf("%d la so am.\n", inum); 34 else 35 printf("%d la so duong.\n", inum); 36 } F1 Help Alt-F8 Next Msg Alt-F7Prev Msg Alt - F9 Compile F9 Make F10 Menu Kết quả in ra màn hình Giải thích chương trình Chương trình trên gồm 2 hàm oddeven và negative, 2 hàm này ta thấy không có tham số để truyền biến inum vào xử lý nhưng vẫn cho kết quả đúng. Do chương trình sử dụng biến inum toàn cục (dòng 9) nên biến này có ảnh hưởng đến toàn bộ chương
  10. 53 trình mỗi khi gọi và sử dụng nó. Xét tình huống sau: Giả sử trong hàm negative ta khai báo biến inum có kiểu int như sau: void negative() { int inum; . } Khi đó chương trình sẽ cho kết quả sai! Do các câu lệnh trong hàm negative sử dụng biến inum sẽ sử dụng biến inum khai báo trong hàm negative và lúc này biến inum toàn cục không có tác dụng đối với các câu lệnh trong hàm này. Biến inum khai báo trong hàm negative chỉ có ảnh hưởng trong phạm vi hàm và chu trình sống của nó bắt đầu từ lúc gọi hàm đến khi thực hiện xong. 5.2. Biến địa phương Các biến trong hàm là biến địa phương. Biến địa phương chỉ tồn tại trong thời gian hàm đó hoạt động. Tầm tác dụng của biến địa phương chỉ hạn chế trong hàm mà nó được khai báo. Các biến địa phương cũng sẽ không có mối liên hệ nào với biến toàn cục có cùng tên và cùng kiểu. Ví dụ int n; main() { int p; } ham_thi_du() { int p int n; . } - Các biến địa phương không lưu trữ kết quả cho các lần sau. Lần nào biết lần ấy, các biến địa phương được sinh ra rồi chết luôn khi ra khỏi hàm. - Các tham số cũng là biến địa phương. Nghĩa là cũng chỉ hoạt động khi hàm đó được gọi
  11. 54 BÀI TẬP Lý thuyết 1. Hàm là gì? Tại sao phải sử dụng hàm? 2. Trình bày các thành phần của hàm. 3. Trình bày tóm tắt các cách truyền tham số? Phân biệt sự khác nhau giữa các cách này. Cho ví dụ minh họa. Thực hành 4. Viết hàm nhập một số nguyên bất kỳ. Hãy đọc giá trị của số nguyên đó nếu nó có giá trị từ 0 đến 9, ngược lại thông báo không đọc được. 5. Viết hàm hập 3 số nguyên a, b và c từ bàn phím. Hãy tìm số có giá trị nhỏ nhất ( hoặc lớn nhất). 6. Viết hàm tính tiền đi taxi từ số km nhập vào. Biết: - 1 km đầu giá 15000đ - Từ km thứ 2 đến km thứ 5 giá 13500đ - Từ km thứ 6 trở đi giá 11000đ - Nếu đi hơn 120 km sẽ được giảm 10% trên tổng số tiền. 7. Viết hàm nhập vào tháng, in ra tháng đó có bao nhiêu ngày. Hướng dẫn: Nhập vào tháng Nếu là tháng 1, 3, 5, 7,8, 10, 12 thì có 30 ngày Nếu là tháng 4, 6, 9, 11 thì có 31 ngày Nếu là tháng 2 và là năm nhuận thì có 29 ngày ngược lại 28 ngày (Năm nhuận là năm chia chẵn cho 4) 8. Viết chương trình nhập vào 2 số x, y và 1 trong 4 toán tử +, -, *, /. Nếu là + thì in ra kết quả x + y, nếu là – thì in ra x – y, nếu là * thì in ra x * y, nếu là / thì in ra x / y (nếu y = 0 thì thông báo không chia được) 9. Viết hàm nhận vào một số nguyên dương n và thực hiện: a. Có phải là số đối xứng? Là số nghịch đảo bằng chính nó. Ví dụ: 121, b. Có phải là số chính phương? Là số bằng bình phương số khác. Ví dụ: 4, 9, c. Có phải là số nguyên tố? Là số lớn hơn 1 và chỉ có 2 ước số là 1 và nó. Ví dụ: 2, 3, 5, 7, 11, 13, d. Chữ số lớn nhất và nhỏ nhất? Ví dụ: số 1706, nhỏ nhất 0 và lớn nhất 7 e. Các chữ số có tăng dần hay giảm dần không? Ví dụ: 12245, 156, 442, 941, 10. Viết hàm nhận vào một số nguyên dương n và thực hiện: a. S = 1 + 2 + + n b. S = 12 + 22 + + n2 c. S = 1 + 1/2 + + 1/n d. S = 1! + 2! + + n! 11. Viết hàm trả về USCLN của 2 số nguyên. 12. Viết hàm in ra n phần tử của dãy Fibonacy
  12. 55 CHƯƠNG 5: DỮ LIỆU KIỂU MẢNG (ARRAY), CHUỖI KÝ TỰ (STRING) VÀ BẢN CHI (STRUCT) Mục tiêu − Trình bày được khái niệm mảng, chuỗi ký tự và bản ghi; − Thực hiện cách khai báo, gán giá trị cho mảng, chuỗi ký tự và bản ghi; − Thực hiện các thao tác và truy xuất cho mảng, chuỗi ký tự và bản ghi; − Thực hiện các thao tác an toàn với máy tính. Nội dung 1. Dữ liệu kiểu mảng 1.1. Khái niệm Mảng là một tổ chức kiểu dữ liệu có cấu trúc bao gồm một số cố định các thành phần có cùng kiểu. Mỗi thành phần của mảng được truy xuất thông qua các chỉ số mô tả vị trí của thành phần đó trong mảng. 1.2. Khai báo mảng 2.2.1. Khai báo kiểu mảng Cú pháp: typedef [ ]; Trong đó: - : tên kiểu mảng theo quy định đặt tên/định danh. - : kiểu dữ liệu của các thành phần trong mảng. - : số lượng phần tử của mảng. Ví dụ: khai báo kiểu dữ liệu mảng một chiều có tên MangInt (gồm 20 phần tử kiểu số nguyên) và MangFloat (gồm 30 phần tử kiểu số thực). typedef int MangInt[20]; typedef float MangFloat[30]; 2.2.2. Khai báo biến mảng Biến mảng được khai báo trực tiếp (tường minh) như sau: Cú pháp: [ ]; 2.2.3. Khởi tạo giá trị cho mảng khi khai báo Ta có thể khởi tạo giá trị cho mảng một chiều thông qua các cách sau: - Khởi tạo giá trị cho mọi phần tử của mảng.
  13. 56 int a[4] = {2912, 1706, 1506, 1904}; Mảng a gồm 4 phần tử 2912, 1706, 1506, 1904 - Khởi tạo giá trị cho một số phần tử đầu tiên của mảng. Các phần tử còn lại sẽ có giá trị 0. int a[4] = {2912, 1706}; Mảng a gồm 4 phần tử 2912, 1706, 0, 0 - Khởi tạo giá trị 0 cho tất cả các phần tử của mảng, ta chỉ cần khởi tạo phần tử đầu bằng 0. int a[100] = {0}; - Trình biên dịch tự xác định số phần tử của mảng thông qua danh sách khởi tạo nếu số phần tử không được chỉ rõ. int a[] = {2912, 1706, 1506, 1904}; Mảng a sẽ gồm 4 phần tử 2912, 1706, 1506, 1904. 1.3. Gán giá trị cho mảng 1.3.1. Truy xuất dữ liệu kiểu mảng Truy xuất đến từng phần tử của mảng thông qua cú pháp sau: Cú pháp: [ ][ ] [ ] Trong đó , , , : là các giá trị cụ thể của phần tử trong mảng muốn truy xuất. Lưu ý, mảng a có n phần tử thì chỉ số của mảng sẽ từ 0 đến n–1. Tức mà các phần tử của mảng là a[0], a[1], , a[n-1]. Ví dụ, cho hai mảng sau: int MangSo[100]; float DiemHK[100][2]; Lúc này, phần tử thứ 3 của mảng có chỉ số là 2: MangSo[2], điểm thi môn thứ nhất của sinh viên thứ 2: DiemHK[1, 0] Không thể nhập xuất trực tiếp biến kiểu mảng mà phải thông qua từng thành phần của mảng đó. Ví dụ: printf(“%d”, MangSo); // Sai printf(“%d”, MangSo[2]); // Dung printf(“%f”, DiemHK); // Sai printf(“%f”, DiemHK[1][0]); // Dung Không thể dùng lệnh gán thông thường để gán dữ liệu giữa hai kiểu mảng cùng loại. Thay vào đó, ta sẽ gán dữ liệu trực tiếp giữa từng phần tử tương ứng.
  14. 57 Gán trực tiếp từng phần tử [ ] = [ ]; Ví dụ: typedef int MangSo[3]; MangSo a, b = {1, 2, 3}; a = b; // Sai for (int i=0; i<3; i++) // Dung a[i] = b[i]; 1.3.2. Truyền mảng cho hàm Tham số kiểu mảng trong khai báo hàm giống khai báo mảng. void SapXepTang(int a[100]); Tham số kiểu mảng được truyền cho hàm chính là địa chỉ của phần tử đầu tiên của mảng do đó số lượng phần tử trong tham số mảng có thể bỏ trống hoặc ta khai báo dạng con trỏ. void SapXepTang(int a[]); // Cach 1 void SapXepTang(int *a); // Cach 2 Do ta chỉ truyền địa chỉ của phần tử đầu tiên của mảng nên số thành phần thực sự được sử dụng phải được truyền cho hàm thông qua một tham số khác. // n la so phan tu thuc su duoc su dung void SapXepTang(int a[], int n); void SapXepTang(int *a, int n); Do biến mảng chính là địa chỉ của phần tử đầu tiên của mảng đó nên khi gọi hàm, ta chỉ việc truyền tên biến mảng cho hàm. Lưu ý, nội dung của mảng có thể thay đổi khi kết thúc hàm. void NhapMang(int a[], &n); void SapXepTang(int a[], int n); void XuatMang(int a[], n); void main(){ int a[100]; int n; NhapMang(a, n); // Goi ham NhapMang SapXepTang(a, n); // Goi ham SapXepTang XuatMang(a, n); // Goi ham XuatMang } 1.4. Một số bài toán trên mảng 1.4.1. Một số qui ước
  15. 58 Mảng được xét là mảng các số nguyên và số phần tử tối đa của mảng là MAX = 100. #define MAX 100 1.4.2. Nhập mảng Yêu cầu Viết thủ tục nhập mảng cho phép người sử dụng nhập số lượng phần tử n thực tế của mảng a và lần lượt nhập vào giá trị cho từng phần tử trong mảng này. Ý tưởng - Nhập số lượng phần tử thực tế n của mảng. - Lần lượt nhập giá trị cho n phần tử của mảng từ chỉ số 0 đến chỉ số n – 1. Cài đặt Thủ tục nhập mảng Đầu vào : mảng a, số lượng phần tử n (tham chiếu) Đầu ra : không có void NhapMang(int a[], int &n){ // Nhap so luong phan tu n cua mang printf(“Nhap so phan tu n: ”); scanf(“%d”, &n); // Nhap gia tri cho n phan tu cua mang for (int i = 0; i < n; i++){ printf(“Nhap phan phan tu thu %d: ”, i); scanf(“%d”, &a[i]); } } Lưu ý - Tham số n (số lượng phần tử) phải là tham chiếu (có dấu &) vì nội dung sẽ thay đổi sau khi thực hàm. - Vì số lượng phần tử lớn nhất là MAX nên khi cần có thể kiểm tra xem n có vượt quá MAX hay không trước khi cho nhập mảng. 1.4.3. Xuất mảng Yêu cầu Viết thủ tục xuất mảng cho phép người sử dụng xuất nội dung mảng a cho trước với số lượng phần tử là n. Ý tưởng - Lần lượt xuất giá trị của n phần tử trong mảng từ chỉ số 0 đến chỉ số n – 1.
  16. 59 Cài đặt Thủ tục xuất mảng Đầu vào : mảng a, số lượng phần tử n Đầu ra : không có void XuatMang(int a[], int n){ // Xuat gia tri cua N phan tu trong mang printf(“Noi dung cua mang la: ”); for (int i = 0; i < n; i++) printf(“%d ”, a[i]); printf(“\n”); } Lưu ý: Tham số n không cần thiết phải là tham chiếu (không cần &) vì nội dung sẽ không thay đổi sau khi thực hiện hàm. 1.5. Mảng nhiều chiều 1.5.1. Khái niệm Ví dụ: Khảo sát ma trận:
  17. 60 1.5.2. Khai báo kiểu mảng 2 chiều Cú pháp: typedef [ ][ ]; N1, N2: số lượng phần tử mỗi chiều Ví dụ: typedef int MaTran[3][4]; Cú pháp (tường minh) [ ][ ]; Cú pháp (không tường minh – thông qua kiểu) Typedef [ ][ ]; ; , ; Ví dụ: (tường minh) int a[10][20], b[10][20]; int c[5][10]; int d[10][20]; Ví dụ: (không tường minh – thông qua kiểu) typedef int MaTran10x20[10][20]; typedef int MaTran5x10[5][10]; MaTran10x20 a, b; MaTran11x11 c; MaTran10x20 d; 1.5.3. Truy xuất đến một phần tử Thông qua chỉ số [ ][ ]
  18. 61 Ví dụ: Cho mảng 2 chiều như sau: int a[3][4]; Các truy xuất Hợp lệ: a[0][0], a[0][1], , a[2][2], a[2][3] Không hợp lệ: a[-1][0], a[2][4], a[3][3] Gán dữ liệu kiểu mảng Không được sử dụng phép gán thông thường mà phải gán trực tiếp giữa các phần tử. = ; // sai [ ][ ] = Ví dụ: int a[5][10], b[5][10]; b = a; //sai int i, j; for (i = 0; i < 5; i++) for (j = 0; j< 10; j++ ) b[i][j] = a[i][j]; Truyền tham số cho hàm - Tham số kiểu mảng trong khai báo hàm giống như khai báo biến mảng void NhapMaTran(int a[50][100]); - Tham số kiểu mảng truyền cho hàm chính là địa chỉ của phần tử đầu tiên của mảng. • Có thể bỏ số lượng phần tử chiều thứ 2 hoặc con trỏ. • Mảng có thể thay đổi nội dung sau khi thực hiện hàm. void NhapMaTran(int a[][100]); void NhapMaTran(int (*a)[100]); Truyền mảng cho hàm - Số lượng phần tử thực sự truyền qua biến khác. void XuatMaTran(int a[50][100], int m, int n); void XuatMaTran(int a[][100], int m, int n); void XuatMaTran(int (*a)[100], int m, int n); - Lời gọi hàm void XuatMaTran(int a[][100], int &m, int &n); void XuatMaTran(int a[][100], int m, int n); void main(){ int a[50][100], m, n; NhapMaTran(a, m , n); XuatMaTran(a, m, n); }
  19. 62 1.5.4. Một số bài toán cơ bản Một số qui ước Kiểu dữ liệu: #define MAXD 50 #define MAXC 50 Nhập ma trận Yêu cầu: Cho phép nhập mảng a, m dòng, n cột. Ý tưởng: - Cho trước một mảng 2 chiều có dòng tối đa là MAXD, số cột tối đa là MAXC. - Nhập số lượng phần tử thực sự m, n của mỗi chiều. - Nhập từng phần tử từ [0][0] đến [m-1][n-1]. Hàm nhập ma trận void NhapMaTran(int a[][MaxC], int &m, int &n){ printf(“Nhap so dong, so cot cua ma tran: ”); scanf(“%d%d”,&m, &n); int i, j; for (i = 0; i<m; i++) for (j = 0; j<n; j++){ printf(“Nhap a[%d][%d]: ”,i,j); scanf(“%d”,&a[i][j]); } } Xuất ma trận Yêu cầu: cho phép nhập mảng a, m dòng, n cột. Ý tưởng: xuất giá trị từng phần tử của mảng 2 chiều từ dòng có 0 đến dòng m -1, mỗi dòng xuất giá trị của cột 0 đến cột n-1 trên dòng đó. Hàm xuất ma trận: void XuatMaTran(int a[][MAXC], int m, int n){ int i, j; for (i = 0; i<m; i++){ for (j = 0; j<n; j++) printf(“%d”,a[i][j]); printf(“\n”); } }
  20. 63 2. Dữ liệu kiểu chuỗi ký tự 2.1. Khái niệm Chuỗi ký tự là một dãy gồm các ký tự hoặc một mảng các ký tự được kết thúc bằng ký tự '\0' (còn được gọi là ký tự NULL trong bảng mã Ascii). Các hằng chuỗi ký tự được đặt trong cặp dấu nháy kép "". 2.2. Khai báo chuỗi 2.2.1. Khai báo theo mảng Cú pháp: char [Chiều dài tối đa] Ví dụ: Trong chương trình, ta có khai báo: char Ten[12]; Trong khai báo này, bộ nhớ sẽ cung cấp 12-1 bytes để lưu trữ nội dung của chuỗi ký tự Ten; byte cuối cùng lưu trữ ký tự ‘\0’ để chấm dứt chuỗi. Ghi chú: Chiều dài tối đa không nên khai báo thừa để tránh lãng phí bộ nhớ, nhưng cũng không nên khai báo thiếu. 2.2.2. Khai báo theo con trỏ Cú pháp: char * Ví dụ: Trong chương trình, ta có khai báo: char *Ten; Trong khai báo này, bộ nhớ sẽ dành 2 byte để lưu trữ địa chỉ của biến con trỏ Ten đang chỉ đến, chưa cung cấp nơi để lưu trữ dữ liệu. Muốn có chỗ để lưu trữ dữ liệu, ta phải gọi đến hàm malloc() hoặc calloc() có trong “alloc.h”, sau đó mới gán dữ liệu cho biến. 2.2.3. Vừa khai báo vừa gán giá trị Ví dụ: #include #include int main(){ char Chuoi[]="Mau nang hay la mau mat em" ; printf("Vua khai bao vua gan trị : %s",Chuoi) ; getch(); return 0; } Ghi chú: Chuỗi được khai báo là một mảng các ký tự nên các thao tác trên mảng có thể áp dụng đối với chuỗi ký tự.
  21. 64 2.3. Các thao tác trên chuỗi Không thể gán giá trị hay sử dụng phép toán + (ghép chuỗi) và các phép toán so sánh như: > (lớn hơn), ; 2.3.1. Cộng chuỗi - Hàm strcat() Cú pháp: char *strcat(char *des, const char *source) Hàm này có tác dụng ghép chuỗi nguồn vào chuỗi đích. Ví dụ: Nhập vào họ lót và tên của một người, sau đó in cả họ và tên của họ lên màn hình. #include #include #include int main(){ char HoLot[30], Ten[12]; printf("Nhap Ho Lot: ");gets(HoLot); printf("Nhap Ten: ");gets(Ten); strcat(HoLot,Ten); /* Ghep Ten vao HoLot*/ printf("Ho ten la: ");puts(HoLot); getch(); return 0; } 2.3.2 Xác định độ dài chuỗi - Hàm strlen() Cú pháp: int strlen(const char* s); Ví dụ: Sử dụng hàm strlen xác định độ dài một chuỗi nhập từ bàn phím. #include #include #include int main(){ char Chuoi[255]; int Dodai; printf("Nhap chuoi: ");gets(Chuoi); Dodai = strlen(Chuoi) printf("Chuoi vua nhap: ");puts(Chuoi); printf("Co do dai %d",Dodai); getch();
  22. 65 return 0; } 2.3.3. Đổi một ký tự thường thành ký tự hoa - Hàm toupper() Hàm toupper() (trong ctype.h) được dùng để chuyển đổi một ký tự thường thành ký tự hoa. Cú pháp: char toupper(char c) 2.3.4. Đổi chuỗi chữ thường thành chuỗi chữ hoa, hàm strupr() Hàm struppr() được dùng để chuyển đổi chuỗi chữ thường thành chuỗi chữ hoa, kết quả trả về của hàm là một con trỏ chỉ đến địa chỉ chuỗi được chuyển đổi. Cú pháp: char* strupr(char *s) Ví dụ: Viết chương trình nhập vào một chuỗi ký tự từ bàn phím. Sau đó sử dụng hàm strupr() để chuyển đổi chúng thành chuỗi chữ hoa. #include #include #include int main(){ char Chuoi[255],*s; printf("Nhap chuoi: ");gets(Chuoi); s=strupr(Chuoi) ; printf(“Chuoi chu hoa: ”);puts(s); getch(); return 0; } 2.3.5. Đổi chuỗi chữ hoa thành chuỗi chữ thường, hàm strlwr() Muốn chuyển đổi chuỗi chữ hoa thành chuỗi toàn chữ thường, ta sử dụng hàm strlwr(), các tham số của hàm tương tự như hàm strupr(); Cú pháp: char *strlwr(char *s) 2.4. Nhập, xuất chuỗi Để xuất chuỗi, ta có thể sử dụng hàm printf với đặc tả “%s” hoặc hàm puts như sau:
  23. 66 Hàm xuất dữ liệu ra màn hình (#include ) int puts(const char *s); Hàm puts xuất chuỗi s ra màn hình và tự động xuống dòng. Nếu thành công sẽ trả về giá trị không âm, ngược lại sẽ trả về EOF. Ví dụ: char ten[] = “THCS A”; printf(“%s”, ten); // Khong xuong dong puts(ten); // Tu dong xuong dong Để nhập chuỗi, ta có thể sử dụng hàm scanf( ) với đặc tả “%s” nhưng hàm này chỉ đọc các ký tự từ bàn phím đến khi gặp ký tự khoảng trắng. Ví dụ: char ten[100; scanf(“%s”, &ten); puts(ten); Nếu nhập vào “THCS A” thì chỉ nhận được chuỗi “THCS” Để nhập được một chuỗi đầy đủ, ta sử dụng hàm sau: Hàm nhập dữ liệu từ bàn phím (#include ) char *gets(char *s); Hàm gets đọc tất cả các ký tự nhập từ bàn phím đến khi gặp ký tự sang dòng mới (khi ta nhấn enter). Hàm gets sẽ loại bỏ ký tự enter và thêm vào chuỗi ký tự kết thúc chuỗi ‘\0’. Hàm gets trả về địa chỉ của chuỗi nhận được. Ví dụ: char ten[100]; gets(ten); puts(ten); 2.5. Các hàm làm việc với chuỗi 2.5.1. Sao chép một phần chuỗi, hàm strncpy() Hàm này cho phép chép n ký tự đầu tiên của chuỗi nguồn sang chuỗi đích. Cú pháp: char *strncpy(char *Des, const char *Source, size_t n) 2.5.2. Trích một phần chuỗi, hàm strchr() Để trích một chuỗi con của một chuỗi ký tự bắt đầu từ một ký tự được chỉ định trong chuỗi cho đến hết chuỗi, ta sử dụng hàm strchr().
  24. 67 Cú pháp: char *strchr(const char *str, int c) Ghi chú: - Nếu ký tự đã chỉ định không có trong chuỗi, kết quả trả về là NULL. - Kết quả trả về của hàm là một con trỏ, con trỏ này chỉ đến ký tự c được tìm thấy đầu tiên trong chuỗi str. 2.5.3. Tìm kiếm nội dung chuỗi, hàm strstr() Hàm strstr() được sử dụng để tìm kiếm sự xuất hiện đầu tiên của chuỗi s2 trong chuỗi s1. Cú pháp: char* strstr(const char *s1, const char *s2) Kết quả trả về của hàm là một con trỏ chỉ đến phần tử đầu tiên của chuỗi s1 có chứa chuỗi s2 hoặc giá trị NULL nếu chuỗi s2 không có trong chuỗi s1. Ví dụ: Viết chương trình sử dụng hàm strstr() để lấy ra một phần của chuỗi gốc bắt đầu từ chuỗi "hoc". 1. #include 2. #include 3. #include 4. int main() 5. { 6. char Chuoi[255],*s; 7. printf("Nhap chuoi: ");gets(Chuoi); 8. s=strstr(Chuoi,"hoc"); 9. printf("Chuoi trich ra: ");puts(s); 10. getch(); 11. return 0; 12. } 2.5.4. So sánh chuỗi, hàm strcmp() Để so sánh hai chuỗi theo từng ký tự trong bảng mã Ascii, ta có thể sử dụng hàm strcmp(). Cú pháp: int strcmp(const char *s1, const char *s2) Hai chuỗi s1 và s2 được so sánh với nhau, kết quả trả về là một số nguyên (số này có được bằng cách lấy ký tự của s1 trừ ký tự của s2 tại vị trí đầu tiên xảy ra sự khác nhau). - Nếu kết quả là số âm, chuỗi s1 nhỏ hơn chuỗi s2. - Nếu kết quả là 0, hai chuỗi bằng nhau. - Nếu kết quả là số dương, chuỗi s1 lớn hơn chuỗi s2.
  25. 68 2.5.5. So sánh chuỗi, hàm stricmp() Hàm này thực hiện việc so sánh trong n ký tự đầu tiên của 2 chuỗi s1 và s2, giữa chữ thường và chữ hoa không phân biệt. Cú pháp: int stricmp(const char*s1, const char *s2) Kết quả trả về tương tự như kết quả trả về của hàm strcmp(). 2.5.6. Khởi tạo chuỗi, hàm memset() Hàm này được sử dụng để đặt n ký tự đầu tiên của chuỗi là ký tự c. Cú pháp: memset(char *Des, int c, size_t n) 2.5.7. Đổi từ chuỗi ra số, hàm atoi(), atof(), atol() (trong stdlib.h) Để chuyển đổi chuỗi ra số, ta sử dụng các hàm trên. Cú pháp: − int atoi(const char *s): chuyển chuỗi thành số nguyên − long atol(const char *s): chuyển chuỗi thành số nguyên dài − float atof(const char *s): chuyển chuỗi thành số thực Nếu chuyển đổi không thành công, kết quả trả về của các hàm là 0. Ngoài ra, thư viện string.h còn hỗ trợ các hàm xử lý chuỗi khác, ta có thể đọc thêm trong phần trợ giúp. 3. Dữ liệu kiểu bản ghi 3.1. Khái niệm Kiểu cấu trúc (Structure) là kiểu dữ liệu bao gồm nhiều thành phần có kiểu khác nhau, mỗi thành phần được gọi là một trường (field). Sự khác biệt giữa kiểu cấu trúc và kiểu mảng là: các phần tử của mảng là cùng kiểu còn các phần tử của kiểu cấu trúc có thể có kiểu khác nhau. Định nghĩa kiểu cấu trúc Cách 1: struct
  26. 69 { ; ; ; }; Cách 2: Sử dụng từ khóa typedef để định nghĩa kiểu: typedef struct{ ; ; . ; } ; Trong đó: - : là một tên được đặt theo quy tắc đặt tên của danh biểu; tên này mang ý nghĩa sẽ là tên kiểu cấu trúc. - (i=1 n): mỗi trường trong cấu trúc có dữ liệu thuộc kiểu gì (tên của trường phải là một tên được đặt theo quy tắc đặt tên của danh biểu). Ví dụ 1: Để quản lý ngày, tháng, năm của một ngày trong năm ta có thể khai báo kiểu cấu trúc gồm 3 thông tin: ngày, tháng, năm. struct NgayThang{ typedef struct{ unsigned char Ngay; unsigned char Ngay; unsigned char Thang; unsigned char Thang; unsigned int Nam; unsigned int Nam; }; } NgayThang; Ví dụ 2: Mỗi sinh viên cần được quản lý bởi các thông tin: mã số sinh viên, họ tên, ngày tháng năm sinh, giới tính, địa chỉ thường trú. Lúc này ta có thể khai báo một struct gồm các thông tin trên. struct SinhVien{ typedef struct{ char MSSV[10]; char MSSV[10]; char HoTen[40]; char HoTen[40]; struct NgayThang NgaySinh; NgayThang NgaySinh; int Phai; int Phai; char DiaChi[40]; char DiaChi[40]; }; }SinhVien;
  27. 70 3.2. Khai báo kiểu bản ghi Việc khai báo biến cấu trúc cũng tương tự như khai báo biến thuộc kiểu dữ liệu chuẩn. Cú pháp: Đối với cấu trúc được định nghĩa theo cách 1: struct [, ]; Đối với các cấu trúc được định nghĩa theo cách 2: [, ]; Ví dụ: Khai báo biến NgaySinh có kiểu cấu trúc NgayThang; biến SV có kiểu cấu trúc SinhVien. struct NgayThang NgaySinh; NgayThang NgaySinh; struct SinhVien SV; SinhVien SV; 3.3. Truy xuất kiểu bản ghi Cú pháp: . Khi sử dụng cách truy xuất theo kiểu này, các thao tác trên . giống như các thao tác trên các biến của kiểu dữ liệu của . Ví dụ: Viết chương trình cho phép đọc dữ liệu từ bàn phím cho biến mẩu tin SinhVien và in biến mẩu tin đó lên màn hình: #include #include #include typedef struct{ unsigned char Ngay; unsigned char Thang; unsigned int Nam; } NgayThang; typedef struct{ char MSSV[10]; char HoTen[40]; NgayThang NgaySinh;
  28. 71 int Phai; char DiaChi[40]; } SinhVien; /* Hàm in lên màn hình 1 mẩu tin SinhVien*/ void InSV(SinhVien s){ printf("MSSV: | Ho va ten | Ngay Sinh | Dia chi\n"); printf("%s | %s | %d-%d-%d | %s\n",s.MSSV,s.HoTen, s.NgaySinh.Ngay,s.NgaySinh.Thang,s.NgaySinh.Nam,s .DiaChi); } /* Hàm main */ int main(){ SinhVien SV, s; printf("Nhap MSSV: ");gets(SV.MSSV); printf("Nhap Ho va ten: ");gets(SV.HoTen); printf("Sinh ngay: ");scanf("%d",&SV.NgaySinh.Ngay); printf("Thang: ");scanf("%d",&SV.NgaySinh.Thang); printf("Nam: ");scanf("%d",&SV.NgaySinh.Nam); printf("Gioi tinh (0: Nu), (1: Nam): "); scanf("%d",&SV.Phai); flushall(); printf("Dia chi: ");gets(SV.DiaChi); InSV(SV); s=SV; /* Gán trị cho mẩu tin s*/ InSV(s); getch(); return 0; } Lưu ý: Các biến cấu trúc có thể gán cho nhau. Thực chất đây là thao tác trên toàn bộ cấu trúc không phải trên một trường riêng rẽ nào. Chương trình trên dòng s=SV là một.
  29. 72 Ví dụ: Với các biến kiểu cấu trúc ta không thể thực hiện được các thao tác sau đây: o Sử dụng các hàm xuất nhập trên biến cấu trúc. o Các phép toán quan hệ, các phép toán số học và logic. 4.4.2. Khởi tạo cấu trúc Việc khởi tạo cấu trúc có thể được thực hiện trong lúc khai báo biến cấu trúc. Các trường của cấu trúc được khởi tạo được đạt giữa 2 dấu { và }, chúng được phân cách nhau bởi dấu phẩy (,). Ví dụ: Khởi tạo biến cấu trúc NgaySinh: struct NgayThang NgaySinh ={29, 8, 1986};
  30. 73 BÀI TẬP MẢNG (ARRAY) Lý thuyết 1. Mảng là gì? Trường hợp nào thì sử dụng mảng? 2. Bảng ghi là gì? Trường hợp nào thì sử dụng bảng ghi? 3. Tập hợp là gì? Trường hợp nào thì sử dụng kiểu tập hợp? 4. Tình bày các cách khai báo kiểu, biến, hằng mảng, bảng ghi, tập hợp và cho ví dụ minh họa. 5. Trình bày các thao tác truy xuất trên mảng, bảng ghi, tập hợp. Cho ví dụ minh họa từng trường hợp. Thực hành 6. Viết chương trình nhập vào một mảng, hãy xuất ra màn hình: - Phần tử lớn nhất của mảng. - Phần tử nhỏ nhất của mảng. - Tính tổng của các phần tử trong mảng. 7. Viết chương trình nhập vào một dãy n số thực a[0], a[1], , a[n-1], sắp xếp dãy số theo thứ tự từ lớn đến nhỏ. In dãy số sau khi sắp xếp. 8. Viết chương trình sắp xếp một mảng theo thứ tự tăng dần sau khi đã loại bỏ các phần tử trùng nhau. 9. Viết chương trình nhập vào một dãy các số theo thứ tự tăng, nếu nhập sai quy cách thì yêu cầu nhập lại. In dãy số sau khi đã nhập xong. Nhập thêm một số mới và chèn số đó vào dãy đã có sao cho dãy vẫn đảm bảo thứ tự tăng. In lại dãy số để kiểm tra. 10. Viết chương trình nhập vào một ma trận (mảng hai chiều) các số nguyên, gồm m hàng, n cột. In ma trận đó lên màn hình. Nhập một số nguyên khác vào và xét xem có phần tử nào của ma trận trùng với số này không ? Ở vị trí nào ? Có bao nhiêu phần tử? 11. Viết chương trình nhập vào một mảng số tự nhiên. Hãy xuất ra màn hình: - Dòng 1: gồm các số lẻ, tổng cộng có bao nhiêu số lẻ. - Dòng 2: gồm các số chẵn, tổng cộng có bao nhiêu số chẵn. - Dòng 3: gồm các số nguyên tố. - Dòng 4: gồm các số không phải là số nguyên tố. 12. Viết chương trình thực hiện việc đảo một mảng một chiều. Ví dụ: 1 2 3 4 5 7 9 10 đảo thành 10 9 7 5 4 3 2 1 . 13. Viết chương trình thực hiện việc trộn hai dãy có thứ tự thành một dãy có thứ tự. Yêu cầu không được trộn chung rồi mới sắp thứ tự. Khi trộn phải tận dụng được tính chất đã sắp của hai dãy con. 14. Viết chương trình nhập vào một mảng các số thực từ bàn phím. Hãy viết chương
  31. 74 trình định nghĩa hàm tính số lớn nhất của 2 số thực và sử dụng hàm này để tìm số lớn nhất trong mảng nói trên. Hướng dẫn: xây dựng hàm tìm số lớn nhất của 2 số thực. Nhập vào mảng rồi gọi hàm vừa định nghĩa. float max_xy(float x, float y){ return x>y?x:y; } void main(){ float m[100], max; int n; printf(“Nhap vao so phan tu n cua mang: ”); scanf(“%d”,&n); for(int i=1;i<=n;i++) scanf(“%f”,&m[i]); max=m[1]; for(i=2;i<=n;i++) max=max_xy(max,m[i]); } 15. Viết chương trình trong đó có các hàm: Nhập dãy số, kiểm tra dãy số tăng dần, chèn một số vào vị trí thích hợp trong dãy tăng dần. Trong hàm main() yêu cầu nhập dãy số và một số. Kiểm tra nếu dãy số tăng dần thì chèn số vào vị trí thích hợp trong dãy. CHUỐI KÝ TỰ (SRING) Lý thuyết 1. Trình bày khái niệm kiểu chuỗi? 2. Mô tả cách khai báo và sử dụng nó. Cho ví dụ minh họa Thực hành 3. Viết hàm upper(char s[]) đổi toàn bộ các ký tự sang ký tự hoa (giống hàm strupr) 4. Viết hàm lower(char s[]) đổi toàn bộ các ký tự sang ký tự thường (giống hàm strlwr) 5. Viết hàm proper(char s[]) đổi các ký tự đầu tiên của mỗi từ sang ký tự hoa. 6. Viết hàm standard(char s[]) bỏ toàn bộ khoảng trắng đầu chuỗi, cuối chuỗi và giữa 2 từ trong s chỉ còn 1 khoảng trắng. 7. Xóa tất cả các khoảng trắng của s 8. Đếm xem có bao nhiêu từ trong s. Xuất các từ trên các dòng liên tiếp. 9. Tìm từ có chiều dài dài nhất và in ra. 10. Trích ra n ký tự đầu tiên/cuối cùng/bắt đầu tại vị trí pos.
  32. 75 11. Viết chương trình nhập một chuỗi ký tự từ bàn phím, xuất ra màn hình chuỗi đảo ngược của chuỗi đó. Ví dụ đảo của "abcd egh" là "hge dcba". 12. Viết chương trình nhập một chuỗi ký tự và kiểm tra xem chuổi đó có đối xứng không. Ví dụ : Chuỗi ABCDEDCBA là chuỗi đối xứng. 13. Nhập vào một chuỗi bất kỳ, hãy đếm số lần xuất hiện của mỗi loại ký tự. 14. Viết chương trình nhập vào một chuỗi rồi xuất chuỗi đó ra màn hình dưới dạng mỗi từ một dòng. Ví dụ: "Nguyễn Văn Minh" In ra : Nguyễn Văn Minh 15. Viết chương trình nhập vào một chuỗi, in ra chuỗi đảo ngược của nó theo từng từ. Ví dụ : chuỗi "Nguyễn Văn Minh" đảo thành "Minh Văn Nguyễn" 16. Viết chương trình nhập vào họ và tên của một người, cắt bỏ các khoảng trống không cần thiết (nếu có), tách tên ra khỏi họ và tên, in tên lên màn hình. Chú ý đến trường hợp cả họ và tên chỉ có một từ. 17. Viết chương trình nhập vào một danh sách họ và tên của n người theo kiểu chữ thường, đổi các chữ cái đầu của họ, tên và chữ lót của mỗi người thành chữ hoa. In kết quả lên màn hình. 18. Viết chương trình nhập vào một danh sách họ và tên của n người, tách tên từng người ra khỏi họ và tên rồi sắp xếp danh sách tên theo thứ tự từ điển. In danh sách họ và tên sau khi đã sắp xếp. BẢN GHI (STRUCT) Hãy định nghĩa kiểu: struct Hoso{ char HoTen[40]; float Diem; char Loai[10]; }; Viết chương trình nhập vào họ tên, điểm của n học sinh. Xếp loại văn hóa như sau: Điểm Xếp loại 9, 10 Giỏi 7, 8 Khá 5, 6 Trung bình Dưới 5 Không đạt
  33. 76 In danh sách lên màn hình theo dạng sau: XEP LOAI VAN HOA HO VA TEN DIEM XEP LOAI Nguyen Van A 7 Kha Ho Thi B 5 Trung binh Dang Kim C 4 Khong dat
  34. 77 TÀI LIỆU THAM KHẢO  [1]. Giáo trình môn Lập trìn C, TS Lê Mạnh Thạnh, NXB Giáo dục năm 2000. [2]. Giáo trình Kỹ thuật lập trình C, Nguyễn Linh Giang, Nguyễn Xuân Thực, Lê Văn Thái, NXB Giáo dục năm 2005. [3]. Giáo trình Tin học cơ sở A1 (Ngôn ngữ lập trình C), Đặng Bình Phương, Trường Đại Học Khoa Học Tự Nhiên TP. HCM. [4]. HanoiAptech Computer Education Center, Giáo trình Lập trình C căn bản [5].