Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 17 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
17
Dung lượng
289,06 KB
Nội dung
Con trỏ, mảng quản lý nhớ EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ Biến trỏ biến có chứa địa vùng nhớ có kiểu xác định Kích thước trỏ tương đương int, nhiên kích thước vùng nhớ trỏ tới không xác định (con trỏ khơng chứa thơng tin kích thước) Khai báo cách thêm dấu * trước tên biến: int *pInt; char *pChar; struct SinhVien *pSV; int* int 10 Truy xuất giá trị thơng qua trỏ dùng tốn tử *: int aInt = *pInt; (*pInt hiểu biến int mà pInt trỏ tới) *pChar = 'A'; printf("Gia tri: %d", *pInt); EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Thay đổi địa trỏ tới Vì giá trị trỏ địa chỉ, nên thay đổi giá trị đó, biến trỏ trỏ tới vùng nhớ khác Gán địa cho trỏ phép gán thông thường int *pInt2; pInt2 = pInt; Toán tử địa &: tạo trỏ việc lấy địa pA a biến int a; int* pA = &a; 10 /* pA trỏ tới a */ & toán tử ngược với *, với biến a *&a tương đương với a, a trỏ &*a tương đương với a EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Minh hoạ char c = 'A'; int *pInt; short s = 50; int a = 10; Địa biến nhớ theo thứ tự tăng dần có tính chất minh hoạ Trong thực tế, stack cấp phát từ cao xuống thấp biến khai báo sau có địa nhỏ pInt = &a; *pInt = 100; Địa 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 Biến char c int* pInt short s int a … 'A' 1507 50 100 … Giá trị pInt: *pInt: &a: a: 1507 100 1507 100 EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ void* Là trỏ khơng mang thơng tin kiểu Có thể chuyển kiểu ngầm định sang kiểu trỏ khác, ngược lại (nhưng C++ khơng) void* pVoid; int *pInt; char *pChar; pInt = pVoid; pChar = pVoid; /* OK */ /* OK */ pVoid = pInt; pVoid = pChar; /* OK */ /* OK */ pChar = pInt; pChar = (char*)pInt; /* lỗi */ /* OK */ Khơng dùng tốn tử * với trỏ void* *pVoid /* lỗi */ Con trỏ void* dùng để làm việc với nhớ tuý để thao tác với biến chưa xác định kiểu memcpy(void* dest, const void* src, int size); EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ NULL Là trỏ chứa địa 0, kiểu (void*), mang ý nghĩa đặc biệt không trỏ tới địa nhớ Bản chất macro khai báo: #define NULL ((void*)0) Không gán giá trị cho trỏ NULL int *pInt = NULL *pInt = 100; /* lỗi */ Cần phân biệt trỏ NULL trỏ chưa khởi tạo (trỏ đến địa ngẫu nhiên) Con trỏ NULL thường dùng để xác định tính hợp lệ biến trỏ để tránh lỗi, gán trỏ NULL chưa tạm thời không dùng tới Vì NULL có giá trị nên so sánh trỏ với NULL bỏ qua biểu thức logic: if (p != NULL) … if (p) … EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Các phép toán với trỏ Tăng giảm: để thay đổi trỏ trỏ tới vị trí (tương ứng với kích thước kiểu trỏ tới) Địa 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 p-(1502) short *p p++ (1504) (1506) Cộng địa chỉ: tương ứng với kiểu trỏ tới Địa 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 p-2 (1500) short *p (1504) p+3 (1510) So sánh: trỏ kiểu so sánh địa với số nguyên (lớn, nhỏ, bằng) Hai trỏ kiểu trừ cho để số phần tử sai khác EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ mảng Mảng trỏ tĩnh (không thể thay đổi địa chỉ), chứa địa (trỏ) tới phần tử Có thể thao tác với biến kiểu mảng thao tác với trỏ, trừ việc gán địa cho int arr[] = {1, 2, 3, 4, 5}; int x; *arr = 10; /* như: arr[0] = 10; */ printf("%d", *(arr+2)); /* arr[2] */ arr = &x; /* lỗi */ Con trỏ hiểu mảng thao tác mảng int *p = arr; p[2] = 20; p = arr+2; p[0] = 30; /* như: arr[2] = 20; */ /* như: p = &arr[2]; */ /* như: arr[2] = 30; hoặc: *p = 30; */ Kết luận: trỏ mảng dùng thay cho nhau, tuỳ trường hợp mà dùng cho thuận tiện EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ mảng (tiếp) Khác biệt: Không gán địa cho biến kiểu mảng Biến kiểu mảng cấp phát nhớ cho phần tử (trong stack) từ khai báo Toán tử sizeof() với mảng cho biết kích thước thực mảng (tổng phần tử), dùng với trỏ cho biết kích thước thân (chứa địa chỉ) float arr[5]; sizeof(arr) trả 20 (5*4) float* p = arr; sizeof(p) trả với hệ thống 32 bit sizeof(arr)/sizeof(arr[0]) số phần tử mảng Với chất trỏ, dùng số âm với mảng: int arr[] = {1, 2, 3, 4, 5}; int *p = arr + 2; p[-1] = 10; /* như: arr[1] = 10; */ EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ tới trỏ Con trỏ trỏ tới trỏ khác: float x = 1.5; float *pX = &x; float **ppX = &pX; printf("%f", **ppX); ppX /* in giá trị 1.5 */ pX x 1.5 **ppX = 2.3; ppX pX x 2.3 Tương tự mảng chiều (hay mảng mảng, trỏ tới mảng, mảng trỏ) 10 EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Kiểu chuỗi ký tự Là mảng ký tự, kết thúc ký tự '\0' (khởi tạo mảng trỏ) char ten[10] = "Tung"; char ten[10] = {'T', 'u', 'n', 'g', '\0' }; (bằng mảng) char *ten = "Tung"; (khởi tạo trỏ trỏ) char *ten = {'T', 'u', 'n', 'g', '\0' }; /* sai */ Ví dụ tính độ dài chuỗi: for (n=0; *s; n++, s++) ; Một số hàm xử lý chuỗi thông dụng #include int strlen(s) char *strcpy(dst, src) copy chuỗi src sang chuỗi dst char *strcat(dst, src) nối thêm chuỗi src vào chuỗi dst int strcmp(str1, str2) so sánh chuỗi, kết quả: 1, 0, -1 char *strstr(s1, s2) 11 tính độ dài chuỗi s tìm vị trí chuỗi s2 s1 EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Xử lý dòng lệnh Tham số truyền cho chương trình từ dịng lệnh C:\>movefile abc.txt Documents Khai báo hàm main() int main(int argc, char* argv[]) { … } argc: số tham số từ dòng lệnh (argc ≥ 1) argv: mảng tham số dạng chuỗi ký tự Đường dẫn tên chương trình ln tham số Trong ví dụ trên: 12 argc: argv: [ "movefile", "abc.txt", "Documents" ] EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Cấp phát nhớ động Các biến khai báo tạo cấp phát nhớ khai báo (trong stack) Có cần cấp phát theo nhu cầu sử dụng mà khơng biết từ viết chương trình cấp phát động (trong heap) Cấp phát nhớ: #include void* malloc(int size) /* size: số byte cần cấp */ int *p = (int*)malloc(10*sizeof(int)); /*cấp 10 int*/ void* calloc(int num_elem, int elem_size) void* realloc(void* ptr, int size) Việc cấp phát không thành công trả NULL cần kiểm tra Huỷ (trả lại) vùng nhớ cấp phát: 13 void free(void* p); free(p); EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ tới struct, union Với trỏ tới struct union, dùng toán tử “->” để truy xuất biến thành phần thay dùng “*” “.” p->member tương đương với (*p).member Ví dụ: 14 typedef struct { int x, y; } Point; Point *pP = (Point*)malloc(sizeof(Point)); pP->x = 5; /* như: (*pP).x = 5; */ (*pP).y = 7; /* như: pP->y = 7; */ EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Lỗi sử dụng trỏ Trong ứng dụng thông thường, chương trình khơng truy xuất ngồi vùng nhớ cấp cho Phải kiểm sốt địa mà trỏ trỏ tới Hệ quả: 15 Không dùng trỏ chưa khởi tạo nên có thói quen gán trỏ NULL chưa khơng dùng, để sau kiểm tra khởi tạo hay chưa Chỉ gán địa biến tạo (biến tĩnh nhớ cấp phát) cho trỏ để đảm bảo trỏ trỏ tới vùng nhớ hợp lệ Phải kiểm tra độ dài vùng nhớ mà trỏ trỏ tới để không bị truy xuất vượt (lỗi buffer overflow) Khi vùng nhớ cấp phát khơng cịn dùng đến nữa, phải huỷ bỏ để sử dụng lại EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Kết luận Con trỏ đặc trưng quan trọng tạo nên sức mạnh C so với ngôn ngữ khác, dao hai lưỡi sử dụng sai việc gỡ lỗi khó khăn cần nắm vững sử dụng trỏ cách linh hoạt Con trỏ dùng nhiều trường hợp sau: Truyền giá trị từ hàm qua tham số Con trỏ hàm Cấu trúc liệu: chuỗi liên kết, hàng đợi, mảng động,… trở lại có liên quan 16 EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Bài tập Viết chương trình: • • • Nhập số ngun N Cấp phát mảng N số nguyên nhập liệu cho In hình mảng theo thứ tự ngược lại Viết chương trình nhập mảng số thực chưa biết trước số phần tử, không nhập số phần tử từ đầu (nhập đến đâu mở rộng mảng tới đó) Viết chương trình nhập chuỗi s1, sau copy s1 vào chuỗi s2 Viết chương trình nhập chuỗi s1 s2, sau so sánh xem s1 s2 có giống khơng Viết chương trình nhận chuỗi từ tham số dịng lệnh, sau tách thành mảng từ tương ứng Khai báo hai mảng float có giá trị tăng dần, viết chương trình trộn hai mảng thành mảng thứ theo thứ tự tăng dần 17 EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội ... (hay mảng mảng, trỏ tới mảng, mảng trỏ) 10 EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Kiểu chuỗi ký tự Là mảng ký tự, kết thúc ký tự ''\0'' (khởi tạo mảng. .. tiện EE3490: Kỹ thuật lập trình – HK1 2011/2012 Đào Trung Kiên – ĐH Bách khoa Hà Nội Con trỏ mảng (tiếp) Khác biệt: Không gán địa cho biến kiểu mảng Biến kiểu mảng cấp phát nhớ cho phần... *pVoid /* lỗi */ Con trỏ void* dùng để làm việc với nhớ tuý để thao tác với biến chưa xác định kiểu memcpy(void* dest, const void* src, int size); EE3490: Kỹ thuật lập trình – HK1 2011/2012