Bài giảng C căn bản - Chương 1: Kỹ thuật xử lý Mảng và Con trỏ
Mảng (array) là một dãy các phần tử có cùng kiểu dữ liệu được đặt liên tiếp trong bộ nhớ.
Mỗi phần tử được xác định bởi một chỉ số biểu thị vị trí của phần tử trong mảng.
Số lượng phần tử trong mảng được gọi là kích thước của mảng.
Kích thước của mảng là cố định và phải được xác định trước.
g long TongUocSo(int n) { long S; int i; S = 0; for (i = 1; i <n; i++) if(n%i ==0) S = S + i; return S; } 7 1.1. Khái niệm Mảng long TichUocSo(int n) { long P; int i; P = 1; for (i = 1; i <n; i++) if(n%i ==0) P = P * i; return P; } int SoHoanChinh(int n) { return ( TongUocSo(n )== TichUocSo(n )); } 8 1.1. Khái niệm Mảng Đếm các số a[1], a[2], , a[n] thõa điều kiện count = 0; Lặp i = 1, 2, 3, , n Nếu a[i ] thõa điều kiện thì Count = count + 1; Cuối lặp . Ví dụ : Đếm số phần tử dương , số phần tử âm , số phần tử bằng 0 trong mảng số nguyên a có n phần tử . 9 1.1. Khái niệm Mảng void Demso(int a[], int n, int & demduong , int&demam , int & demkhong ) { int i; demduong =0; demam = 0; demkhong = 0; for (i = 0; i < n; i++) { if ( a[i ]>0) ( demduong )++; if ( a[i ]<0) ( demam )++; if(a[i ]==0) ( demkhong )++; } } 10 1.1. Khái niệm Mảng Tìm phần tử đầu tiên trong mảng a thõa điều kiện j = -1, i = 1; Lặp ( trong khi (i<=n) và (j = -1)) Nếu a[i] thõa điều kiện thì j = i; Cuối nếu. i = i+1; Cuối lặp. Ví dụ : Tìm phần tử âm đầu tiên trong mảng a mà có tận cùng bằng 6. 11 1.1. Khái niệm Mảng int AmTanCung6(int a[], int n) { i = 0; j = -1; while (i < n && j ==-1) { if(a[i]<0 && -a[i] %10 ==6) j = i; i++; } re turn j; } 12 1.1. Khái niệm Mảng Tìm tất cả các phần tử mảng a thõa điều kiện m = 0; Lặp i = 1, 2, 3, , n Nếu ( a[i ] thõa điều kiện thì ) b[m] = a[i]; m = m + 1; Cuối nếu. Cuối lặp. Ví dụ: Tìm tất cả các phần tử chỉ xuất hiện một lần trong mảng số nguyên a, n phần tử. 13 1.1. Khái niệm Mảng int Dem(int a[], int n, int x) { int i, kq = 0; for(i = 0; i < n ; i++) if(a[i] == x) kq = kq + 1; return kq; } 14 1.1. Khái niệm Mảng void XuatHien01Lan(int a[], int n, int b[], int&m ) { m = 0; for(i = 0; i < n; i++) if(Dem(a, n, a[i]) == 1) { b[m] = a[i] m = m + 1; } } 15 1.1. Khái niệm Mảng Tìm phần tử lớn nhất, nhỏ nhất Bước 1: Chọn một phần tử xo và gán min := xo Bước 2: Lặp (cho đến khi chọn hết các phần tử của S) Chọn phần tử kế tiếp x, nếu min > x thì gán min := x; Ví dụ: Hãy tìm phần tử âm lớn nhất có tận cùng là 6 trong mảng a 16 1.1. Khái niệm Mảng void MaxAmTanCung6 ( int a[], int n) { int i, j; int max; j = AmTanCung6(a, n); if (j ==-1) return 0; else { max = a[j]; for (i = j+1; i < n; i++) if(a[i ]<0&&(-a[i]%10==6)) if (max < a[i ]) max = a[i ]; } return max; } 17 1.1. Khái niệm Mảng Sắp xếp mảng thõa một điều kiện ( giữ nguyên vị trí các phần tử khác ) Lặp i = 1, 2, , n -1 Lặp j = i +1, i + 2, , n Nếu ( a[i ], a[j ] thõa điều kiện ) thì Nếu a[i ] > a[j ] thì x = a[i]; a[i] = a[j]; a[j]= x; Cuối nếu. Cuối lặp j. Cuối lặp i. 18 1.2. Mảng hai chiều Khai báo mảng 2 chiều kiểu int gồm 10 dòng , 10 cột : int A[10][10]; Khai báo mảng 2 chiều kiểu float gồm 10 dòng , 10 cột : float b[10][10]; int A[3][4] = { {2,3,9,4} , {5,6,7,6} , {2,9,4,7} }; A[0][0] = 2; A[0][1] = 3; A[1][1] = 6; A[1][3] = 6; Khi nhập liệu cho mảng hai chiều , nếu là mảng các số nguyên thì ta nhập liệu theo cách thông thường . Nhưng nếu là mảng các số thực thì ta phải thông qua biến trung gian . 19 1.2. Mảng hai chiều Duyệt các phần tử của mảng . // Duyệt từng dòng từ trên xuống dưới . for(i = 0; i< so_dong ; i++) for(j = 0; j < so_cot ; j++) { // Xử lý a[i][j ]; } // Duyệt từng cột từ trái qua phải for(j = 0; j < so_cot ; j++) for(i = 0; i< so_dong ; i++) { // Xử lý a[i][j ]; } 20 1.2. Mảng hai chiều Duyệt các phần tử nằm trên cùng một dòng hay trên cùng một cột . // Duyệt các phần tử trên dòng thứ k (0 <=k < so_dong ) for (i = 0; i < so_cot ; i++) { // Xử lý phần tử a[k][i ]; } // Duyệt các phần tử trên cột thứ k (0 <=k < so_cot ) for (i = 0; i < so_dong ; i++) { // Xử lý phần tử a[i][k ]; } 21 1.2. Mảng hai chiều Duyệt các phần tử trên đường chéo của ma trận vuông // Duyệt các phần tử trên đường chéo chính . for (i = 0; i < n; i++) { // Xử lý phần tử a[i][i]; } // Duyệt các phần tử trên đường chéo phụ . for (i = 0; i < n; i++) { // Xử lý phần tử a[n-1-i][i]; } 22 1.3. Con trỏ Ta xét dòng khai báo sau : int *p; Dòng này cho bi ết bi ến p đư ợc khai báo là m ột con trỏ ki ểu int , đ ịa chỉ c ủa ki ểu dữ li ệu số nguyên . D ấu * không ph ải là m ột ph ần c ủa bi ến p, int * có nghĩa là con trỏ ki ểu int. Cú pháp khai báo như sau : * ; 23 Địa chỉ & ô nhớ Bộ nhớ Địa chỉ ô nhớ 0xA00h ĐỊA CHỈ Ô NHỚ DÙNG ĐỂ QUẢN LÝ Ô NHỚ TRONG BỘ NHỚ. 0xA01h 0xAFFh . . 24 POINTER int x; int *p; p 0xA04h x = 5; p = 0xA04h; p = &x; Dùng biến con trỏ (pointer) để lưu giữ các giá trị địa chỉ . x 5 p = &x; Khai báo : * ; Ví dụ : int * p; 25 POINTER *p = *p + 2; *p = x = x = 6 *p = 8 int x; int *p; p 0xA04h x = 5; p = &x; Nếu gán con trỏ p = &x thì : 6 5 6 *p x *p và biến x cùng sử dụng chung một ô nhớ 8 8 26 Ví dụ 1 int main() { int i; int j; int *p; p = &i; *p = 5; j = i; printf (“%d %d %d ”, i, j, *p); return 0; } i j p 5 5 5 int i; int j; int *p; p = &i; *p = 5; 5 5 j = i; printf (“%d %d %d ”, i, j, *p); return 0; 5 27 Ví dụ 2 int main() { int i; int *p; printf(“%d %d \n”, p, &i); p = &i; printf(“%d % d\n”,p,&i ); return 0; } i 0xA06h p 852 2566 2566 2566 int i; int *p; printf(“%d %d \n”, p, &i); printf(“%d % d\n”,p,&i ); p = &i; p = &i; return 0; 28 Ví dụ 3 void swap(int *a, int *b) { int tmp ; tmp = *a; *a = *b; *b = tmp ; } int main() { int a, b; a = 5; b = 10; swap(&a , &b); printf(“%d,%d”,a , b); return 0; } int a, b; 0xA06h 0xA08h a b a = 5; 5 5 b = 10; 10 10 swap(&a , &b); void swap(int *a, int *b) int tmp ; tmp tmp = *a; 5 5 *a = *b; *b = tmp ; 5 10 10 10 5 printf(“%d,%d”,a , b); 0xAA0h return 0; 5 29 Ví dụ 4 void tinh ( int * a, int * b) { (*a) ++; *a = *a + *b; (*b) ++; *b = *b + *a; } int main() { int * pa , * pb ; int x = 10; pa = &x; pb = &x; tinh(pa , &x); printf(“%d%d%d ”, x, *pa, * pb ); tinh(pa , pb ); x++; printf(“%d%d%d ”, x, *pa, * pb ); return 0; } int * pa , * pb ; pa pb int x = 10; x pa = &x; pb = &x; tinh(pa , &x); void tinh ( int * a, int * b) (*a) ++; 11 10 *a = *a + *b; 22 (*b) ++; 23 *b = *b + *a; 46 printf(“%d%d%d ”, x, *pa, * pb ); 46 46 46 tinh(pa , pb ); void tinh ( int * a, int * b) (*a) ++; 47 *a = *a + *b; 94 (*b) ++; 95 *b = *b + *a; 190 x++; 191 printf(“%d%d%d ”, x, *pa, * pb ); 191 191 191 return 0; 30 POINTER Pointer là một biến mà trỏ đến một ô nhớ . int x = 5; int *p; 5 Pointer lưu trữ địa chỉ bộ nhớ của một ô nhớ . p = &x; p 0xA04h p = 0xA04h *p = 5 p = &x; p = &x; 31 array & pointer Lưu ý: 5 4 3 6 8 12 16 24 10 9 a[0] a[1] a[2] a[6] a[3] a[7] a[4] a[8] a[5] a[9] a int a[10] ={5, 4, 3, 6, 8, 12, 16, 24, 10, 9}; int *pa; pa pa = a; pa + 8; pa = pa + 8; & a[i ] (a + i) pa + i & a[i ] pa[i ] *(pa + i) 32 Ví dụ 5 int main() { int a[10] ={5, 4, 3, 6, 8, 12, 16, 24, 10, 9}; int * pa ; int x; pa = &a[0]; x = *pa; printf(“%d ”, x); pa++; x = *pa; printf(“%d ”, x); pa = pa + 5; x = *pa; printf(“%d ”, x); return 0 ; } x pa int a[10] ={5, 4, 3, 6, 8, 12, 16, 24, 10, 9}; int * pa ; int x; pa = &a[0]; x = *pa; 5 printf(“%d ”, x); 5 pa++; x = *pa; 4 printf(“%d ”, x); 4 pa = pa + 5; x = *pa; 16 printf(“%d ”, x); 16 return 0 ; 5 4 3 6 8 12 16 24 10 9 a[0] a[1] a[2] a[6] a[3] a[7] a[4] a[8] a[5] a[9] a 33 array & pointer M ảng không ph ải là m ột bi ến ( ta không thể th ực hi ện a = pa và a++ ) 5 4 3 6 8 12 16 24 10 9 a[0] a[1] a[2] a[6] a[3] a[7] a[4] a[8] a[5] a[9] a pa pa = a pa = a pa++ pa++ Pointer là m ột bi ến (ta có thể th ực hi ện : pa = a và pa ++) 34 MỘT SỐ LƯU Ý Ph ải kh ởi t ạo đ ịa chỉ ô nhớ cho con trỏ (pointer) trư ớc khi sử d ụng . int * p; *p = *p + 2; p int * p; int x = 5; p = x; p Không đư ợc gán m ột giá trị cho con trỏ. 5 x 35 MỘT SỐ LƯU Ý Sử d ụng p++ t ức là con trỏ p tham chi ếu đ ến ô nhớ ti ếp theo . int * p; p = &x; p int * p, *q, *r; int x; r = p + q; p Không đư ợc th ực hi ện các phép toán (+, *, /) trên hai con trỏ. int x = 2; p ++; p = &x; q = &x; Lưu ý: Phép toán trừ hai con trỏ (p – q) v ẫn th ực hi ện đư ợc . K ết quả c ủa : p – q = ? ( Bài t ập ) 36 TỔNG KẾT Phân bi ệt gi ữa đ ịa chỉ và ô nhớ . Cách qu ản lý ô nhớ c ủa con trỏ. Toán tử đ ịa chỉ (&) và n ội dung (*). Phân bi ệt sự khác nhau gi ữa m ảng và con trỏ. Lưu ý m ột số l ỗi khi sử d ụng con trỏ. 37 BÀI TẬP int * Func () { int x; int * p; x = 2; p = &x; return p; } int main() { int * q; q = Func (); printf(“%d ”, *q); return 0; } Tìm l ỗi sai c ủa chương trình trên và s ửa l ại cho đúng . 38 BÀI TẬP int * p; int x; p = &x; Con trỏ p sẽ lưu giữ giá trị đ ịa chỉ c ủa bi ến x. Đ ịa chỉ c ủa bi ến con trỏ p là gì ? Làm cách nào để qu ản lý đư ợc đ ịa chỉ c ủa bi ến con trỏ p ? 39 Q&A 40
File đính kèm:
- bai_giang_c_can_ban_chuong_1_ky_thuat_xu_ly_mang_va_con_tro.ppt