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

pdf77 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 2419 | Lượt tải: 2download
Tóm tắt nội dung Bài giảng Ngôn ngữ lập trình C - Mảng và con trỏ, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
 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:

  • pdfBài giảng Ngôn ngữ lập trình C - Mảng và con trỏ.pdf