Bài giảng Hệ thống máy tính và ngôn ngữ C - Chương 12: Pointer
12.1 Khái niệm
12.2 Thao tác trên POINTER
12.3 POINTER và mảng
12.4 Đối số của hàm là pointer -
truyền đối số theo số dạng tham
số biến
12.5 Hàm trả về pointer và
mảng
12.6 Chuỗi ký tự
12.7 Pointer và việc định vị
bộ nhớ động
12.8 Mảng các pointer
12.9 Pointer của pointer
12.10 Đối số của hàm MAIN
12.11 Pointer trỏ đến hàm
12.12 Ứng dụng
Bài tập cuối chương
Trang 1
Trang 2
Trang 3
Trang 4
Trang 5
Trang 6
Trang 7
Trang 8
Trang 9
Trang 10
Tải về để xem bản đầy đủ
Bạn đang xem 10 trang mẫu của tài liệu "Bài giảng Hệ thống máy tính và ngôn ngữ C - Chương 12: Pointer", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Bài giảng Hệ thống máy tính và ngôn ngữ C - Chương 12: Pointer
ng, cú pháp khai báo hàm như sau: kiểu * tên_hàm (danh_sách_khai_báo_đối_số); với kiểu là kiểu của đối tượng mà pointer được hàm trả về trỏ đến. CHƯƠNG 12 POINTER 12.5 HÀM TRẢ VỀ POINTER VÀ MẢNG Ví dụ: Có khai báo int * lon_nhat (int a, int b, int c); thì hàm lon_nhat() trả về một địa chỉ, địa chỉ đó có thể là địa chỉ của một int hoặc địa chỉ của một mảng các int, việc sử dụng địa chỉ theo đối tượng nào là do nơi gọi. CHƯƠNG 12 POINTER 12.5 HÀM TRẢ VỀ POINTER VÀ MẢNG Ví dụ: Thiết kế hàm nhập trị cho mảng các int int *nhap_tri (int *num) { static int a[10]; int i, n; printf ("Nhap kich thuoc mang:"); scanf ("%d", &n); *num = n; printf ("Nhap tri cho %d phan tu cua mang:", n); for (i = 0; i < n; i++) scanf ("%d", &a[i]); return a; /* a là địa chỉ đầu mảng cần trả về */ } CHƯƠNG 12 POINTER 12.5 HÀM TRẢ VỀ POINTER VÀ MẢNG Ví dụ: Chương trình sử dụng hàm nhập trị mảng #include #include int *nhap_tri(int *num); main() { int *pint, so_phan_tu, i; clrscr(); pint = nhap_tri (&so_phan_tu); printf ("Cac phan tu cua mang la:"); for (i =0; i <so_phan_tu; i++) printf ("%d", pint[i]); getch(); } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ Ví dụ: Khi khai báo “Hello, world!” thì chuỗi này sẽ được C ghi vào một nơi nào đó trong bộ nhớ và có địa chỉ xác định. Địa chỉ này có thể được gán vào cho một biến con trỏ trỏ đến ký tự để quản lý chuỗi. Ví dụ : Cho khai báo char s[20]; s = “Hello, world!”; Không hợp lệ CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 1- Nhập trị chuỗi Việc nhập trị cho chuỗi bao gồm hai bước: đầu tiên cần khai báo một nơi trống để chứa chuỗi, sau đó dùng một hàm nhập trị để lấy chuỗi. CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 1- Nhập trị chuỗi - Hàm gets() đọc các ký tự đến khi nào gặp ký tự quy định hàng mới (tức ký tự '\n', tức khi ta ấn phím ENTER) thì kết thúc việc nhập. Sau đó hàm này lấy tất cả các ký tự đã nhập trước ký tự '\n', gắn thêm vào cuối chuỗi một ký tự NUL ('\0') và trả chuỗi cho chương trình gọi. Prototype của hàm này trong file stdio.h: char * gets (char * s); CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 1- Nhập trị chuỗi Ví dụ: #include #include main() { char ten[41]; char *pten; clrscr(); printf ("Ban ten gi?\n"); pten = gets (ten); printf("%s? A! Chao ban %s\n", ten, pten); getch(); } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 1- Nhập trị chuỗi - Hàm scanf() cũng cho phép nhập chuỗi qua định dạng nhập %s. Việc nhập chuỗi sẽ kết thúc khi hàm scanf() gặp một trong các ký tự khoảng trắng, ký tự tab hay ký tự xuống hàng đầu tiên mà nó gặp. Đây chính là điểm khác nhau giữa hai hàm nhập chuỗi gets() và scanf(). CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 1- Nhập trị chuỗi Ví dụ: #include #include main() { char ten1[41], ten2[41]; clrscr(); printf(Moi ban nhap hai ten: ); scanf ("%s %s", ten1, ten2); printf("A! Chao hai ban %s va %s \n", ten1, ten2); getch(); } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 2- Xuất chuỗi Để xuất chuỗi, hai hàm thường hay được dùng là puts() và printf(). - Hàm puts: ta chỉ cần cung cấp cho hàm đối số là địa chỉ của chuỗi cần in. Hàm này sẽ đọc từng ký tự của chuỗi và in ra màn hình cho đến khi gặp ký tự NUL thì in ra màn hình thêm một ký tự xuống hàng nữa. Prototype của hàm này như sau: int puts (char * s); CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 2- Xuất chuỗi - Hàm printf () cũng cho phép xuất chuỗi ra màn hình nếu ta dùng định dạng xuất "%s" cho nó. Hàm này sẽ không tự động in thêm ký tự xuống hàng mới như hàm puts(). CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 2- Xuất chuỗi Ví dụ: #include #include main() { char ten[41]; clrscr(); printf ("Moi ban nhap ten: "); gets(ten); printf ("A! Chao ban: %s", ten); getch(); } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 3- Gán trị cho chuỗi Việc gán trị cho biến chuỗi thực tế là việc chép từng ký tự từ hằng chuỗi hoặc biến chuỗi đã biết sang một biến chuỗi khác. Trong C, thao tác này được thực hiện nhờ hàm strcpy(), hàm này có prototype trong file string.h như sau: char *strcpy(char *dest, const char *src); CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 3- Gán trị cho chuỗi Hàm strcpy có thể được mô tả như sau: char *strcpy(char *dest, const char *src) { int i; for (i = 0; (dest[i] = scr[i]) != '\0'; i++) ; return dest; } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 3- Gán trị cho chuỗi Ví dụ: #include #include #include main() { char ten1[41], ten2[41]; clrscr(); printf("Moi ban nhap ten: "); gets(ten1); strcpy (ten2, ten1); printf("A! Chao ban: %s", ten2); getch(); } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 4- Lấy chiều dài chuỗi Trong C, để lấy chiều dài chuỗi ta dùng hàm strlen(). Prototype của hàm này trong file string.h: size_t strlen(const char *s); với size_t là một kiểu nguyên, C quy định đây là unsigned. CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 4- Lấy chiều dài chuỗi Ví dụ: Xét chương trình nhập một chuỗi, đổi các ký tự thường của chuỗi đó thành ký tự hoa, in chuỗi đó ra lại màn hình. CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 4- Lấy chiều dài chuỗi #include #include #include main() { char ten[41]; int i; clrscr(); printf("Moi ban nhap ten: "); gets(ten); for ( i = 0; i < strlen (ten); i++) if (ten[i] >= 'a' && ten[i] <= 'z') ten[i] -= 32; printf ("A! Chao ban: %s", ten); getch();} CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 5- Nối chuỗi Để nối hai chuỗi lại, C có hàm chuẩn strcat(). Hàm này nhận hai chuỗi làm đối số, và một bản sao của chuỗi thứ hai sẽ được chép nối vào cuối của chuỗi thứ nhất, để tạo ra chuỗi mới. Chuỗi thứ hai vẫn không có gì thay đổi. Prototype của hàm này trong file string.h: char *strcat(char *dest, const char *src); Ví dụ 13.37(SGT) CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 6- So sánh chuỗi Hàm này là strcmp(), có prototype trong file string.h: int strcmp(const char *s1, const char*s2); Hàm này so sánh hai chuỗi s1 và s2 và trả về một trị là: - số dương nếu s1 > s2 - số âm nếu s1 < s2 - số 0 nếu s1 == s2 CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 6- So sánh chuỗi Ví dụ:Xét chương trình ví dụ sau đây #include #include #include main() { clrscr(); printf("%d \n", strcmp("QUAN", “quan”)); printf("%d \n', strcmp("QUAN", "QUAN")); printf("%d \n", strcmp("quan", "QUAN")); printf("%d \n", strcmp("quang”, “quanG")); printf("%d \n", strcmp("quang”, “quan")); getch(); } CHƯƠNG 12 POINTER 12.6 CHUỖI KÝ TỰ 6- So sánh chuỗi Chương trình cho xuất liệu: -32 0 32 32 103 CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG C cho phép khai báo các biến động, các biến này khi cần thì xin chỗ, không cần thì giải phóng vùng nhớ cho chương trình sử dụng vào mục đích khác. Các biến động này được cấp phát trong vùng nhớ heap, là vùng đáy bộ nhớ (vùng còn lại sau khi đã nạp các chương trình khác xong), và được quản lý bởi các biến pointer CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG Trong C có hai hàm chuẩn để xin cấp phát bộ nhớ động malloc() và calloc(), cả hai hàm đều có prototype nằm trong file alloc.h hoặc stdlib.h như sau: void *malloc(size_t size); void *calloc(size_t nitems, size_t size); CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG Nếu biến động được xin, sau khi dùng xong, vùng nhớ của nó không được giải phóng thì nó vẫn chiếm chỗ trong bộ nhớ, mặc dù chương trình đã kết thúc. C đưa ra hàm free() để giải phóng khối bộ nhớ được xin bằng hàm malloc() hoặc calloc(). Prototype của hàm free() trong file stdlib.h hoặc alloc.h như sau: void free (void * block); CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG Cấu trúc bộ nhớ LC-3 với ứng bộ nhớ heap CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG Ví dụ: Cần xin một khối bộ nhớ có 10 phần tử int, ta viết như sau: int *pint; pint = (int *) malloc (10 * siezof (int)); hoặc pint = (int *) calloc (10, siezof (int)); CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG Ví dụ: #include #include #include EXIT #include main() { int *pint, s = 0, i; pint = (int *) calloc (10, sizeof (int)); if (pint == NULL) { printf ("Khong du bo nho \n"); exit (1); } CHƯƠNG 12 POINTER 12.7 POINTER VÀ VIỆC ĐỊNH VỊ BỘ NHỚ ĐỘNG Ví dụ: clrscr(); printf ("Moi nhap 10 tri vao mang: "); for (i = 0; i <10; i++) scanf ("%d", &pint[i]); for (i = 0; i <10; i++) s += pint[i]; printf ("Tong cac phan tu cua mang la: %d \n", s); getch(); free (pint); } CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER Cú pháp khai báo mảng các pointer: kiểu * tên_mảng [Kích_thước]; Ví dụ: Khi khai báo int * pint[4]; CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER Ví dụ: Khi khai báo int * pint[4]; int a = 2, b = 3, c = 4, d = 5; pint[0] = &a; pint[1] = &b; pint[2] = &c; pint[3] = &d; CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER Ví dụ: Khi khai báo int * pint[4]; int a[3], b[3], c[3], d[3]; pint[0] = a; pint[1] = b; pint[2] = c; pint[3] = d; CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER Ví dụ 13.48, 13.49 (SGT) Ví dụ : Khi khai báo int a[4][5]; int *b[4]; thì khi truy xuất a[2][3] và b[2][3], C đều hiểu đây là các biến int CHƯƠNG 12 POINTER 12.8 MẢNG CÁC POINTER Một mảng các pointer cũng có thể được khởi động trị nếu mảng là mảng toàn cục hay mảng tĩnh. Ví dụ: static char *thu[7] = {"Thu 2", "Thu 3", "Thu 4", "Thu 5", "Thu 6", "Thu 7", "Chua nhat"}; CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER Cú pháp khai báo pointer này như sau: kiểu ** tên_pointer Ví dụ: int **pint; int*p; int a[4][4]; thì pint = &p; hoặc pint = (int **) &a; CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER CHƯƠNG 12 POINTER Thay vì truy xuất a[i][j], ta có thể truy xuất *(pint + m*i + j), với m là số phần tử trên một hàng của mảng hai chiều. 12.9 POINTER CỦA POINTER Ví dụ: #include #define MAX_ROW 3 #define MAX_COL 3 main() { int row, col; int *pint1; int a2d [MAX_ROW][MAX_COL] = { {0, 1, 2}, {10, 11, 12}, {20, 21, 22} }; CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER int **pint2; int (*pa2d)[MAX_ROW][MAX_COL]; /* Thu dia chi cua pointer va mang 2 chieu */ pint1 = a2d[1]; pa2d = &a2d; pint2 = (int **)&a2d; printf ("pint1 = a2d[1] = %p\n", pint1); printf ("*( *( ( int (*)[MAX_COL] ) pint2 + 1)+ 2)= %d\n", *( *( ( int (*)[MAX_COL] ) pint2 + 1)+ 2)); printf ("*( *(a2d + 1) + 2) = %d\n", *( *(a2d + 1) + 2)); CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER printf ("*pint1[2] = %d\n", pint1[2]); printf ("(*pa2d)[1][2] = %d\n", (*pa2d)[1][2]); printf ("Tri cua cac phan tu trong mang truy xuat qua pointer 2 lan:\n"); for (row = 0; row < MAX_ROW; row ++) { for (col = 0; col < MAX_COL; col ++) printf ("%d ", *( *( ( int (*)[MAX_COL] ) pint2 + row)+ col)); printf ("\n"); } getchar();} CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER Ví dụ : int *m[4]; int a = 1, b = 2, c = 3, d = 4; int **pint; pint = m; m[0] = &a; m[1] = &b; m[2] = &c; m[3] = &d; Thay vì truy xuất trực tiếp a, b, ..., ta có thể dùng pointer *(pint[i]) CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER Ví dụ: Xét khai báo sau: int ** pi; int * pint[4]; int a[3], b[3], c[3], d[3]; pi = pint; pint[0] = a; pint[1] = b; pint[2] = c; pint[3] = d; CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER CHƯƠNG 12 POINTER 12.9 POINTER CỦA POINTER Ví dụ 13.56(GT) CHƯƠNG 12 POINTER 12.10 ĐỐI SỐ CỦA HÀM MAIN C hoàn toàn cho phép việc nhận đối số vào hàm main(), có hai đối số C đã quy định theo thứ tự: int agrc: đối số cho biết số tham số đã nhập, kể cả tên chương trình. char *argv[]: mảng các pointer trỏ đến các chuỗi là tham số đi theo sau tên chương trình khi chạy chương trình từ DOS. CHƯƠNG 12 POINTER 12.10 ĐỐI SỐ CỦA HÀM MAIN Ví dụ: Xét chương trình ví dụ sau: #include #include main (int argc, char *argv[]) { int i; clrscr(); printf ("Cac doi so cua chuong trinh la: \n"); printf ("Ten chuong trinh la: %s \n", argv[0]); if ( argc >1 ) for (i = 1; i < argc; i++) printf ("Doi so thu %d: %s \n", i, argv[i]); getch(); } CHƯƠNG 12 POINTER 12.10 ĐỐI SỐ CỦA HÀM MAIN Nếu nhập từ bàn phím như sau C:\>thu_main tin thu 123 thì chương trình cho xuất liệu là: Cac doi so cua chuong trinh la: Ten chuong trinh la: C:\thu_main.exe Doi so thu 1: tinDoi so thu 2: thu Doi so thu 3: 123 Ví dụ 13.59(GT) CHƯƠNG 12 POINTER 12.11 POINTER TRỎ ĐẾN HÀM Cú pháp khai báo một pointer chỉ tới hàm: kiểu (* tên_pointer) (kiểu_các_đối_số); Chú ý: kiểu * tên_hàm (kiểu_các_đối_số); Hàm trả về pointer CHƯƠNG 12 POINTER 12.11 POINTER TRỎ ĐẾN HÀM Ví dụ: Nếu khai báo int (* p_function) (int, int); và đã có hàm int cong (int a, int b) { ... } Ta có thể: p_function = cong; tong = (*p_function) (m, n); CHƯƠNG 12 POINTER 12.11 POINTER TRỎ ĐẾN HÀM Ví dụ 13.62 (GT) CHƯƠNG 12 POINTER 12.12 ỨNG DỤNG 12.12.1 Danh sách liên kết là stack 12.12.2 Danh sách liên kết là queue (GT) CHƯƠNG 12 POINTER 12.12 ỨNG DỤNG BÀI TẬP CUỐI CHƯƠNG 1. Viết chương trình với một hàm cho phép truy xuất chuỗi trong stack (danh sách liên kết và mảng) và in ra màn hình thông tin theo thứ tự alphabet. 2. Dùng cấu trúc dữ liệu queue dạng danh sách liên kết, tính biểu thức dạng đa thức bất kỳ sau: f(x) = trong phần thông tin có hai vùng biến - hệ số - số mũ CHƯƠNG 12 POINTER ...n m 3 o 1 n 1 n a x a x a x a 12.12 ỨNG DỤNG BÀI TẬP CUỐI CHƯƠNG 3. Viết chương trình với một hàm duyệt toàn bộ các phần tử trong queue, trả về số phần tử trong queue. 4. Viết chương trình tạo một danh sách liên kết lưu các thông tin là các số nguyên theo thứ tự từ lớn tới nhỏ. Thiết kế hàm insert() cho phép chèn một phần tử lưu thông tin số vào vị trí có thứ tự phù hợp trong chuỗi. 5. Viết chương trình nhập vào một số số nguyên (chưa biết có bao nhiêu số nguyên). Loại bỏ cácsố nguyên bị lặp lại. In ra dãy số mới này. Ví dụ: Nhập 5 4 10 8 5 4 10 2 8 In ra: 5 4 10 8 2 CHƯƠNG 12 POINTER
File đính kèm:
- bai_giang_he_thong_may_tinh_va_ngon_ngu_c_chuong_12_pointer.pdf