Bài giảng Ngôn ngữ lập trình C - Mảng và con trỏ
Mục đích & Nội dung
Giới thiệu kiểu dữ liệu mảng
Biết cách sử dụng mảng (lưu, sắp xếp, tìm kiếm)
Khai báo một mảng, truy cập đến các thành
phần của mảng
Mảng nhiều chiều
Giới thiệu khái niệm con trỏ
Biết cách sử dụng con trỏ trong lập trình
Quan hệtương hỗ giữa con trỏ, mảng và xâu ký
tự
Mảng các con trỏ, mảng các xâu
Phép cộng con trỏ với số nguyên
Phép trừ hai con trỏ cùng kiểu
Gán hai con trỏ cùng kiểu
Ta có thể
Gán địa chỉ một biến nguyên cho một biến trỏ
nguyên
Gán hai con trỏ cùng kiểu với nhau
Ví dụ:
int n, *pi, *qi;
pi = &n;
qi = pi;
Cho phép pi và qi cùng trỏ đến biến n
*pi, *qi và n là một
Gán hai con trỏ cùng kiểu (tiếp)
Ví dụ:
int n, *pi;
float *pf;
Câu lệnh không hợp lệ
pf = &n;
pf = pi;
Phép chuyển đổi kiểu (thực hiện trước
phép gán) là hợp lệ
pf = (float *)&n;
pf = (float *)pi;
Cộng con trỏ với số nguyên
Cộng một con trỏ với một số nguyên cho ta một
con trỏ cùng kiểu
Ví dụ:
int m, n, p;
pi = &n;
Khi đó m, n, p tương ứng với 3 vùng nhớ 2 bytes liên
tiếp nhau
pi trỏ đến n
pi+1 cho ta địa chỉ của số nguyên m đi ngay trước n
pi-1 cho ta địa chỉ của số nguyên p đi ngay sau n
Ví dụ
/*pointer2.c*/
#include
#include
void main() {
int m=2, n=100, p=20;
int *pi = &n;
clrscr();
printf("m = %d n = %d p = %d\n",m,n,p);
printf("&n = %p &m = %p &p = %p\n",&n,&m,&p);
printf("pi = %p pi+1 = %p pi-1 = %p\n", pi, pi+1, pi-1);
printf("*pi = %d\n", *pi);
printf("*(pi+1) = %d\n", *(pi+1));
printf("*(pi-1) = %d\n", *(pi-1));
getch();
}
Kết quả
Phép trừ hai con trỏ cùng kiểu
Cho kết quả là một số nguyên biểu thị
“khoảng cách” giữa hai biến con trỏ
Ví dụ
int m, n, *pi, *qi;
pi = &n;
qi = &m;
qi – pi == 1
Không có phép cộng, nhân, chia giữa hai
con trỏ (không có ý nghĩa thực tế)
Con trỏ void*
Kiểu dữ liệu void
Là kiểu dữ liệu rỗng
Một biến kiểu void không tương ứng với bất
kỳ vùng nhớ nào
Con trỏ kiểu void*
Có thể nhận địa chỉ của bất kỳ vùng nhớ nào
Không thể thực hiện các phép tính số học
trên con trỏ void*
Con trỏ void* (tiếp)
Ví dụ
void *px, *py;
int x = 1;
float y = 0.1;
px = &x;
py = &y;
Con trỏ đa cấp
Bản thân biến trỏ cũng có địa chỉ
Có thể chứa địa chỉ của nó trong một đối
tượng khác
Những đối tượng có giá trị là địa chỉ của
một biến con trỏ là con trỏ đa cấp
Sử dụng thêm một số dấu ‘*’
Số lượng dấu ‘*’ xác định cấp của con trỏ
Con trỏ đa cấp (tiếp)
Ví dụ:
int *pi;
int **ppi = π
Liên hệ giữa con trỏ và mảng
Con trỏ và mảng một chiều
Con trỏ đa cấp và mảng nhiều chiều
Con trỏ và xâu kí tự
Con trỏ và mảng một chiều
Xét câu lệnh: int a[10];
Xin cấp phát một vùng nhớ 10 số nguyên
a[0], a[1], …,a[9] có địa chỉ xác định bởi a
a là địa chỉ của biến nguyên a[0]
Nếu pi là một con trỏ nguyên thì pi = a là hợp
lệ
Sau câu lệnh: pi = a; có thể
Sử dụng pi như một tên mảng
Thực hiện các phép toán số học trên con trỏ a
Con trỏ và mảng một chiều (tiếp)
pi[0], …, pi[9] tương ứng là a[0], …, a[9]
a, a+1, …,a+9 tương ứng là địa chỉ của
a[0], a[1], …, a[9]
Có mối liên hệ mật thiết giữa việc đánh chỉ
số trên mảng và các tính toán trên con trỏ
Khác
Tên mảng là hằng số
Biến trỏ là biến
Không thể sử dụng câu lệnh:
int b[10];
b = a;
Ví dụ
Nhập một dãy số nguyên vào bộ nhớ động
Xét xem trong dãy có ít nhất 2 số nguyên tố
bằng nhau hay không?
Tìm số nguyên tố max của dãy nếu có
Chương trình nguồn trong tệp array1.c
#include
#include
#include
int *init(int n){
int *p, *y;
y = (float *)calloc(n, sizeof(int));
for (p=y; p<y+n; p++)
scanf("%d",p);
return y;
}
void show(int *y, int n){
int *p;
for (p=y; p<y+n; p++)
printf("%5d",*p);
}
int ktnt(int k){
int i;
for (i=2; i<k; i++)
if (k%i==0) return 0;
return k>1;
}
void caua(int *y, int n){
int *p, *q;
for (p=y; p<y+n-1; p++)
for (q=p+1; q<y+n; q++)
if (ktnt(*p)&& *p==*q){
printf("Co 2 so nguyen to bang nhau\n");
return;
}
printf("Khong co 2 so nguyen to bang nhau\n");
}
void caub(int *y, int n){
int *p, max;
max = 0;
for (p=y; p<y+n; p++)
if(ktnt(*p)&&(max<*p))
max = *p;
if (!max)
printf("Khong co so nguyen to nao\n");
else
printf("So NT lon nhat la %d\n",max);
}
int main(){
int *x, n;
printf("Nhap n="); scanf("%d",&n);
x = init(n);
caua(x,n);
caub(x,n);
getch();
return 0;
}
Con trỏ đa cấp và mảng nhiều chiều
Mảng hai chiều là mảng một chiều của các
mảng một chiều
Con trỏ hai cấp là con trỏ chỉ đến con trỏ
một cấp
Con trỏ hai cấp và mảng hai chiều có nhiều
điểm tương đồng
Có thể suy rộng cho các mảng và con trỏ
nhiều mức
Con trỏ đa cấp và mảng nhiều chiều
(tiếp)
Ví dụ
int **ppi;
int a2[10][10];
Ta có thể thực hiện phép gán:
ppi=a2;
Có thể sử dụng ppi như tên một biến mảng
Ví dụ
Nhập dữ liệu của một ma trận vào bộ nhớ
động, in ma trận vừa nhập
Ví dụ - nhập in ma trận
/*array21.c*/
#include
#include
float *init(int n, int m){
float *p, *x;
x = (float *)calloc(n*m,sizeof(float));
for (p=x; p<x+n*m; p++)
scanf("%f",p);
return x;
}
void show(float *x, int n, int m){
int i, j;
for (i=0; i<n; i++){
for (j=0; j<m; j++)
printf("%5.2f",x[i*m+j]);
puts("");
}
}
void main(){
float *a;
int n, m;
printf("Nhap n, m=");
scanf("%d%d",&n,&m);
a = init(n,m);
show(a,n,m);
getch();
}
Con trỏ và xâu kí tự
Xây dựng lại các hàm
so sánh
sao chép xâu
kiểm tra tính đối xứng của xâu
Nhập một xâu kí tự
Các ô trống kề nhau chỉ giữ lại một.
Ví dụ - so sánh hai xâu kí tự
/*strcmp.c*/
#include
#include
void init(char *w);
void show(char *w);
int sosanh(char *w,char *s);
void main(){
char *w, *s;
clrscr();
init(w);
init(s);
show(w);
show(s);
if (sosanh(w,s))
printf("Hai xau khac nhau\n");
else printf("Hai xau giong nhau\n");
getch();
}
void init(char *w){
printf("Nhap xau:");
gets(w);
}
void show(char *w){
printf("Xau = %s\n",w);
}
int sosanh(char *w, char *s){
char *p, *q;
p = w;
for(q = s; *p||*q; p++, q++)
if (*p != *q) return (*p - *q);
return (*p - *q);
}
Ví dụ - sao chép xâu
/*strcpy.c*/
#include
#include
void init(char *w);
void show(char *w);
void saochep(char *w,char *s);
void main(){
char *w, *s;
clrscr();
init(w);
/* show(w);*/
saochep(s,w);
show(s);
getch();
}
void init(char *w){
printf("Nhap xau:");
gets(w);
}
void show(char *w){
printf("Xau = %s\n",w);
}
void saochep(char *w, char *s)
{
char *p, *q;
p = w;
for(q = s; *q; q++, p++)
*p = *q;
*p = 0;
}
Ví dụ - Kiểm tra xâu đối xứng
/*strsym.c*/
#include
#include
void init(char *w);
void show(char *w);
int ktdx(char *w);
void main(){
char *w;
clrscr();
init(w);
if (ktdx(w))
printf("Xau doi xung\n");
else printf("Xau khong doi xung\n");
getch();
}
void show(char *w){
printf("Xau = %s\n",w);
}
int ktdx(char *w)
{
char *q;
q = w + strlen(w) - 1;
while (w <q)
{
if (*w != *q) return 0;
w ++;
q--;
}
return 1;
}
Ví dụ - các ô trống kề nhau chỉ giữ
lại một
/*xoakt.c*/
#include
#include
#include
#define tr ' '
/*void init(char *w){
printf("Nhap xau =");
gets(w);
} */
char *init(){
char *w;
printf("Nhap xau");
gets(w);
return w;
}
void show(char *w){
printf("%s\n",w);
}
void del(char *p){
for(; *p; p++)
*p = *(p+1);
}
void del_space(char *w){
char *p;
for (p=w; *p; )
if ((*p==tr)&&*(p+1)==tr)
del(p);
else p++;
}
int main(){
char *w;
// init(w);
w = init();
show(w);
del_space(w);
show(w);
getch();
return 0;
}
Cấp phát động
Cho phép chương trình sử dụng vừa đúng
khối lượng bộ nhớ chương trình cần
Khi không cần dùng có thể giải phóng cho các
công việc khác
Cùng một vùng nhớ có thể được sử dụng cho
các mục đích khác nhau trong thời gian thực
hiện chương trình
Hàm cấp phát bộ nhớ
Hàm malloc()
Hàm calloc()
Hàm free()
Hàm malloc()
Tệp tiêu đề liên quan:
alloc.h
stdlib.h
Cú pháp: malloc(size);
Xin cấp phát một vùng nhớ có kích thước size byte từ
vùng nhớ heap
Giá trị trả về
Thành công: trả về một con trỏ tới khối nhớ mới được
cung cấp
Lỗi: trả về giá trị NULL
Nếu size = 0, malloc() trả về con trỏ NULL
Ví dụ
int *pi, *qi;
char *pc;
double *pd;
double **ppd;
int i;
/*cấp phát vùng nhớ một số nguyên*/
qi = (int *)malloc(sizeof(int));
/*cấp phát một mảng các số nguyên – mảng động*/
pi = (int *)malloc(12*sizeof(int));
/*cấp phát xâu ký tự*/
pc = (char *)malloc(20);
pd = (double *)malloc(10*sizeof(double));
/*cấp phát ma trận*/
ppd = (double **)malloc(10*sizeof(double *));
for (i=0; i<10; i++)
ppd[i] = (double *)malloc(10*sizeof(double));
Hàm calloc()
Tệp tiêu đề liên quan
alloc.h
stdlib.h
Cú pháp: calloc(nitems, size);
Xin cấp phát một vùng nhớ kích thước nitems*size
byte và xóa trắng vùng nhớ này
Muốn xin cấp phát vùng nhớ >64KB, phải sử dụng
hàm faralloc (cấp phát xa)
Giá trị trả về
Thành công: trả về con trỏ trỏ tới vùng nhớ mới được
cấp
Lỗi: hàm trả về NULL
Ví dụ
int *pi;
double *pd;
double **ppd;
int i;
/*cấp phát một mảng các số nguyên – mảng động*/
pi = (int *)calloc(12,sizeof(int));
pd = (double *)calloc(10, sizeof(double));
/*cấp phát ma trận*/
ppd = (double **)calloc(10, sizeof(double*));
for (i=0; i<10; i++)
ppd[i] = (double *)calloc(10, sizeof(double));
Hàm free()
Tệp tiêu đề liên quan:
alloc.h
stdlib.h
Cú pháp: free(address);
Giải phóng một khối nhớ đã được cấp phát
trước đó bằng hàm calloc() hoặc malloc()
hoặc realloc()
Địa chỉ vùng nhớ được giải phóng được
truyền làm tham số cho hàm free()
Ví dụ
free(pi);
free(qi);
free(pc);
free(pd);
for (i=1; i<10; i++)
free(ppd[i]);
free(ppd);
Ví dụ
/*38.c*/
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#include "alloc.h"
void main()
{
double **p;
int m, n;
int i, j;
double temp;
clrscr();
printf("Kich thuoc ma tran");
scanf("%d%d",&m,&n);
p = (double *)calloc(m,sizeof(double *));
for (i=0; i<m; i++)
p[i] = (double *)calloc(n, sizeof(double));
Ví dụ
for (i=0; i<m; i++)
for (j=0; j<n; j++)
{
printf("p[%d,%d]=",i,j);
scanf("%lf", &temp);
p[i][j] = temp;
}
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%6.2f", p[i][j]);
printf("\n");
}
for (i=0; i<m; i++)
free(p[i]);
free(p);
getch();
}
Kết quả
File đính kèm:
Bài giảng Ngôn ngữ lập trình C - Mảng và con trỏ.pdf

