Giáo trình Cơ Sở Lập Trình Phần 2: Mảng, Xâu Ký Tự và Con Trỏ

Giáo trình về cơ sở lập trình phan 2, biên soạn theo chương trình đào tạo chuẩn, hệ thống hóa kiến thức từ cơ bản đến nâng cao., phục vụ nghiên cứu và ứng dụng thực tiễn

Trường đại học

Trường Đại Học

Chuyên ngành

Lập Trình

Người đăng

Ẩn danh

Thể loại

Giáo Trình

2023

114
3
0

Phí lưu trữ

35 Point

Mục lục chi tiết

3. CHƯƠNG 3: MẢNG, XÂU KÍ TỰ VÀ CON TRỎ

3.1. MẢNG VÀ XÂU

3.2. Khởi tạo mảng

3.3. Dùng mảng làm tham số

3.4. Khai báo và truy nhập vào phần tử của xâu

3.5. Nhập và xuất dữ liệu cho xâu ký tự

3.6. Một số hàm xử lý xâu

Tóm tắt

I. Tổng Quan Giáo Trình Mảng Xâu Ký Tự Trong Lập Trình

Trong lĩnh vực lập trình, việc quản lý và thao tác với dữ liệu là vô cùng quan trọng. Mảngxâu ký tự là hai cấu trúc dữ liệu cơ bản, đóng vai trò then chốt trong việc xây dựng các ứng dụng hiệu quả. Mảng cho phép lưu trữ một tập hợp các phần tử cùng kiểu dữ liệu, giúp truy xuất và xử lý dữ liệu một cách có tổ chức. Trong khi đó, xâu ký tự (hay còn gọi là chuỗi ký tự) là một dãy các ký tự, thường được sử dụng để biểu diễn văn bản, tên, địa chỉ, và nhiều loại thông tin khác. Hiểu rõ về mảngxâu ký tự là nền tảng vững chắc cho bất kỳ lập trình viên nào, bất kể ngôn ngữ lập trình họ sử dụng. Các ngôn ngữ lập trình như C, C++, JavaPython đều hỗ trợ mạnh mẽ mảngxâu ký tự. Chương này sẽ cung cấp kiến thức toàn diện về hai cấu trúc dữ liệu này, từ khái niệm cơ bản đến các ứng dụng nâng cao. Việc nắm vững cách sử dụng mảngxâu ký tự sẽ giúp giải quyết nhiều bài toán thực tế một cách hiệu quả, từ xử lý dữ liệu đơn giản đến xây dựng các hệ thống phức tạp. Cấu trúc dữ liệu mảngcấu trúc dữ liệu xâu đóng vai trò quan trọng trong việc thiết kế thuật toán và tối ưu hóa hiệu năng của chương trình. Tài liệu gốc nhấn mạnh rằng mảng giúp giải quyết các trường hợp cần làm việc với số lượng lớn các biến có cùng kiểu dữ liệu với nhau, một cách đặc biệt. Điều này thể hiện sức mạnh của mảng trong việc quản lý dữ liệu có tổ chức.

1.1. Định Nghĩa và Vai Trò Của Mảng Trong Lập Trình

Trong lập trình, mảng là một cấu trúc dữ liệu quan trọng, cho phép lưu trữ một tập hợp các phần tử có cùng kiểu dữ liệu dưới một tên duy nhất. Các phần tử này được sắp xếp liên tiếp trong bộ nhớ, và mỗi phần tử có thể được truy xuất thông qua chỉ số của nó. Mảng giúp đơn giản hóa việc quản lý và xử lý dữ liệu, đặc biệt khi làm việc với số lượng lớn các phần tử cùng loại. Ví dụ, thay vì khai báo 100 biến riêng lẻ để lưu trữ điểm số của 100 học sinh, ta có thể sử dụng một mảng duy nhất có kích thước 100. Khai báo mảng cần xác định kiểu dữ liệu của các phần tử, tên mảng và kích thước của mảng. Việc truy xuất phần tử mảng được thực hiện thông qua chỉ số, bắt đầu từ 0. Ứng dụng của mảng rất đa dạng, từ lưu trữ dữ liệu đơn giản đến xây dựng các cấu trúc dữ liệu phức tạp hơn như ma trận và đồ thị.

1.2. Giới Thiệu Xâu Ký Tự Trong Lập Trình và Ứng Dụng

Xâu ký tự (hay còn gọi là chuỗi ký tự) là một dãy các ký tự, thường được sử dụng để biểu diễn văn bản. Trong nhiều ngôn ngữ lập trình, xâu ký tự được coi là một mảng ký tự, kết thúc bằng ký tự null ('\0'). Xâu ký tự được sử dụng rộng rãi trong nhiều ứng dụng, từ xử lý văn bản, tìm kiếm và thay thế, đến lưu trữ tên, địa chỉ và thông tin khác. Các thao tác phổ biến trên xâu ký tự bao gồm: tìm độ dài, nối chuỗi, so sánh chuỗi, trích xuất chuỗi con, và chuyển đổi giữa chữ hoa và chữ thường. Khai báo xâu có thể thực hiện bằng cách sử dụng mảng ký tự hoặc con trỏ ký tự. Việc lựa chọn phương pháp nào phụ thuộc vào yêu cầu cụ thể của ứng dụng. Ví dụ mảng và xâu ký tự: Ví dụ, xâu ký tự "Hello World" có thể được lưu trữ trong một mảng ký tự có kích thước đủ lớn để chứa tất cả các ký tự, bao gồm cả ký tự null.

II. Thách Thức Khi Lập Trình Với Mảng Và Xâu Ký Tự

Mặc dù mảngxâu ký tự là những công cụ mạnh mẽ, nhưng việc sử dụng chúng cũng đi kèm với một số thách thức. Một trong những thách thức lớn nhất là quản lý bộ nhớ. Khi khai báo mảng, cần xác định kích thước của nó trước, và kích thước này không thể thay đổi trong quá trình thực thi chương trình. Điều này có thể dẫn đến lãng phí bộ nhớ nếu kích thước mảng được khai báo quá lớn, hoặc gây ra lỗi tràn bộ nhớ nếu kích thước mảng không đủ để chứa dữ liệu. Với xâu ký tự, việc quản lý bộ nhớ cũng rất quan trọng, đặc biệt khi thực hiện các thao tác như nối chuỗi hoặc trích xuất chuỗi con. Ngoài ra, cần chú ý đến độ phức tạp thuật toán của các thao tác trên mảngxâu ký tự. Một số thao tác, như tìm kiếm một phần tử trong mảng, có thể có độ phức tạp tuyến tính (O(n)), trong khi các thao tác khác, như sắp xếp mảng, có thể có độ phức tạp cao hơn (O(n log n) hoặc O(n^2)). Việc hiểu rõ độ phức tạp của các thuật toán giúp lựa chọn phương pháp phù hợp để giải quyết bài toán một cách hiệu quả. Các lỗi thường gặp khi lập trình với mảngxâulỗi truy cập ngoài vùng nhớ.

2.1. Quản Lý Bộ Nhớ Hiệu Quả Cho Mảng Và Xâu Ký Tự

Quản lý bộ nhớ là một trong những thách thức quan trọng nhất khi làm việc với mảngxâu ký tự. Việc lưu trữ mảng trong bộ nhớ đòi hỏi việc cấp phát một vùng nhớ liên tục có kích thước đủ lớn để chứa tất cả các phần tử của mảng. Nếu không quản lý bộ nhớ cẩn thận, có thể dẫn đến lãng phí bộ nhớ hoặc gây ra lỗi tràn bộ nhớ. Đối với xâu ký tự, việc quản lý bộ nhớ càng trở nên phức tạp hơn khi thực hiện các thao tác như nối chuỗi hoặc trích xuất chuỗi con. Trong nhiều ngôn ngữ lập trình, việc cấp phát và giải phóng bộ nhớ cho xâu ký tự phải được thực hiện thủ công, đòi hỏi lập trình viên phải cẩn thận để tránh rò rỉ bộ nhớ. Các kỹ thuật quản lý bộ nhớ hiệu quả bao gồm: sử dụng mảng động (có thể thay đổi kích thước trong quá trình thực thi), sử dụng các thư viện hỗ trợ quản lý bộ nhớ tự động, và tránh tạo ra các xâu ký tự tạm thời không cần thiết. Tài liệu gốc chỉ ra rằng mảng là một khối nhớ tĩnh có kích cỡ xác định và trình biên dịch phải có khả năng xác định xem cần bao nhiêu bộ nhớ để cấp phát cho mảng trước khi các lệnh có thể được thực hiện.

2.2. Vấn Đề Độ Phức Tạp Thuật Toán Trong Thao Tác Trên Mảng

Độ phức tạp thuật toán là một yếu tố quan trọng cần xem xét khi lựa chọn phương pháp để thao tác trên mảng. Các thao tác khác nhau có độ phức tạp khác nhau, và việc lựa chọn thuật toán phù hợp có thể ảnh hưởng đáng kể đến hiệu năng của chương trình. Ví dụ, việc tìm kiếm một phần tử trong mảng bằng cách duyệt tuần tự có độ phức tạp tuyến tính (O(n)), trong khi việc tìm kiếm trong một mảng đã được sắp xếp bằng thuật toán tìm kiếm nhị phân có độ phức tạp logarit (O(log n)). Tương tự, các thuật toán sắp xếp mảng khác nhau có độ phức tạp khác nhau, từ O(n^2) (ví dụ: sắp xếp nổi bọt) đến O(n log n) (ví dụ: sắp xếp trộn, sắp xếp nhanh). Khi làm việc với mảng lớn, việc lựa chọn thuật toán có độ phức tạp thấp có thể giúp cải thiện đáng kể hiệu năng của chương trình. Phân tích độ phức tạp thuật toán giúp dự đoán thời gian thực thi và sử dụng tài nguyên của chương trình, từ đó đưa ra các quyết định thiết kế hợp lý.

III. Phương Pháp Khai Báo Khởi Tạo Và Truy Xuất Mảng Xâu

Việc khai báo, khởi tạo và truy xuất mảngxâu ký tự là những thao tác cơ bản mà mọi lập trình viên cần nắm vững. Khai báo mảng bao gồm việc xác định kiểu dữ liệu của các phần tử, tên mảng và kích thước của mảng. Khởi tạo mảng là quá trình gán giá trị ban đầu cho các phần tử của mảng. Việc khởi tạo có thể được thực hiện khi khai báo mảng hoặc sau đó. Truy xuất phần tử mảng được thực hiện thông qua chỉ số của phần tử, bắt đầu từ 0. Tương tự, khai báo xâu ký tự có thể được thực hiện bằng cách sử dụng mảng ký tự hoặc con trỏ ký tự. Khởi tạo xâu ký tự có thể được thực hiện bằng cách gán một chuỗi ký tự trực tiếp cho biến xâu, hoặc bằng cách gán giá trị cho từng ký tự trong xâu. Truy xuất ký tự trong xâu được thực hiện thông qua chỉ số của ký tự, tương tự như truy xuất phần tử trong mảng.

3.1. Khai Báo Mảng Cú Pháp Ví Dụ Chi Tiết Và Lưu Ý

Khai báo mảng là bước đầu tiên để sử dụng mảng trong chương trình. Cú pháp khai báo mảng thường bao gồm kiểu dữ liệu của các phần tử, tên mảng và kích thước của mảng. Ví dụ, trong ngôn ngữ C, để khai báo một mảng các số nguyên có kích thước 10, ta sử dụng cú pháp: int arr[10];. Trong ngôn ngữ Java, cú pháp tương tự là: int[] arr = new int[10];. Khi khai báo mảng, cần chú ý đến việc chọn kiểu dữ liệu phù hợp với loại dữ liệu mà mảng sẽ lưu trữ. Kích thước của mảng phải là một số nguyên dương, và phải được xác định trước khi chương trình thực thi (đối với mảng tĩnh). Cần tránh khai báo mảng có kích thước quá lớn để tránh lãng phí bộ nhớ, hoặc quá nhỏ để tránh lỗi tràn bộ nhớ. Tài liệu gốc nhấn mạnh rằng sizel, size2 ... sizeN của biến mảng ở bên trong cặp ngoặc phải là một giá trị hằng khi khai báo một mảng, vì mảng là một khối nhớ tĩnh có kích cỡ xác định.

3.2. Phương Pháp Khai Báo Xâu Ký Tự Từ Cơ Bản Đến Nâng Cao

Khai báo xâu ký tự có thể được thực hiện bằng hai cách chính: sử dụng mảng ký tự hoặc sử dụng con trỏ ký tự. Khi sử dụng mảng ký tự, cần xác định kích thước của mảng đủ lớn để chứa tất cả các ký tự trong xâu, bao gồm cả ký tự null ('\0'). Ví dụ, trong ngôn ngữ C, để khai báo một xâu ký tự có thể chứa tối đa 20 ký tự, ta sử dụng cú pháp: char str[21]; (cần thêm 1 vị trí cho ký tự null). Khi sử dụng con trỏ ký tự, ta có thể gán một chuỗi ký tự trực tiếp cho con trỏ. Ví dụ: char *str = "Hello";. Tuy nhiên, cần lưu ý rằng trong trường hợp này, chuỗi ký tự được lưu trữ trong vùng nhớ chỉ đọc, và không thể thay đổi nội dung của nó. Để tạo một xâu ký tự có thể thay đổi nội dung, ta cần cấp phát bộ nhớ động cho con trỏ, ví dụ: char *str = (char*) malloc(21 * sizeof(char));. Khai báo xâu bằng mảng ký tự phù hợp khi biết trước kích thước tối đa của xâu, trong khi khai báo xâu bằng con trỏ ký tự phù hợp khi kích thước của xâu có thể thay đổi trong quá trình thực thi chương trình.

IV. Các Thao Tác Cơ Bản Với Mảng và Xâu Ký Tự Trong C

Ngôn ngữ C cung cấp một loạt các thao tác cơ bản để làm việc với mảngxâu ký tự. Đối với mảng, các thao tác phổ biến bao gồm: gán giá trị cho phần tử, truy xuất giá trị của phần tử, duyệt mảng, tìm kiếm phần tử, và sắp xếp mảng. Đối với xâu ký tự, các thao tác phổ biến bao gồm: tìm độ dài xâu, nối xâu, so sánh xâu, trích xuất xâu con, và chuyển đổi giữa chữ hoa và chữ thường. Các hàm thư viện chuẩn trong C, như strcpy, strcat, strcmp, strlen, cung cấp các công cụ mạnh mẽ để thực hiện các thao tác trên xâu ký tự. Việc nắm vững các thao tác cơ bản này là nền tảng quan trọng để xây dựng các ứng dụng phức tạp hơn.

4.1. Thao Tác Với Mảng Trong Lập Trình C Truy Xuất Sửa Đổi

Trong ngôn ngữ C, việc thao tác với mảng bao gồm các thao tác cơ bản như truy xuất phần tử, gán giá trị cho phần tử, và duyệt mảng. Để truy xuất một phần tử trong mảng, ta sử dụng cú pháp arr[i], trong đó arr là tên mảngi là chỉ số của phần tử (bắt đầu từ 0). Để gán giá trị cho một phần tử trong mảng, ta sử dụng cú pháp arr[i] = value;, trong đó value là giá trị cần gán. Để duyệt mảng, ta thường sử dụng vòng lặp for, ví dụ: for (int i = 0; i < size; i++) { ... }, trong đó size là kích thước của mảng. Các thao tác nâng cao hơn trên mảng bao gồm tìm kiếm phần tử (sử dụng thuật toán tìm kiếm tuyến tính hoặc tìm kiếm nhị phân), sắp xếp mảng (sử dụng các thuật toán sắp xếp như sắp xếp nổi bọt, sắp xếp chèn, sắp xếp trộn), và thực hiện các phép toán trên mảng (ví dụ: tính tổng các phần tử, tìm giá trị lớn nhất/nhỏ nhất). Tài liệu gốc nhấn mạnh rằng phần tử thứ ba của mảng a là a[2], vì mảng bắt đầu từ chỉ số 0.

4.2. Các Thao Tác Quan Trọng Trên Xâu Ký Tự Trong C Chuỗi

Trong ngôn ngữ C, việc thao tác với xâu ký tự (hay còn gọi là chuỗi ký tự) bao gồm các thao tác cơ bản như tìm độ dài xâu, nối xâu, so sánh xâu, trích xuất xâu con, và chuyển đổi giữa chữ hoa và chữ thường. Hàm strlen được sử dụng để tìm độ dài của xâu (không bao gồm ký tự null). Hàm strcpy được sử dụng để sao chép một xâu vào một xâu khác. Hàm strcat được sử dụng để nối một xâu vào cuối một xâu khác. Hàm strcmp được sử dụng để so sánh hai xâu. Hàm strstr được sử dụng để tìm kiếm một xâu con trong một xâu lớn hơn. Các hàm touppertolower được sử dụng để chuyển đổi ký tự sang chữ hoa và chữ thường, tương ứng. Các thao tác nâng cao hơn trên xâu ký tự bao gồm phân tích cú pháp xâu, mã hóa/giải mã xâu, và xử lý biểu thức chính quy.

V. Ứng Dụng Thực Tế Của Mảng Và Xâu Ký Tự Trong Lập Trình

Mảngxâu ký tự có rất nhiều ứng dụng thực tế trong lập trình. Mảng được sử dụng để lưu trữ dữ liệu có cấu trúc, như danh sách sản phẩm, thông tin khách hàng, hoặc kết quả của các phép tính toán. Xâu ký tự được sử dụng để biểu diễn văn bản, tên, địa chỉ, và nhiều loại thông tin khác. Trong các ứng dụng web, xâu ký tự được sử dụng để xử lý dữ liệu nhập vào từ người dùng, tạo ra các trang web động, và giao tiếp với cơ sở dữ liệu. Trong các ứng dụng di động, xâu ký tự được sử dụng để hiển thị văn bản trên màn hình, xử lý tin nhắn, và lưu trữ thông tin cá nhân. Trong các ứng dụng khoa học và kỹ thuật, mảng được sử dụng để biểu diễn ma trận, vector, và các cấu trúc dữ liệu phức tạp khác.

5.1. Mảng Đa Chiều Và Ứng Dụng Trong Xử Lý Ảnh Ma Trận

Mảng đa chiều là một mở rộng của mảng một chiều, cho phép lưu trữ dữ liệu trong một không gian nhiều chiều. Ví dụ, mảng hai chiều có thể được sử dụng để biểu diễn một ma trận, trong đó mỗi phần tử được xác định bởi hai chỉ số (hàng và cột). Mảng ba chiều có thể được sử dụng để biểu diễn một khối dữ liệu 3D, hoặc một ảnh màu (trong đó mỗi điểm ảnh được biểu diễn bởi ba giá trị màu: đỏ, xanh lá, xanh lam). Ứng dụng của mảng đa chiều rất đa dạng, từ xử lý ảnh (lọc ảnh, nhận dạng đối tượng), đến giải các bài toán tuyến tính (giải hệ phương trình, tìm giá trị riêng), và mô phỏng các hệ thống vật lý. Việc lưu trữ mảng đa chiều trong bộ nhớ thường được thực hiện theo một trong hai cách: lưu trữ theo hàng (row-major order) hoặc lưu trữ theo cột (column-major order). Việc lựa chọn phương pháp nào phụ thuộc vào ngôn ngữ lập trình và kiến trúc phần cứng.

5.2. Xâu Ký Tự Trong Các Ứng Dụng Xử Lý Văn Bản Tìm Kiếm

Xâu ký tự đóng vai trò quan trọng trong các ứng dụng xử lý văn bản và tìm kiếm. Các thao tác cơ bản trên xâu ký tự, như tìm kiếm xâu con, thay thế xâu, và phân tích cú pháp xâu, được sử dụng rộng rãi trong các trình soạn thảo văn bản, trình duyệt web, và các công cụ tìm kiếm. Các thuật toán tìm kiếm hiệu quả, như thuật toán Knuth-Morris-Pratt (KMP) và thuật toán Boyer-Moore, được sử dụng để tìm kiếm xâu con trong một xâu lớn hơn một cách nhanh chóng. Các biểu thức chính quy (regular expressions) cung cấp một công cụ mạnh mẽ để mô tả các mẫu xâu phức tạp, và được sử dụng trong các ứng dụng kiểm tra dữ liệu nhập vào, trích xuất thông tin từ văn bản, và thay thế xâu. Các thư viện xử lý xâu ký tự trong các ngôn ngữ lập trình hiện đại cung cấp nhiều chức năng tiện lợi để làm việc với xâu ký tự một cách dễ dàng và hiệu quả.

VI. Con Trỏ Và Mảng Xâu Mối Liên Hệ Sâu Sắc Trong Lập Trình C

Trong ngôn ngữ C, con trỏmảng, xâu ký tự có mối liên hệ mật thiết với nhau. Tên của mảng thực chất là một con trỏ trỏ đến phần tử đầu tiên của mảng. Điều này có nghĩa là ta có thể sử dụng con trỏ để truy xuất các phần tử của mảng, và ngược lại. Tương tự, xâu ký tự trong C được biểu diễn như một mảng các ký tự, kết thúc bằng ký tự null. Do đó, ta cũng có thể sử dụng con trỏ để thao tác với xâu ký tự. Việc hiểu rõ mối liên hệ giữa con trỏmảng, xâu ký tự giúp lập trình viên viết mã C một cách hiệu quả và linh hoạt hơn.

6.1. Sử Dụng Con Trỏ Truy Xuất Phần Tử Mảng Ưu Điểm Và Hạn Chế

Sử dụng con trỏ để truy xuất các phần tử của mảng có thể mang lại một số ưu điểm, như tăng tốc độ truy xuất (trong một số trường hợp), và cho phép thực hiện các phép toán trên địa chỉ bộ nhớ. Tuy nhiên, việc sử dụng con trỏ cũng đi kèm với một số hạn chế, như tăng nguy cơ gây ra lỗi truy cập bộ nhớ (nếu con trỏ trỏ đến một vùng nhớ không hợp lệ), và làm cho mã nguồn trở nên khó đọc và khó bảo trì hơn. Khi sử dụng con trỏ để truy xuất các phần tử của mảng, cần cẩn thận để đảm bảo rằng con trỏ luôn trỏ đến một vùng nhớ hợp lệ, và rằng các phép toán trên địa chỉ bộ nhớ được thực hiện một cách chính xác. Ví dụ con trỏ và mảng: Ví dụ, nếu ta có một mảng int arr[10];, thì arr&arr[0] đều trỏ đến địa chỉ của phần tử đầu tiên của mảng.

6.2. Con Trỏ Và Xâu Ký Tự Các Kỹ Thuật Thao Tác Nâng Cao

Trong ngôn ngữ C, xâu ký tự thường được biểu diễn bằng con trỏ kiểu char*. Điều này cho phép ta sử dụng con trỏ để duyệt qua các ký tự trong xâu, và thực hiện các thao tác như tìm kiếm, thay thế, và sao chép. Các kỹ thuật thao tác nâng cao trên xâu ký tự sử dụng con trỏ bao gồm: sử dụng con trỏ để trích xuất xâu con (mà không cần sao chép dữ liệu), sử dụng con trỏ để nối xâu một cách hiệu quả, và sử dụng con trỏ để thực hiện các phép toán trên xâu (ví dụ: đảo ngược xâu, mã hóa xâu). Khi sử dụng con trỏ để thao tác với xâu ký tự, cần chú ý đến việc quản lý bộ nhớ, và đảm bảo rằng con trỏ luôn trỏ đến một vùng nhớ hợp lệ. Ví dụ con trỏ và xâu ký tự: Ví dụ, hàm strlen có thể được triển khai bằng cách sử dụng con trỏ để duyệt qua các ký tự trong xâu cho đến khi gặp ký tự null.

16/08/2025

Trích đoạn nội dung tài liệu

Chương 3 MẢNG, XÂU KÍ Tự VÀ CON TRỎ 3. MẢNG VÀ XÂU 3. Mảng Để giải quyết các trường hợp cần phải làm việc với một số lượng lớn các biến có cùng kiểu dữ liệu với nhau, ngôn ngữ c cung cấp một loại biến đặc biệt gọi là mảng. Màng là một dãy các phần tử có cùng kiểu dữ liệu được đặt liên tiếp trong bộ nhớ và có thể truy xuất đến từng phần tử thông qua chỉ số mảng.

Chỉ số màng là thành phần được đặt trong cặp [ ] và đứng sau tên của mảng. Điều này có nghĩa là, chúng ta có thể lưu 5 giá trị kiểu int mà không cần phải khai báo 5 biến khác nhau.Ví dụ, một mảng chứa 5 giá trị nguyên kiểu int có tên là a có thể được biểu diễn như sau: 0 i 2 3 4 2B 2B 2B 2B 2B Trong đó mỗi một ô trống biểu diễn một phần tử của mảng, trong trường hợp này là các giá trị nguyên kiểu int. Chúng được đánh số từ 0 đến 4 vì phần tử đầu tiên của mảng luôn là 0 bất kể độ dài của nó là bao nhiêu. Như vậy với một mảng được hiểu như sau: - Tập hợp các phần tử cùng kiểu.

- Các phần tử phân biệt bởi chi số mảng - Mỗi phần tử như một biến đơn có địa chỉ liên tiếp trong ô nhớ - Kiểu mảng là kiểu các phần tử Thông tin về mảng sẽ phải bao gồm: - Kiểu mảng. Ví dụ như int 77 - Tên mảng. Tên mảng được đặt cũng phải tuân thủ theo qui tắc đặt tên. - Số các phần tử hay kích thước của mảng.

Như ví dụ trên thì số các phần tử của mảng là 5. Cú pháp chung nhất khi khai báo một mảng được định nghĩa như sau: <kiểu dữliệu> <tên mảng> [sizel][[size2][.[sizeN]]]; Trong đó: Kiểu dữ liệu là các kiểu dữ liệu cơ sở như đà định nghĩa ở trên; Tên mảng là tên được đặt cho mảng., sizeN là các số qui định kích cỡ của mảng hoặc số phần tử ưong mảng, số lượng thành phần [] được đặt sau tên mảng sẽ qui định chiều của mảng đó., a[8], a[9] hoặcint arr[2][3]; arr là mảng hai chiều kiểu nguyên gồm có 2x3 = 6 phần tử. Chú ý: Các lỗi thường gặp: int n,m; int a[n][m]; //n, m chưa xác định Chú ý: sizel,size2.sizeN của biến màng ở bên trong cặp ngoặc n phải là một giá trị hằng khi khai báo một mảng, vì mảng là một khối nhớ tĩnh có kích cỡ xác định và trình biên dịch phải có khả năng xác định xem cần bao nhiêu bộ nhớ để cấp phát cho mảng trước khi các lệnh có thể được thực hiện. Vì thế các câu lệnh viết như trên là sai, chương trình sẽ báo các lỗi như: 78 expected constant expression (cần một biểu thức hằng) cannot allocate an array of constant size 0 (không thể cấp phát một mảng kích thước 0) 'a': unknown size (a: không biết kích cỡ) 3.

Khởi tạo mảng Khi khai báo một màng với tầm hoạt động địa phương (trong một hàm), theo mặc định nó sẽ không được khởi tạo, vì vậy nội dung của nó là không xác định cho đến khi chúng ta lưu các giá trị lên đó. Nếu chúng ta khai báo một màng toàn cục (bên ngoài tất cả các hàm) nó sẽ đựợc khởi tạo và tất cà các phần tử được đặt băng 0 nếu là mảng có dữ liệu kiểu số và NULL nếu màng có dữ liệu kiểu con trỏ. Vì vậy nếu chúng ta khai báo mảng toàn cục: char a[5]; thì mọi phần tử của a sẽ được khởi tạo là 0: 0 12 3 4 00000000 00000000 00000000 00000000 00000000 Tuy nhiên, khi khai báo một mảng, chúng ta có thể gán các giá trị khởi tạo cho từng phần tử của nó. Ví dụ: char a[5] = {0,1,4,3,2}; lệnh trên sẽ khai báo một màng như sau: 0 12 3 4 00000000 00000001 00000100 00000011 00000010 Hay nếu viết theo giá trị thập phân sẽ là: 0 12 3 4 0 1 4 3 2 79 Điều này tương đương với khi khởi tạo a[0] =0, a[l] = 1, a[2] = 4, a[3] = 3,a[4] = 2 Tuy nhiên, khi khỏi tạo, có thể không cần khởi tạo hết tất cả các phần tử của mảng.

Có thể tổng quát như sau. Với mảng 1 chiều'. <kiểu dữ liệu> <tên mảng> [size]={gtl,gt2,gt3,.,gtk}; (k<=N) Khi đó thì k phần tử đầu tiên của mảng 1 chiều này sẽ được khởi tạo với các giá trị liên tiếp tương ứng gtl, gt2, gt3,. Hoặc: <kỉểu dữ liệu> <tên mảng> []={gtl,gt2,gt3,.,gtk}; thì mảng có được sẽ là mảng một chiều có k phần tử.

Với mảng hai chiều'. Mảng 2 chiều tương đương với mảng 1 chiều n phần tử mà mỗi phàn tử lại là mảng 1 chiều m phần tử. Vì vậy khi khai báo một mảng hai chiều như sau: <kỉểu dữ liệu> <tên mảng> [sizel][size2]; Thì trình biên dịch sẽ cấp phát cho mảng fren một vùng nhớ là sizel* size2*sizeof(<kiểu dữ liệu>). về hàm sizeof() các bạn có thể đọc thêm ở cuối chương này.

Ví dụ về mảng int a[2][3], các bạn có thể tưởng tượng nó giống như hình sau: Index 0 1 2 0 2B 2B 2B 1 2B 2B 2B Mảng này sẽ có 2 dòng và 3 cột và 6 phần tử. Mỗi một phần tử tương đương với một biến kiểu int. Hoặc có thể khởi tạo như sau: 80 <kiểu dữ liệu> <tên mảng> [sizel] [size2] ={ {an,ai2,ai3,. là giá trị khởi đầu của hàng đầu tiên của mảng.

là giá trị khởi đầu của hàng thứ hai của mảng. Ở đây số giá trị khởi đầu của mỗi hàng không yêu cầu phải giống nhau. Và giá trị khởi đầu cùa các phần tử trong mỗi hàng sẽ được gán đứng vị trí của chúng trong màng. Ví dụ int a[][4]={ {0},{l,3,5}, {2,4,6,8} } Lúc này: a[0] [0] =0 a[l][0]=l, a[l][l]=3, a[l][2]=5, và a[2][0]=2, a[2][l]=4, a[2][2]=6, a[2][3]=8 Ngoài ra mảng hai chiều còn có cách khởi tạo khác như sau: <kiểu dữ liệu> <tên mảng> [sizel][size2] ={gtl, gt2,.,gtk}; (k <= sizel*size2) Khi đó m giá trị đầu tiên của k gán cho dòng 1, m giá trị tiếp theo gán cho dòng 2, ., cho đến hết k giá trị, còn lại gán là 0, NULL hoặc giá trị bất kì tuỳ theo kiểu dữ liệu và mảng là biến toàn cục hay biến cục bộ.

81 Ví dụ a[3][2]={l,2,3,4,5,6}; Hoặc: <kỉểu dữ liệu> <tên mảng> [] [size2J ={gtl, gt2,.,gtk}; thì mảng có được sẽ được cấp phát cho số dòng là sizel = [k/m] +1 và các phần tử của mảng lại được khởi tạo theo đúng qui trình lần lượt hết các phần tử ở dòngl, rồi đến dòng2,. Truy xuất đến các phần tử của mảng Ờ bất kì điểm nào của chương trình trong tầm hoạt động của mảng, chúng ta có thể truy xuất từng phần tử của mảng để đọc hay chỉnh sửa như là đối với một biến bình thường, cấu trúc của nó như sau: Tên_mảng\chỉ_số\ Như ở trong ví dụ trước ta có mảng a gồm 5 phần tử có kiểu int, chúng ta có thể truy xuất đến từng phần tử cùa mảng như sau: a[OJ 3(1] 3(2] 3(3] 3(4] 0 1 4 3 2 Ví dụ, để lưu giá trị 75 vào phần tử thứ ba của a ta viết như sau: a[2] = 75; và ví dụ để gán giá trị của phần tử thứ 3 cùa b cho biến X, chúng ta viết: X = a[2] ; Vì vậy, xét về mọi phương diện, biểu thức 3(2] giống như bất kì một biến kiểu int khác mà thôi. Chú ý rằng phần tử thứ ba của a là a [2], vì màng bắt đầu từ chỉ số 0. Vì vậy, phần tử cuối cùng sẽ là a [4].

Vì vậy nếu chúng ta viết a [5], chúng ta sẽ truy xuất đến phần tử thứ 6 của mảng và vượt quá giới hạn của mảng. Việc vượt quá giới hạn chỉ số của màng là hoàn toàn hợp lệ, Tuy nhiên, nó có thể gây ra những vấn đề thực sự khó phát hiện bởi vì chúng không tạo ra những lỗi bong quá trình dịch nhưng chúng có thể tạo ra những kết quả không mong muốn frong quá trình thực hiện. 82 Nguyên nhân của việc này sẽ được nói đến kĩ hơn ở phần sử dụng con trỏ (mục 3. Cần phải nhấn mạnh rằng chúng ta sử dụng cặp ngoặc vuông cho hai mục đích: Đầu tiên là đặt kích thước cho mảng khi khai báo chúng và thứ hai, để chỉ định chỉ số cho một phần tử cụ thể của mảng khi xem xét đến nó.

int a[5]; // khai báo một mảng mới. int x,i; a[2) = 75; // truy xuất đến một phần tử của mảng. Một vài thao tác hợp lệ khác với màng: a[0] = x; // Gán giá trị biến X cho phần tử a[OJ a[i] = 75; // Gán giá trị 75 cho phần tử a[i] , i đã khai báo ở hên X = a [i+2]; // Gán cho X giá trị của phần tử a[i+2] a[a[i]] = a[2) + 5; // Gán cho a[a[i]] giá fri của phần tử a[2) + 5. Nói chung chỉ được viết a[i] với i cũng là một biến khi mà i đã được khai báo là một biến kiểu nguyên.

Với mảng hai chiều, việc truy xuất tới các phàn tử của mảng cũng tương tự như mảng một chiều. Mảng hai chiều cũng phải bắt đầu từ phần tử có chỉ số 0, tức là a[0][0]. Truy xuất tới phần tử a[i][j] có nghĩa là phần tử ở dòng i cột j và cũng như mảng một chiều. Với mảng hai chiều, thường sử dụng define để định nghĩa trước kích cỡ của mảng.

Việc khai báo define này cũng sẽ tiện lợi khi muốn thay đổi giới hạn kích cỡ của mảng.1: Nhập và in ra một ma trận số nguyên a(n,m) với n và m không vượt quá 100.h> #defineN 100 #define M 100 83 int main() { _ int a[N][M]; int n,m,i j; // kiem tra neu so dong hoac so cot vuot qua 100 Do { printf("\n Nhap so dong:"); scanf("%d",&n); printf("\n Nhap so cot:"); scanf("%d",&m); } while (n>=N||m>=M); // phan nhap cac phan tu ma tran printf("\n Nhap cac phan tu ma tran:"); for(i=0;i<n;i++) for(j=0j<m;j++) { printf("a[%d][%d]=",ij); scanf("%d",&a[i][j]); } // phan in ra printf("\n Ma tran vua nhap la:\n"); for(i=0;i<n;i++) { for(j=0;j<m;j-H-) printf("%d ",a[i][j]); printf("\n"); } return 1; } 84 Để in ra dưới dạng ma trận phải sử dụng hai vòng lặp for cho số dòng và số cột của ma trận. Trong đó, cứ hết một dòng lại phải in xuống dòng. Cụ thể phần cài đặt của in ma ưận là: printf("\n Ma tran vua nhap la:\n"); for(ì=0;i<n;i++) { for(j=Oj<mj++) printf("%d ",a[i][j]); printf("\n"); } Ví dụ 3.2: Quay trở lại bài toán dãy sổ ban đầu. Để nhập một dãy số sau đó in ra dãy tăng dần, có thể sử dụng một màng nguyên 1 chiều.

Thuật toán sắp xếp cũng có thể sử dụng thuật toán đơn giàn nhất là sắp xếp tuyến tính. Cài đặt như sau: #include <stdio.

Nội dung được bảo vệ bản quyền — Tải xuống đầy đủ