C là một ngơn ngữ lập trình có cấu trúc, tuy vậy nó vẫn chứa một số câu lệnh làm phá vớ cấu trúc của chương trình:
Bài 8 Con trỏ Mục tiêu:
8.4.1 Con trỏ và mảng nhiều chiều
Một mảng nhiều chiều cũng có thể được biểu diễn dưới dạng con trỏ của mảng một chiều (tên của mảng) và một độ dời (chỉ số). Thực hiện được điều này là bởi vì một mảng nhiều chiều là một tập hợp của các mảng một chiều.Ví dụ, một mảng hai chiều có thể được định nghĩa như là một con trỏ đến một nhóm các mảng một chiều kế tiếp nhau. Cú pháp báo mảng hai chiều có thể viết như sau:
data_type (*ptr_var)[expr 2]; thay vì
data_type array[expr 1][expr 2];
Khái niệm này có thể được tổng quát hóa cho các mảng nhiều chiều, đó là, data_type (*ptr_var)[exp 2] .... [exp N]; thay vì
data_type array[exp 1][exp 2] ... [exp N];
Trong các khai báo trên, data_type là kiểu dữ liệu của mảng, ptr_var là tên của biến con trỏ, array là tên mảng, và exp 1, exp 2, exp 3, ... exp N là các giá trị nguyên dương xác định số lượng tối đa các phần tử mảng được kết hợp với mỗi chỉ số.
Chú ý dấu ngoặc () bao quanh tên mảng và dấu * phía trước tên mảng trong cách khai báo theo dạng con trỏ. Cặp dấu ngoặc () là không thể thiếu, ngược lại cú pháp khai báo sẽ khai báo một mảng của các con trỏ chứ khơng phải một con trỏ của một nhóm các mảng.
Ví dụ, nếu ary là một mảng hai chiều có 10 dịng và 20 cột, nó có thể được khai báo như sau: int (*ary)[20];
thay vì
int ary[10][20];
Trong sự khai báo thứ nhất, ary được định nghĩa là một con trỏ trỏ tới một nhóm các mảng một chiều liên tiếp nhau, mỗi mảng có 20 phần tử kiểu số ngun. Vì vậy, ary trỏ đến phần tử đầu tiên của mảng, đó là dịng đầu tiên (dịng 0) của mảng hai chiều. Tương tự, (ary + 1) trỏ đến dòng thứ hai của mảng hai chiều, ...
Một mảng thập phân ba chiều fl_ary có thể được khai báo như: float (*fl_ary)[20][30];
thay vì
Trong khai báo đầu, fl_ary được định nghĩa như là một nhóm các mảng thập phân hai chiều có kích thước 20 x 30 liên tiếp nhau. Vì vậy, fl_ary trỏ đến mảng 20 x 30 đầu tiên, (fl_ary + 1) trỏ đến mảng 20 x 30 thứ hai,...
Trong mảng hai chiều ary, phần tử tại dịng 4 và cột 9 có thể được truy xuất sử dụng câu lệnh: ary[3][8];
hoặc
*(*(ary + 3) + 8);
Cách thứ nhất là cách thường được dùng. Trong cách thứ hai, (ary + 3) là một con trỏ trỏ đến dịng thứ 4. Vì vậy, đối tượng của con trỏ này, *(ary + 3), tham chiếu đến tồn bộ dịng. Vì dịng 3 là một mảng một chiều, *(ary + 3) là một con trỏ trỏ đến phần tử đầu tiên trong dịng 3, sau đó 8 được cộng vào con trỏ. Vì vậy, *(*(ary + 3) + 8) là một con trỏ trỏ đến phần tử 8 (phần tử thứ 9) trong dịng thứ 4. Vì vậy đối tượng của con trỏ này, *(*(ary + 3) + 8), tham chiếu đến tham chiếu đến phần tử trong cột thứ 9 của dịng thứ 4, đó là ary [3][8].
Có nhiều cách thức để định nghĩa mảng, và có nhiều cách để xử lý các phần tử mảng. Lựa chọn cách thức nào tùy thuộc vào người dùng. Tuy nhiên, trong các ứng dụng có các mảng dạng số, định nghĩa mảng theo cách thông thường sẽ dễ dàng hơn.
Con trỏ và chuỗi
Chuỗi đơn giản chỉ là một mảng một chiều có kiểu ký tự. Mảng và con trỏ có mối liên hệ mật thiết, và như vậy, một cách tự nhiên chuỗi cũng sẽ có mối liên hệ mật thiết với con trỏ. Xem trường hợp hàm strchr(). Hàm này nhận các tham số là một chuỗi và một ký tự để tìm kiếm ký tự đó trong mảng, nghĩa là,
ptr_str = strchr(strl, ‘a’);
biến con trỏ ptr_str sẽ được gán địa chỉ của ký tự ‘a’ đầu tiên xuất hiện trong chuỗi str. Đây không phải là vị trí trong chuỗi, từ 0 đến cuối chuỗi, mà là địa chỉ, từ địa chỉ bắt đầu chuỗi đến địa chỉ kết thúc của chuỗi.
Chương trình sau sử dụng hàm strchr(), đây là chương trình cho phép người dùng nhập vào một chuỗi và một ký tự để tìm kiếm. Chương trình in ra địa chỉ bắt đầu của chuỗi, địa chỉ của ký tự, và vị trí tương đối của ký tự trong chuỗi (0 là vị trí của ký tự đầu tiên, 1 là vị trí của ký tự thứ hai,...). Vị trí tương đối này là hiệu số giữa hai địa chỉ, địa chỉ bắt đầu của chuỗi và địa chỉ nơi mà ký tự cần tìm đầu tiên xuất hiện.
#include <stdio.h> #include <string.h> int main () { char a, str[81], *ptr; printf(“\nEnter a sentence:”); gets(str);
printf(“\nEnter character to search for:”); a = getche();
/* return pointer to char*/
printf(“\nString starts at address: %u”, str);
printf(“\nFirst occurrence of the character is at address: %u”, ptr);
printf(“\nPosition of first occurrence (starting from 0)is: %d”, ptr-str);
}
Một ví dụ về kết quả thực hiện chương trình như sau:
Enter a sentence: We all live in a yellow submarine Enter character to search for: Y
String starts at address: 65420.
First occurrence of the character is at address: 65437. Position of first occurrence (starting from 0) is: 17
Trong câu lệnh khai báo, biến con trỏ ptr được thiết đặt để chứa địa chỉ trả về từ hàm strchr(), vì
vậy đây là một địa chỉ của một ký tự (ptr có kiểu char).
Hàm strchr() khơng cần thiết phải khai báo nếu thư viện string.h được khai báo.