Con trỏ và mảng 1 chiều
Địa chỉ của một phần tử mảng có thể được biểu diễn theo hai cách:
- Sử dụng ký hiệu & trước một phần tử mảng.
- Sử dụng một biểu thức trong đó chỉ số của phần tử được cộng vào tên của mảng.
Giữa mảng và con trỏ có một sự liên hệ rất chặt chẽ. Những phần tử của mảng có thể được xác định bằng chỉ số trong mảng, bên cạnh đó chúng cũng có thể được xác lập qua biến con trỏ.
Truy cập các phần tử mảng theo dạng con trỏ Ta có các quy tắc sau:
- &<Tên mảng>[0] tương đương với <Tên mảng>
- &<Tên mảng> [<Vị trí>] tương đương với <Tên mảng> + <Vị trí>
- <Tên mảng>[<Vị trí>] tương đương với *(<Tên mảng> + <Vị trí>)
Ví dụ:
Lệnh: scanf(“%f”, &a[i]);
sẽ tương đương với các lệnh sau:
scanf(“%f”, a+i);
scanf(“%f”, &pa[i]);
scanf(“%f”, pa+i);
Ví dụ
#include <stdio.h> #include <conio.h> #include <stdlib.h> void main() { static int ary[10]={1,2,3,4,5,6,7,8,9,10}; for (int i= 0; i<10; i++) { printf("\n i=%d, ary[i]=%d, (ary+i)=%d",i, ary[i], *(ary + i)); printf("&ary[i]=%X, ary+i=%X", &ary[i], ary+i); /*%X lay he so 16*/ } getch(); }
Kết quả (lưu ý có thể khác nhau đối với từng máy. Xem thêm ở đây)
Ví dụ 1: Cho 1 mảng 1 chiều các số nguyên a có 5 phần tử, truy cập các phần tử theo kiểu mảng và theo kiểu con trỏ.
#include <stdio.h> #include <conio.h> /* Nhap mang binh thuong */ void NhapMang(int a[], int N) { int i; for(i=0;i<N;i++) { printf("Phan tu thu %d: ",i); scanf("%d",&a[i]); } } /* Nhap mang theo dang con tro */ void NhapContro(int a[], int N) { int i; for(i=0;i<N;i++) { printf("Phan tu thu %d: ",i); scanf("%d",a+i); } } void main() { int a[20],N,i; printf("So phan tu N= "); scanf("%d",&N); NhapMang(a,N); // NhapContro(a,N); printf("Truy cap theo kieu mang: "); for(i=0;i<N;i++) printf("%d ",a[i]); printf("\nTruy cap theo kieu con tro: "); for(i=0;i<N;i++) printf("%d ",*(a+i)); getch(); }
Truy xuất từng phần tử đang được quản lý bởi con trỏ theo dạng mảng
- <Tên biến>[<Vị trí>] tương đương với *(<Tên biến> + <Vị trí>)
- &<Tên biến>[<Vị trí>] tương đương với (<Tên biến> + <Vị trí>)
Trong đó <Tên biến> là biến con trỏ, <Vị trí> là 1 biểu thức số nguyên.
Ví dụ 2: Giả sử có khai báo:
#include <stdio.h> #include <alloc.h> #include <conio.h> #include <stdlib.h>/* Them vao so voi phien ban tren DOS*/ void main() { int *a; int i; a=(int*)malloc(sizeof(int)*10); for(i=0;i<10;i++) a[i] = 2*i; printf("Truy cap theo kieu mang: "); for(i=0;i<10;i++) printf("%d ",a[i]); printf("\nTruy cap theo kieu con tro: "); for(i=0;i<10;i++) printf("%d ",*(a+i)); getch(); }
Con trỏ chỉ đến phần tử mảng
Giả sử con trỏ ptr chỉ đến phần tử a[i] nào đó của mảng a thì:
ptr + j chỉ đến phần tử thứ j sau a[i], tức a[i+j]
ptr – j chỉ đến phần tử đứng trước a[i], tức a[i-j]
Ví dụ 3: Giả sử có 1 mảng mang_int, cho con trỏ contro_int chỉ đến phần tử thứ 5 trong mảng. In ra các phần tử của contro_int & mang_int.
#include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> /* Them vao so voi phien ban tren DOS*/ void main() { int i,mang_int[10]; int *contro_int; for(i=0;i<=9;i++) mang_int[i]=i*2; contro_int=&mang_int[5]; printf("\nNoi dung cua mang_int ban dau="); for (i=0;i<=9;i++) printf("%d ",mang_int[i]); printf("\nNoi dung cua contro_int ban dau ="); for (i=0;i<5;i++) printf("%d ",contro_int[i]); for(i=0;i<5;i++) contro_int[i]++; printf("\n--------------------"); printf("\nNoi dung cua mang_int sau khi tang 1="); for (i=0;i<=9;i++) printf("%d ",mang_int[i]); printf("\nNoi dung cua contro_int sau khi tang 1="); for (i=0;i<5;i++) printf("%d ",contro_int[i]); if (contro_int!=NULL) free(contro_int); getch(); }
Con trỏ và mảng nhiều chiều
Ta có thể sử dụng con trỏ thay cho mảng nhiều chiều như sau: Giả sử ta có mảng 2 chiều và biến con trỏ như sau:
int a[n][m];
int *contro_int;
Thực hiện phép gán
contro_int=a;
khi đó phần tử a[0][0] được quản lý bởi contro_int;
a[0][1] được quản lý bởi contro_int+1;
a[0][2] được quản lý bởi contro_int+2;
…
a[1][0] được quản lý bởi contro_int+m;
a[1][1] được quản lý bởi contro_int+m+1;
…
a[n-1][m-1] được quản lý bởi contro_int+(n-1)*m + (m-1);
Tương tự như thế đối với mảng nhiều hơn 2 chiều.
Ví dụ 4: Sự tương đương giữa mảng 2 chiều và con trỏ.
#include <stdio.h> #include <conio.h> #include <alloc.h> #include <stdlib.h> void main() { int i,j; int mang_int[4][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; int *contro_int; contro_int=(int*)mang_int; printf("\nNoi dung cua mang_int ban dau="); for (i=0;i<4;i++) { printf("\n"); for (j=0;j<5;j++) printf("%d\t",mang_int[i][j]); } printf("\n-----------------------------"); printf("\nNoi dung cua contro_int ban dau \n"); for (i=0;i<20;i++) printf("%d ",contro_int[i]); for(i=0;i<20;i++) contro_int[i]++ ; printf("\n-----------------------------"); printf("\nNoi dung cua mang_int sau khi tang 1="); for (i=0;i<4;i++) { printf("\n"); for (j=0;j<5;j++) printf("%d\t",mang_int[i][j]); } printf("\nNoi dung cua contro_int sau khi tang 1=\n"); for (i=0;i<20;i++) printf("%d ",contro_int[i]); if (contro_int!=NULL) free(contro_int); getch(); }
Con trỏ và tham số hình thức của hàm
Khi tham số hình thức của hàm là một con trỏ thì theo nguyên tắc gọi hàm ta dùng tham số thực tế là 1 con trỏ có kiểu giống với kiểu của tham số hình thức. Nếu lúc thực thi hàm ta có sự thay đổi trên nội dung vùng nhớ được chỉ bởi con trỏ tham số hình thức thì lúc đó nội dung vùng nhớ được chỉ bởi tham số thực tế cũng sẽ bị thay đổi theo.
Ví dụ: Xét hàm hoán vị được viết như sau :
#include<stdio.h> #include<conio.h> void HoanVi(int *a, int *b) { int c=*a; *a=*b; *b=c; } void main() { int m=20,n=30; printf("Truoc khi goi ham m= %d, n= %d\n",m,n); HoanVi(&m,&n); printf("Sau khi goi ham m= %d, n= %d",m,n); getch(); }