Kỹ thuật lập trình - Bài 7: Kiểu con trỏ - Ngô Hữu Dũng

Tài liệu Kỹ thuật lập trình - Bài 7: Kiểu con trỏ - Ngô Hữu Dũng: Kỹ thuật lập trình Bài 7 – Kiểu con trỏ TS. Ngô Hữu Dũng Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017181 Khái niệm con trỏ (pointer) Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017182  Con trỏ là biến mà giá trị của nó là địa chỉ bộ nhớ  Địa chỉ bộ nhớ?  scanf(“%d”,&i); // &i là địa chỉ bộ nhớ của biến i  Khai báo  type * variable_name;  Con trỏ lưu địa chỉ bộ nhớ  int i = 20;  int * p; // Khai báo con trỏ p  p = &i; // Con trỏ p được gán bằng địa chỉ của biến i  Ta nói con trỏ p “trỏ vào” biến i i = 20 Biến Địa chỉ Giá trị i 0073FB60 20 p 0073FB54 0073FB60 p = 0073FB60 Con trỏ và địa chỉ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017183 1. int x; // Biến số nguyên x 2. int *p; // Con trỏ p kiểu số nguyên 3. p = &x; // p trỏ vào x 4. x = 20; 5. printf("%d ", x); // Giá trị của x 6. printf("%d ", *p); // Giá trị của x 7. printf("%p ", &x); // Địa chỉ của x 8. printf("%p ", p); // Địa chỉ của x 9. *p = 40; 10...

pdf30 trang | Chia sẻ: putihuynh11 | Lượt xem: 488 | Lượt tải: 0download
Bạn đang xem trước 20 trang mẫu tài liệu Kỹ thuật lập trình - Bài 7: Kiểu con trỏ - Ngô Hữu Dũng, để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Kỹ thuật lập trình Bài 7 – Kiểu con trỏ TS. Ngô Hữu Dũng Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017181 Khái niệm con trỏ (pointer) Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017182  Con trỏ là biến mà giá trị của nó là địa chỉ bộ nhớ  Địa chỉ bộ nhớ?  scanf(“%d”,&i); // &i là địa chỉ bộ nhớ của biến i  Khai báo  type * variable_name;  Con trỏ lưu địa chỉ bộ nhớ  int i = 20;  int * p; // Khai báo con trỏ p  p = &i; // Con trỏ p được gán bằng địa chỉ của biến i  Ta nói con trỏ p “trỏ vào” biến i i = 20 Biến Địa chỉ Giá trị i 0073FB60 20 p 0073FB54 0073FB60 p = 0073FB60 Con trỏ và địa chỉ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017183 1. int x; // Biến số nguyên x 2. int *p; // Con trỏ p kiểu số nguyên 3. p = &x; // p trỏ vào x 4. x = 20; 5. printf("%d ", x); // Giá trị của x 6. printf("%d ", *p); // Giá trị của x 7. printf("%p ", &x); // Địa chỉ của x 8. printf("%p ", p); // Địa chỉ của x 9. *p = 40; 10.printf("Gia tri: %d = %d" , *p, x); 11.printf("Dia chi: %p = %p" , p, &x); Kiểu con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017184  Khai báo: Dùng dấu *  int *p;  Địa chỉ của biến mà con trỏ trỏ vào  p = &x  Giá trị của biến mà con trỏ trỏ vào: Dùng dấu *  *p = x  In ra màn hình địa chỉ: Dùng %p  printf(“%p = %p”, p, &x);  Chú ý: Phân biệt các dấu * và các dấu & Sử dụng con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017185  Chưa trỏ vào biến  int *p;  *p = 40; // Run-time error!  Trỏ vào biến  int x, *p1, *p2;  p1 = &x; // Trỏ p1 vào biến x  *p1 = 40; // x = 40;  p2 = p1; // gán trực tiếp, tương đương với p2 = &x;  *p2 = 50; // x = 50;  *p1 = 60; // x = 60; Ví dụ vận dụng Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017186 1. int x, y, *px, *py=NULL; 2. px = &x; // px trỏ vào x 3. py = &y; // py trỏ vào y 4. *px = 10; 5. y = 15; 6. printf("x=%d\ny=%d\n",*px,*py); 7. (*px)++; ++*px; 8. *py += 5; 9. printf("x=%d\ny=%d\n",*px,*py); 10.printf("%d+%d=%d\n",x,y,*px + *py); 11.printf("%d*%d=%d\n",x,y,*px * *py); 12.printf("&x=%p\n&y=%p\n",px,py); Phạm vi ứng dụng con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017187  Con trỏ có thể trỏ vào bất kỳ dữ liệu nào  Một kiểu nguyên thủy: int, float, char  NULL (rỗng, không trỏ đến đâu)  Một hằng số  Một đối số của hàm  Một mảng/chuỗi  Một cấu trúc struct  Một hàm  Một con trỏ khác (con trỏ trỏ vào con trỏ)  Một ô nhớ cấp phát động  Một tập tin Lợi hại của con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017188  Có thể dùng để thao tác với bất kỳ loại dữ liệu nào  Thuật lợi để truy cập đến cấu trúc dữ liệu lớn  Sử dụng bộ nhớ linh hoạt  Cấp phát / giải phóng bộ nhớ động trong quá trình thực thi  Cấp phát bộ nhớ mới: Hàm malloc trong stdlib.h  Giải phóng bộ nhớ: Hàm free trong stdlib.h  Nếu sử dụng con trỏ không cẩn thận  Dễ nhầm lẫn  Khó tìm lỗi Kiểu nguyên thủy Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017189 1. // Con trỏ có thể trỏ vào các kiểu nguyên thủy 2. int i = 10, *pi; 3. float f = 1.2e2, *pf; 4. char c = 'r', *pc; 5. pi = &i; 6. pf = &f; 7. pc = &c; 8. printf("%d,%f,%c\n",*pi,*pf,*pc); 9. // Chú ý dùng đúng kiểu dữ liệu 10.pc = &f; // Warning! 11.pf = &i; // Warning! 12.pi = &c; // Warning! Con trỏ rỗng - NULL Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017190  NULL là giá trị đặc biệt của con trỏ  Không trỏ đến đâu  #define NULL 0  Được định nghĩa trong thư viện stdio.h  Sử dụng  Khởi tạo con trỏ: int *p = NULL;  Kiểm tra một con trỏ  if (p != NULL) printf(“%d”,*p);  if (p) printf(“%d”, *p);  Kết thúc một danh sách dữ liệu Con trỏ và hằng số Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017191  Con trỏ trỏ vào hằng số  int m, n;  const int *ip = &m;  ip = &n; // OK! Có thể thay đổi giá trị con trỏ  *ip = 10; // ERROR !!! Không thể thay đổi giá trị của biến  Con trỏ là hằng số: Chỉ trỏ vào một biến  int m, n;  int * const cip = &m;  *cip = 10; // OK! Có thể thay đổi giá trị của biến  cip = &n; // ERROR !!! Không thể thay đổi giá trị con trỏ Con trỏ và đối số của hàm Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017192 1. void swap (int *px, int *py) // Tham biến 2. { 3. int temp = *px; // Dùng dấu * 4. *px = *py; // để truy cập giá trị 5. *py = temp; 6. } 7. int a = 5, b = 7; 8. swap(&a, &b); // Truyền địa chỉ của biến 9. printf("a = %d, b = %d", a, b); Con trỏ và mảng Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017193  Con trỏ có thể trỏ vào một mảng  #define N 7  int a[N], b[N];  int *pa, *pb;  pa = a;  pb = &b[0];  int *pc;  pc = &b[5];  pa = a; // Mặc định trỏ vào phần tử đầu tiên của mảng, a[0] a[0] a[1] a[2] a[3] a[4] a[5] a[6] pa b[0] b[1] b[2] b[3] b[4] b[5] b[6] pb pc Con trỏ và phần tử của mảng Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017194  Địa chỉ của phần tử thứ i  pa + i = &a[i]  Giá trị của phần tử thứ i  *(pa + i) = pa[i] = a[i]  Ví dụ  *pa = 1;  *(pa+1) = 2;  pa[2] = 3;  *pb = 4;  *(pc-1) = 5;  *pc = 6; a[0] a[1] a[2] a[3] a[4] a[5] a[6] 1 2 3 pa b[0] b[1] b[2] b[3] b[4] b[5] b[6] 4 5 6 pb pc pa+1 pc-1 Ví dụ vận dụng Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017195 1. #define N 10 2. int a[N]; 3. int i, *pa, *pt; 4. pa = a; //Trỏ vào mảng, không dùng & 5. for (i=0;i<N;i++) 6. *(pa+i)=i; // *(pa+i)=a[i] 7. for (pt=pa;pt<pa+N;pt++) 8. printf("%d ",*pt); // *pt=a[i] 9. for (i=0;i<N;i++) 10. printf("%d ",pa[i]); // pa[i]=a[i] Mảng là con trỏ hằng số (constant pointer) Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017196  Mảng là con trỏ hằng số  int a[10];  int *pa;  pa = a; // a là con trỏ, pa có thể được gán cho a, không cần &a  pa++; // Con trỏ pa có thể thay đổi giá trị  a = pa; // ERROR! a là hằng số  a++; // ERROR! a là hằng số  Mảng a là con trỏ trỏ vào phần tử đầu tiên của mảng và không thể thay đổi giá trị địa chỉ Truyền đối số là mảng / chuỗi Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017197  Truyền đối số là một mảng vào một hàm  void sapxep(int a[], int n)  Địa chỉ của phần tử đầu tiên của mảng được truyền: &a[0]  Có thể thay thế bằng con trỏ  void sapxep(int *a, int n)  Tương tự với chuỗi  Tham số function(char s[]){} và function(char *s){} là tương đương Ví dụ truyền đối số là mảng/chuỗi Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017198 1. int printArray(int *pa, int n) 2. { 3. int *pt; 4. for (pt=pa;pt<pa+n;pt++) //gán, so sánh, tăng 5. printf("%d ",*pt); 6. } 7. int stringLength(char *s) 8. { 9. if(*s=='\0') 10. return 0; 11. else 12. return 1 + stringLength(++s); 13. } Các phép toán của con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017199  Phép gán hai con trỏ cùng kiểu dữ liệu  int a, *pa, *pb; pa=&a; pb = pa;  Cộng/trừ con trỏ với số nguyên  Tăng/giảm giá trị của con trỏ theo sizeof()  Ví dụ: pb+n tăng giá trị của p lên n x sizeof(int)  So sánh giữa hai con trỏ trỏ vào phần tử trong cùng một mảng  Các phép toán ==, !=, >, =, <=  Phép trừ giữa hai con trỏ trỏ vào phần tử trong cùng một mảng  Gán hoặc so sánh với NULL (zero) Ví dụ về các phép toán của con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017200 1. int printRevertArray(int *pa, int n) 2. { 3. int *pt = pa+n-1; // Cộng số tự nhiên 4. while (pt>=pa) // Phép so sánh 5. { 6. printf("%d ",*pt); pt--; // Phép toán giảm 7. } 8. } 9. int stringLength(char *s) 10. { 11. char *p = s; // Phép gán 12. while (*p!='\0') 13. p++; // Phép toán tăng 14. return p - s; // Phép trừ của con trỏ 15. } Con trỏ và chuỗi Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017201  Tương tự như với mảng nhưng chuỗi có một đặc điểm khác  Chuỗi kết thúc bằng ký tự rỗng, ‘\0’ 1. void stringCopy(char *s, char *t) 2. { 3. while (*t != '\0') 4. { 5. *s = *t; 6. s++; 7. t++; 8. } 9. *s = '\0'; // Ký tự rỗng kết thúc chuỗi 10. } Con trỏ và chuỗi (tt) Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017202 1. void stringCopy1(char *s, char *t) 2. { 3. while ((*s = *t) != '\0'){ //Gán, so sánh 4. s++; t++; // Tăng 5. } 6. } 7. void stringCopy2(char *s, char *t) 8. { 9. while ((*s++ = *t++) != '\0');//Gán, so sánh, tăng 10. } 11. void stringCopy3(char *s, char *t) 12. { 13. while (*s++ = *t++); // Gán, tăng 14. } Con trỏ và cấu trúc Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017203 1. struct t_date{ 2. int day; 3. int month; 4. int year; 5. }; 6. struct t_date today; // Biến cấu trúc 7. struct t_date *ptr; // Con trỏ kiểu cấu trúc 8. ptr = &today; // Trỏ vào cấu trúc 9. (*ptr).day = 15; // Truy cập member, cách 1 10. (*ptr).month = 9; // Dùng dấu ‘.’ 11. (*ptr).year = 2016; 12. ptr->day = 15; // Truy cập member, cách 2 13. ptr->month = 9; // Dùng dấu ‘->’ 14. ptr->year = 2016; Con trỏ và cấu trúc (2) Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017204 1. struct t_student{ 2. int ID; 3. char *ten; 4. struct t_date birth, *pB; 5. }; 6. struct t_student SV, *pSV; 7. pSV = &SV; // Trỏ vào cấu trúc t_stu 8. pSV->ID = 123; // SV.ID 9. pSV->ten = "Nguyen Van A";// SV.ten 10. pSV->birth.day = 16; // SV.birth.day 11. pSV->pB = &SV.birth; // Trỏ vào cấu trúc t_date 12. pSV->pB->month = 4; // SV.birth.month 13. (*pSV->pB).year = 1996; // SV.birth.year Con trỏ và cấu trúc (3) Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017205 1. ++pSV->ID; // Tăng giá trị ID 2. printf("%d ",pSV->ID); 3. printf("%c",*pSV->ten); //Ký tự đầu tiên ‘N’ 4. printf("%c",pSV->ten[1]); //Ký tự thứ 2 ‘g’ 5. printf("%s ",pSV->ten+2); //Từ ký tự ‘u’->hết 6. printf("%d ",++pSV->pB->day); //Tăng day 7. printf("%d ",(*pSV->pB).month); 8. printf("%d\n",SV.pB->year); 9. while(*pSV->ten!='\0') 10. printf("%c",*pSV->ten++); 11.printf("\n%s",pSV->ten); // !? Chuỗi rỗng !? 12.printf("%s",--pSV->ten); // !? Con trỏ và hàm Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017206  Hàm có thể trả về kiểu con trỏ  Đối số kiểu con trỏ 1. char * stringCopy4(char *s, char *t) 2. { 3. int count = 0; 4. do 5. count++; 6. while (*s++ = *t++); 7. return s-count; 8. } Con trỏ đến con trỏ Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017207  Con trỏ có thể chứa địa chỉ của con trỏ khác  char x;  char * y;  char ** z;  x = 'x';  y = &x;  z = &y; 'x' 00AFF75F00000078 x x x 00000078 00AFF75F 00AFF750 Con trỏ và cấp phát động Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017208  Con trỏ có thể được cấp phát bộ nhớ  Trỏ trực tiếp vào bộ nhớ động  Không cần thông qua một biến cụ thể 1. #include 2. int n ,*a , i; 3. scanf("%d", &n); 4. a =(int*)malloc(sizeof(int)*n); // Cấp phát bộ nhớ 5. for(i=0;i<n;i++) 6. a[i]=i; 7. for (i=0;i<n;i++) 8. printf("%d\n",a[i]); 9. free(a); // Giải phóng bộ nhớ Con trỏ và tập tin Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017209  Con trỏ có thể trỏ vào tập tin 1. #include < 2. FILE * pFile; 3. pFile = fopen ("myfile.txt","w"); 4. if (pFile!=NULL) 5. { 6. fputs ("fopen example",pFile); 7. fclose (pFile); 8. } 9. return 0; Hết bài 7 Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-2017210  Khái niệm con trỏ  Khái quát các ứng dụng của con trỏ  Kiểu nguyên thủy: int, float, char  NULL (rỗng, không trỏ đến đâu)  Hằng số  Đối số của hàm  Mảng/chuỗi  Cấu trúc struct  Hàm  Con trỏ trỏ vào con trỏ  Cấp phát động  Tập tin

Các file đính kèm theo tài liệu này:

  • pdfbai_giang_ky_thuat_lap_trinh_ts_ngo_huu_dung_ky_thuat_lap_trinh_ngo_huu_dung_bai_07_1973_1985332.pdf
Tài liệu liên quan