You are on page 1of 34

CHƯƠNG 6.

MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ


6.2. Định nghĩa con trỏ, cấp phát và hủy vùng nhớ.
Mục tiêu bài học
 Tìm hiểu về con trỏ và khi nào thì sử dụng con trỏ
 Cách sử dụng biến con trỏ và các toán tử con trỏ
 Phép toán trên con trỏ
 Gán giá trị cho con trỏ
 So sánh con trỏ
 Con trỏ và mảng
 Tìm hiểu cách cấp phát bộ nhớ động
 Con trỏ hàm 1
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2. Định nghĩa con trỏ, cấp phát và hủy vùng nhớ.
6.2.1 Định nghĩa con trỏ
- Trong các ngôn ngữ lập trình, biến thực chất là các ô nhớ, có thể được truy cập bằng
cách sử dụng tên (định danh) của chúng. Nhờ đó chúng ta không phải quan tâm đến vị
trí vật lý (địa chỉ) của biến trong bộ nhớ.
- Tuy nhiên, chúng ta có thể truy cập tới biến thông qua địa chỉ của biến.

 Con trỏ là một biến chứa địa chỉ của biến khác.
 Con trỏ được dùng để truy cập biến thông qua địa chỉ biến.

 Khai báo biến con trỏ

Kiểu dữ liệu * tên_con_trỏ; 2


CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.1 Định nghĩa con trỏ

Kiểudữ liệu * tên_con_trỏ;

Ví dụ 1:
x
int x = 6, y = 7;
int *px, *py;
px = &x; y
py = &y;

3
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.1 Định nghĩa con trỏ.

int x = 6, y = 7;
int *px, *py; 16 x
px = &x;
py = &y;
*px += 10;
*py += 10; y
17

Giá trị nào thay đổi?

 Chú ý:
•  là toán tử reference và có thể đọc là “ địa chỉ của”
• * là toán tử dereference có thể được đọc là “ giá trị được trỏ bởi “ 4
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.1 Định nghĩa con trỏ
#include <stdio.h>
void main(void)
{
int x = 6, y = 7;
int *px, *py;
printf("x = %d, y = %d\n", x, y);
px = &x; Gán cho ô nhớ được trỏ bởi
px giá trị bằng giá trị của ô
py = &y;
nhớ đó +10
printf("gia tri cua o nho duoc tro boi px= %d, py = %d\n", *px, *py);
*px += 10;
*py += 10;
printf("x = %d, y = %d\n", x, y);
printf("gia tri cua o nho duoc tro boi px= %d, py = %d\n", *px, *py); Gán cho ô nhớ được trỏ bởi
py giá trị bằng giá trị của ô
getch(); nhớ đó +10
} 5
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2. Định nghĩa con trỏ, cấp phát và hủy vùng nhớ.

6.2.2 Cấp phát và hủy vùng nhớ động

 Như đã biết, mảng là một tập hợp của các phần tử nằm liên tiếp nhau trên bộ nhớ và
có cùng kiểu dữ liệu.
 Khi khai báo mảng, bạn phải chỉ định rõ kích thước tối đa (số lượng phần tử tối đa).
Và sau khi khai báo, bạn không thể thay đổi kích thước của mảng
 Cấp phát tĩnh (bộ nhớ được cấp phát khi bắt đầu thực hiện chương trình)

Một số hạn chế có thể gặp phải khi sử dụng các biến tĩnh:
- Cấp phát ô nhớ dư, gây ra lãng phí ô nhớ;
- Cấp phát ô nhớ thiếu, chương trình thực thi bị lỗi. 6
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2. Cấp phát và hủy vùng nhớ động
 Nếu khi thiết kế chương trình, người lập trình chưa biết số phần tử của mảng ( mà
người sử dụng cần)
 Khi đó sử dụng cấp phát bộ nhớ động.
- Cấp phát bộ nhớ động: vùng bộ nhớ được cấp phát trong quá trình thực hiện chương
trình chứ không cấp phát lúc bắt đầu chương trình.
- Sau khi sử dụng xong có thể giải phóng để tiết kiệm chỗ trong bộ nhớ.

7
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.2 Cấp phát và hủy vùng nhớ động

 Cấp phát bộ nhớ động trong C

 Để cấp phát vùng nhớ động cho biến con trỏ trong ngôn ngữ C, sử dụng hàm:
malloc() hoặc hàm calloc().
 Để giải phóng bộ nhớ đã cấp phát khi không cần sử dụng, sử dụng hàm free().
 Để thay đổi (phân bổ lại) kích thước bộ nhớ đã cấp phát sử dụng realloc()
 Bốn hàm malloc, calloc, realloc và free nằm trong thư viện stdlib.h hoặc alloc.h

8
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
 Cấp phát bộ nhớ động trong C
Hàm malloc() thực hiện cấp phát bộ nhớ bằng cách chỉ định số byte cần cấp phát. Hàm
này trả về con trỏ kiểu void cho phép chúng ta có thể ép kiểu về bất cứ kiểu dữ liệu nào.
Cú pháp của hàm malloc(): ptr = (kiểu dữ liệu*) malloc(số ô nhớ cần cấp phát);
Cú pháp của hàm calloc():
ptr = (kiểu dữ liệu*) calloc(so-phan-tu, kich-co-phan-tu);
Số phần tử cố định
Ví dụ 1: int n, *ptr;
ptr = (int*) malloc(100 * sizeof(int));
Ví dụ 2: int n, *ptr;
printf("Nhap so luong phan tu: ");
scanf("%d", &n); Số phần tử động ( do người dùng
ptr = (int *)malloc(n * sizeof(int)); nhập) 9
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.2 Cấp phát và hủy vùng nhớ động
 Giải phóng bộ nhớ động trong C
 Việc cấp phát bộ nhớ động trong C sử dụng malloc() hay calloc() thì chúng cũng
đều không thể tự giải phóng bộ nhớ.
 Sau nhiều lần chạy chương trình, bộ nhớ sẽ tràn.
 Bộ nhớ động chỉ cần thiết ở thời điểm cụ thể trong chương trình, khi nó không còn
cần thiết nữa thì nên được giải phóng để bộ nhớ sẵn sàng cho các yêu cầu cấp phát
bộ nhớ động khác  Tránh được tràn bộ nhớ.
 Để giải phóng bộ nhớ động dùng hàm free()
Cú pháp của hàm free():

free(tên con trỏ); 10


#include <stdio.h>
Ví dụ 3: Cấp #include <stdlib.h>
phát và giải int main()
phóng bộ nhớ {
động int n, i, *ptr, sum = 0;
printf("Nhap so luong phan tu: ");
scanf("%d", &n);
Cấp phát bộ
ptr = (int *)malloc(n * sizeof(int));
nhớ động
if (ptr == NULL)
{ printf("Co loi! khong the cap phat bo nho.");
exit(0);
}
printf("Nhap cac gia tri: ");
for (i = 0; i < n; ++i)
{ scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Tong = %d", sum); Giải phóng bộ
free(ptr);
nhớ động11
return 0;}
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2. Định nghĩa con trỏ, cấp phát và hủy vùng nhớ.
 Cấp phát lại vùng nhớ cho biến con trỏ
Cú pháp của hàm realloc(): ptr =(kiểu dữ liệu *) realloc(con_trỏ, kích_cỡ);
Ý nghĩa:
- Cấp phát lại 1 vùng nhớ cho con trỏ, vùng nhớ này có kích thước mới là kích_cỡ;
- Kết quả trả về của hàm là địa chỉ đầu tiên của vùng nhớ mới. Địa chỉ này có thể khác với địa
chỉ được chỉ ra khi cấp phát ban đầu.
Ví dụ: Trong ví dụ trên ta có thể cấp phát lại vùng nhớ do con trỏ pa quản lý như sau:
int a, *pa;
pa= (int*)malloc(sizeof(int)); /*Cấp phát vùng nhớ có kích thước 2 byte*/
pa = (int*)realloc(pa, 6); /* Cấp phát lại vùng nhớ có kích thước 6 byte*/ 12
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2. Định nghĩa con trỏ, cấp phát và hủy vùng nhớ.
6.2.3 Một số phép toán trên con trỏ
a. Phép gán con trỏ: Hai con trỏ cùng kiểu có thể gán cho nhau.
Ví dụ

int a, *p, *q ; float *f; Ta cũng có thể ép kiểu con trỏ theo cú pháp:
a = 5 ; p = &a ; q = p ; /* đúng */ (<Kiểu kết quả>*)<Tên con trỏ>
f = p ; /* sai do khác kiểu */ Chẳng hạn, ví dụ trên được viết lại:
int a, *p, *q ; float *f;
a = 5 ; p = &a ; q = p ; /* đúng */
f = (float*)p; /* Đúng nhờ ép kiểu*/

13
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.3 Một số phép toán trên con trỏ
b. Phép so sánh con trỏ.
 Hai con trỏ có thể được so sánh trong một biểu thức quan hệ nếu chúng trỏ đến các biến
có cùng kiểu dữ liệu
Ví dụ: p_a < p_b Trả về giá trị true nếu a được lưu trữ ở vị trí trước b
p_a > p_b Trả về giá trị true nếu a được lưu trữ ở vị trí sau b
int a, b, *p_a, *p_b ; p_a <= p_b Trả về giá trị true nếu a được lưu trữ ở vị trí trước b hoặc
p_a và p_b trỏ đến cùng một vị trí
p_a=&a;
p_a => p_b Trả về giá trị true nếu a được lưu trữ ở vị trí sau b hoặc
p_b=&b; p_a và p_b trỏ đến cùng một vị trí
p_a == p_b Trả về giá trị true nếu cả hai con trỏ p_a và p_b trỏ đến
cùng một phần tử dữ liệu.
p_a! = p_b Trả về giá trị true nếu cả hai con trỏ p_a và p_b trỏ đến các
phần tử dữ liệu khác nhau nhưng có cùng kiểu dữ liệu.
p_a == NULL Trả về giá trị true nếu p_a được gán giá trị NULL(0)
14
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.2.3 Một số phép toán trên con trỏ
c. Cộng, trừ con trỏ với một số nguyên
 Chỉ phép cộng và trừ là được thực hiện với con trỏ, các phép tính khác không có ý
nghĩa đối với con trỏ
 Ta có thể cộng (+), trừ (-) 1 con trỏ với 1 số nguyên N nào đó; kết quả trả về là 1 con
trỏ. Con trỏ này chỉ đến vùng nhớ cách vùng nhớ của con trỏ hiện tại N phần tử.
Ví dụ
int x = 6, y = 7;
int *px, *py; x int x = 6, y = 7;
px = &x; int *px, *py;
py = &y; 1217
px = &x;
px += 7; y py = &y;
1213
py += 3; *px += 10;
*py += 10;
Giá trị nào thay đổi? 15
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng. numbers [0]
 Giữa mảng và con trỏ có một sự liên hệ rất chặt chẽ.
[1]
• Tên của mảng tương đương với địa chỉ phần tử đầu tiên của
nó, tương đương với địa chỉ của phần tử đầu tiên mà con trỏ [2]

trỏ tới.
[3]
Ví dụ: int numbers [5];
int* p; [4]

p = numbers;
• Những phần tử của mảng có thể được xác định bằng chỉ số
trong mảng, hoặc được xác lập qua biến con trỏ.
Ví dụ: numbers[2] = 2;  *(p+2)=2; 16
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng. a [0] 10 2000

Ví dụ 1:
[1] 20 2002
#include <stdio.h> for(i=0; i<5; i++)
int main () printf("Phan tu thu %d cua mang la:
{ %d \n ",i+1, a[i]); [2] 30 2004
int a[5], i; return 0;
int* p; }
[3] 40 2006
p = a;
*p = 10;
p++; Chú ý: Cách sử dụng con trỏ để truy cập các [4] 50 2008
*p = 20; phần tử của mảng.
p = &a[2]; - Con trỏ chứa địa chỉ trực tiếp của các
*p = 30; p 2002
2004
2006
2000 8000
phần tử mảng
p = a + 3; - Truy cập đến phần tử được trỏ bởi (Con
*p = 40;
trỏ+ số nguyên)
p = a;
*(p+4) = 50; 17
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng .
Ví dụ 2: Về truy cập phần tử theo kiểu mảng và con trỏ.

#include <stdio.h> printf("Truy cap theo kieu mang: ");


#include <stdlib.h> for(i=0;i<10;i++)
int main() printf("%d ",a[i]);
{ printf("\nTruy cap theo kieu con tro: ");
int *a; for(i=0;i<10;i++)
int i; printf("%d ",*(a+i));
a=(int*)malloc(sizeof(int)*10); getch();
for(i=0;i<10;i++) return 0;
a[i] = 2*i; }

18
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng . a [0] [0] 2000 (p)

 Con trỏ và mảng nhiều chiều


[0][1] 2002 (p+1)
Giả sử ta có mảng 2 chiều và biến con trỏ như sau:

int a[n][m]; [i][0] (p+i*m)
int *p;
[i][1] (p+i*m+1)
Thực hiện phép gán

p=a; [n-1][m-1] (p+(n-1)*m+(m+1))
khi đó phần tử a[0][0] được quản lý bởi p+0;
a[0][1] được quản lý bởi p+1; a[i][1] được quản lý bởi p+(i)*m +1;
a[0][2] được quản lý bởi p+2; ...
... a[n-1][m-1] được quản lý bởi p+(n-1)*m + (m-1);
19
a[i][0] được quản lý bởi p+(i)*m;(0<i<n-1)
 Con trỏ và mảng nhiều chiều
Ví dụ 3: Sự tương đương giữa mảng 2 chiều và con trỏ
#include <stdio.h> printf("\n-----------------------------");
#include <stdlib.h> printf("\nNoi dung cua mang_int sau khi tang 1=");
int main() for (i=0;i<4;i++)
{ {
int i,j; printf("\n");
int mang_int[4][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14, for (j=0;j<5;j++)
15,16,17,18,19,20}; printf("%d\t",mang_int[i][j]);
int *p; }
p=(int*)mang_int; printf("\nNoi dung cua p sau khi tang 1=\n");
printf("\nNoi dung cua mang_int ban dau="); for (i=0;i<20;i++)
for (i=0;i<4;i++) printf("%d ",p[i]);
{ getch();
printf("\n"); return 0;
for (j=0;j<5;j++) }
printf("%d\t",mang_int[i][j]);
}

20
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng .
 Con trỏ là tham số truyền cho hàm

Ví dụ 1: So sánh hai chương #include<stdio.h> #include<stdio.h>


trình sau: void doi_cho(int x, int y) void doi_cho(int *x, int *y)
{ {
int t ; int t;
Truyền tham số theo tham trị t=x; t = *x ;
x=y; *x = *y ;
y=t; *y = t ;
} }
Truyền tham số theo tham trỏ int main() int main()
{ {
int x = 2; int x = 2;
int y = 5; int y = 5;
doi_cho(x, y) ; doi_cho(&x, &y) ;
printf("%d, %d",x, y); printf("%d, %d",x, y);
getch(); getch();
return 0; return 0;
21
} }
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng . #include<stdio.h>
 Truyền tham trị cho hàm void doi_cho(int x, int y)
{ int t ;
 Khi có lời gọi hàm doi_cho, chương trình sẽ tạo 2 biến mới t=x;
(các ô nhớ trong bộ nhớ) có tên x và y. Gán nội dung các ô x=y;
nhớ này bằng các giá trị trong lời gọi y=t;
}
int main()
x 2 2000 {
int x = 2; int y = 5;
doi_cho(x, y) ;
y 5 2002 printf("%d, %d",x, y);
⋮ Khai báo biến getch();
return 0;
địa phương sẽ }
x 52 4000 “che” mất biến
cùng tên khác  chương trình sau khi thực hiện xong hàm doi_cho
là xoá các biến mới. Do vậy nội dung của các biến
có phạm vi mới thực sự là có thay đổi, nhưng không ảnh hưởng
y 25 4002
rộng hơn. gì đến các biến x, y cũ. 22
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng .
 Truyền tham trỏ cho hàm
 Như vậy hàm doi_cho cần được viết lại sao cho việc thay đối giá trị không #include<stdio.h>
thực hiện trên các biến tạm mà phải thực sự thực hiện trên các biến ngoài. void doi_cho(int *x, int *y)
 Muốn vậy thay vì truyền giá trị của các biến ngoài cho đối, ta truyền địa {
chỉ của nó cho đối, và các thay đổi sẽ thực hiện trên nội dung của các int t;
t = *x ;
địa chỉ này.
*x = *y ;
x 25 2000 *y = t ;
}
int main()
y 25 2002 {
int x = 2;
⋮ int y = 5;
doi_cho(&x, &y) ;
printf("%d, %d",x, y);
x 2000 4000
 Bằng cách truyền tham trỏ, getch();
chương trình đổi được giá trị return 0;
}
y 2002 4002 của biến ngoài hàm. 23
 Con trỏ là tham số truyền cho hàm Cho kết quả không đúng
Mảng kq được khai báo và
Ví dụ 2: Xét đoạn chương trình sau khởi tạo trong day1(), đây là
một mảng cục bộ hay là
#include <stdio.h> int main() mảng "tạm thời“ , chỉ tồn tại
#include <stdlib.h> { trong quá trình hàm hoạt
động  hàm thực hiện xong,
int* day1() int *a, i;
toàn bộ kq sẽ được xoá khỏi
{ a = day1(); bộ nhớ và vì vậy con trỏ kết
int kq[3] = { 7, 5, 3 }; printf(“Mang thu nhat:"); quả hàm đã trỏ đến vùng nhớ
return kq; for (i=0; i<3; i++) không còn các giá trị như
} printf("%d\n",*(a+i)); kq đã có.
int* day2() a = day2(); Cho kết quả đúng
{ printf("Mang thu hai:"); Trong hàm day2(), mảng kq
int *kq; for (i=0; i<3; i++) cũng được tạo ra nhưng
kq=(int*)malloc(3*sizeof(int)); printf("%d\n",*(a+i)); bằng cách xin cấp phát bộ
*kq = *(kq+1) = *(kq+2) = 0 ; getch(); nhớ động. Vùng nhớ này sẽ
vẫn còn tồn tại sau khi hàm
return kq ; return 0;
kết thúc (nó chỉ bị xoá đi khi
} } 24
sử dụng toán tử delete).
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.3. Con trỏ và mảng .
 Con trỏ là tham số truyền cho hàm
Sử dụng con trỏ làm tham số truyền cho hàm, ta có thể:
Thay đổi được biến ngoài hàm ( Ví dụ 1)
Giá trị trả về của hàm có thể là một mảng ( Ví dụ 2)

Bài tập: Viết chương trình thực hiện:


+ Nhập 2 véc-tơ có độ dài n từ bàn phím
+ Cộng 2 vectơ vừa nhập và trả về véc-tơ tổng
+ Hiển thị véc-tơ ra màn hình
Chương trình được viết dưới dạng các hàm.
25
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.4. Con trỏ hàm .

 Một hàm cũng giống như một biến: có tên gọi , có địa chỉ lưu trong bộ nhớ và
có thể truy nhập đến hàm thông qua tên gọi hoặc địa chỉ của nó
 Con trỏ mà trỏ đến điểm xâm nhập vào hàm. Ta gọi đây là con trỏ hàm.
 Việc sử dụng con trỏ cho phép các hàm cũng được truyền như là tham số
cho các hàm khác.

26
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.4. Con trỏ hàm . main { 2000

2002


}
line { 2020

2022
 Khi biên dịch hàm, trình biên dịch chuyển chương trình
nguồn sang dạng mã máy và thiết lập một điểm xâm nhập ⋮

vào hàm (chính là địa chỉ mã máy đầu tiên của hàm). }

 Gọi hàm bằng tên hàm  Gọi hàm trực tiếp
 Gọi hàm thông qua địa chỉ của hàm (sử dụng con trỏ hàm)
 Gọi hàm gián tiếp
27
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.4. Con trỏ hàm .
6.4.1 Khai báo .
 Để truy nhập (gọi) hàm thông qua địa chỉ chúng ta phải khai báo một con trỏ chứa
địa chỉ này và sau đó gọi hàm bằng cách gọi tên con trỏ.
Cú pháp
<kiểu dữ liệu trả về> (*<tên con trỏ hàm>)(<danh sách các tham số> );
Ví dụ:
float (*f)(int); // khai báo con trỏ hàm có tên là f trỏ đến hàm, có một tham số kiểu int và giá
// trị trả về kiểu float.
void (*f)(float, int); // con trỏ hàm, trỏ đến hàm với cặp tham số là (float, int) và không có
// giá trị trả về.
char* (*m[10])(int, char) // khai báo một mảng 10 con trỏ hàm, trỏ đến các hàm có cặp tham
// số truyền (int, char), giá trị trả về là con trỏ kiểu char
28
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.4. Con trỏ hàm .
6.4.2 Sử dụng con trỏ hàm .
Ví dụ:
 Con trỏ hàm thay tên hàm
 Để sử dụng con trỏ hàm ta phải gán nó với #include <stdio.h>
tên hàm cụ thể. Sau đó bất kỳ nơi nào được float bphuong(float x)
{
phép xuất hiện tên hàm thì ta đều có thể thay return x*x;
nó bằng tên con trỏ. }
int main()
Chú ý: phân biệt giữa 2 khai báo {
float (*f)(float);
float (*f)(int); // Khai báo con trỏ hàm f = bphuong;
printf("Binh phuong cua 3.5 =%f",f(3.5));
float *f(int); //Khai báo hàm f có giá trị trả về getch();
// là con trỏ float. return 0;
}
29
CHƯƠNG 6. MẢNG, CON TRỎ VÀ CHUỖI KÝ TỰ
6.4. Con trỏ hàm .
6.4.2 Sử dụng con trỏ hàm .
Ví dụ:
 Con trỏ hàm thay tên hàm
 Để sử dụng con trỏ hàm ta phải gán nó với #include <stdio.h>
tên hàm cụ thể. Sau đó bất kỳ nơi nào được float bphuong(float x)
{
phép xuất hiện tên hàm thì ta đều có thể thay return x*x;
nó bằng tên con trỏ. }
int main()
Chú ý: phân biệt giữa 2 khai báo {
float (*f)(float);
float (*f)(int); // Khai báo con trỏ hàm f = bphuong;
printf("Binh phuong cua 3.5 =%f",f(3.5));
float *f(int); //Khai báo hàm f có giá trị trả về getch();
// là con trỏ float. return 0;
}
30
Bài Tập Phần Con Trỏ
Bài tập 1
Viết chương trình nhập vào một mảng số nguyên ( số phần tử của mảng do người dùng nhập),
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 .
 Sắp xếp mảng theo giá trị tăng dần
 Đếm các số chính phương có trong mảng
 Đếm số nguyên tố có trong mảng
Yêu cầu: Chương trình sử dụng con trỏ để cấp phát bộ nhớ động và truy cập các phần tử của
mảng. 31
Bài Tập Phần Con Trỏ

Bài tập 2
Viết chương trình nhập vào một dãy các số (số lượng phần tử trong dãy do
người dung nhập) 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.
Yêu cầu: Chương trình sử dụng con trỏ để cấp phát bộ nhớ động và truy cập các
phần tử của mảng.

32
Bài Tập Phần Con Trỏ

Bài tập 3
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 (m, n do người dùng nhập). 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ử ?
Yêu cầu: Chương trình sử dụng con trỏ để cấp phát bộ nhớ động và truy cập các
phần tử của mảng.

33
Bài Tập Phần Con Trỏ

Bài tập 4
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 (m, n do người dùng nhập). 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ử ?
Yêu cầu: Chương trình sử dụng con trỏ để cấp phát bộ nhớ động và truy cập các
phần tử của mảng.

34

You might also like