Chuỗi trong C (String)
- 02-11-2023
- Toanngo92
- 0 Comments
Mục lục
Giới thiệu
Trong ngôn ngữ C, chuỗi được triển khai dưới dạng mảng các ký tự kết thúc bằng ký tự NULL (‘\0’). Phần này sẽ thảo luận về cách sử dụng và thao tác với chuỗi.
Biến và Hằng số Chuỗi
Biến chuỗi được sử dụng để lưu trữ một chuỗi ký tự. Giống như bất kỳ biến nào khác, những biến này phải được khai báo trước khi sử dụng. Một khai báo biến chuỗi điển hình là:
char str[10];
str là một biến mảng ký tự có thể chứa tối đa 10 ký tự. Giả sử rằng str được gán một hằng số chuỗi, “WELL DONE”.
Hằng số chuỗi là một chuỗi các ký tự được bao quanh bởi dấu ngoặc kép. Mỗi ký tự trong chuỗi được lưu trữ dưới dạng phần tử mảng. Trong bộ nhớ, chuỗi được lưu trữ như sau:
‘W’ | ‘E’ | ‘L’ | ‘L’ | ‘ ‘ | ‘D’ | ‘O’ | ‘N’ | ‘E’ | ‘\0’ |
Ký tự “0” (NULL) được tự động thêm vào trong biểu diễn nội bộ của chuỗi để cho phép chương trình có thể xác định được cuối của chuỗi. Vì vậy, khi khai báo một biến chuỗi, cần phải cho phép thêm một phần tử bổ sung để lưu ký tự kết thúc NULL.
Con trỏ đến Chuỗi
Chuỗi cũng có thể được lưu trữ và truy cập bằng cách sử dụng con trỏ ký tự. Một con trỏ ký tự đến một chuỗi được khai báo như sau:
char *pstr = "WELCOME";
pstr là một con trỏ được khởi tạo để trỏ đến một hằng số chuỗi. Con trỏ có thể được sửa đổi để trỏ đến nơi khác. Tuy nhiên, việc sửa đổi này sẽ khiến chuỗi ban đầu trở nên không thể truy cập được.
Các Thao tác Vào/Ra Chuỗi
Các thao tác Vào/Ra chuỗi (I/O) trong C được thực hiện bằng cách sử dụng các cuộc gọi hàm. Các hàm này là một phần của thư viện tiêu chuẩn của C được gọi là <stdio.h>. Một chương trình sử dụng các hàm I/O chuỗi phải có câu lệnh sau ở đầu:
#include <stdio.h>
Khi chương trình chứa câu lệnh này được biên dịch, nội dung của tệp <stdio.h> sẽ trở thành một phần của chương trình.
Các Thao Tác Cơ Bản trên Chuỗi
Hàm gets() là phương pháp đơn giản nhất để nhập một chuỗi thông qua đầu vào tiêu chuẩn. Ký tự đầu vào được chấp nhận cho đến khi phím Enter được nhấn. Hàm gets() thay thế ký tự kết thúc dòng mới “\n” bằng ký tự “NULL” ‘\0’. Cú pháp của nó như sau:
gets(str);
Trong đó, str là một mảng ký tự đã được khai báo.
Tương tự, hàm puts() được sử dụng để hiển thị một chuỗi trên thiết bị đầu ra tiêu chuẩn. Ký tự xuống dòng newline kết thúc chuỗi đầu ra. Cú pháp của hàm là:
puts(str);
Trong đó, str là một mảng ký tự đã được khai báo và khởi tạo. Chương trình dưới đây chấp nhận tên và hiển thị một thông báo:
Ví dụ 1:
#include <stdio.h>
void main()
{
char name[20]; // name được khai báo là một mảng ký tự một chiều
puts("Nhập tên của bạn:"); // Hiển thị một thông báo
gets(name); // Chấp nhận đầu vào
puts("Xin chào:"); // Hiển thị một thông báo
puts(name); // Hiển thị đầu vào
}
Nếu tên Lisa được nhập, đầu ra mẫu cho chương trình trên sẽ là:
Nhập tên của bạn:
Lisa
Xin chào:
Lisa
Thao tác Chuỗi Đã Định Dạng
Hàm scanf() và printf() cũng có thể được sử dụng để chấp nhận và hiển thị giá trị chuỗi. Những hàm này được sử dụng để chấp nhận và hiển thị các loại dữ liệu kết hợp trong một lệnh duy nhất. Cú pháp để chấp nhận một chuỗi như sau:
scanf("%s", str);
Ở đây, %s là biểu thức định dạng xác định rằng một giá trị chuỗi sẽ được chấp nhận. str là một mảng ký tự đã được khai báo. Tương tự, để hiển thị một chuỗi, cú pháp là:
printf("%s", str);
Ở đây, %s là biểu thức định dạng xác định rằng một giá trị chuỗi sẽ được hiển thị và str là một mảng ký tự đã được khai báo và khởi tạo. Hàm printf() cũng có thể được sử dụng mà không cần biểu thức định dạng để hiển thị các thông điệp.
Chương trình trước đó có thể được chỉnh sửa để chấp nhận và hiển thị tên bằng cách sử dụng scanf() và printf().
Ví dụ 2:
#include <stdio.h>
void main()
{
char name[20]; // name được khai báo là một mảng ký tự một chiều
printf("Nhập tên của bạn:"); // Hiển thị một thông báo
scanf("%s", name); // Chấp nhận đầu vào
printf("Xin chào: %s", name); // Hiển thị đầu vào
}
nếu tên Brendan được nhập, đầu ra mẫu cho chương trình trên sẽ là:
Nhập tên của bạn: Brendan
Xin chào: Brendan
Hàm String
- Ghép nối chuỗi
- So sánh chuỗi
- Tìm kiếm 1 ký tự trong chuỗi
- Sao chép 1 chuỗi sang chuỗi khác
- Tính độ dài của chuỗi
Hàm ‘strcat()’
Hàm ‘strcat()’ được sử dụng để nối hai giá trị chuỗi thành một chuỗi duy nhất. Cú pháp của hàm này như sau:
strcat(str1, str2);
Ở đây, str1 và str2 là hai mảng ký tự đã được khai báo và khởi tạo trước. Giá trị trong str2 được nối vào cuối của str1.
Chương trình dưới đây cho phép nhập tên và họ. Sau đó, nó nối họ vào tên và hiển thị tên đã nối.
Ví dụ 3:
#include <stdio.h>
#include <string.h>
int main() {
char firstname[15];
char lastname[15];
printf("Nhập tên của bạn: ");
scanf("%s", firstname);
printf("Nhập họ của bạn: ");
scanf("%s", lastname);
strcat(firstname, lastname); // Nối nội dung của lastname vào cuối firstname
printf("%s", firstname);
return 0;
}
Kết quả mẫu cho chương trình trên sẽ là:
Nhập tên của bạn: Carla
Nhập họ của bạn: Johnson
CarlaJohnson
Hàm ‘strcmp()’
Để so sánh chuỗi, ta không thể sử dụng toán tử quan hệ như để so sánh các số. Thay vào đó, chúng ta phải sử dụng một hàm gọi. Hàm ‘strcmp()’ so sánh hai chuỗi và trả về một giá trị số nguyên dựa trên kết quả của sự so sánh. Cú pháp của hàm là:
int strcmp(str1, str2);
Ở đây, str1 và str2 là hai mảng ký tự đã được khai báo và khởi tạo trước. Hàm này trả về một giá trị:
- Nhỏ hơn 0 nếu str1 < str2
- Bằng 0 nếu str1 giống str2
- Lớn hơn 0 nếu str1 > str2
Chương trình sau đây so sánh một tên với ba tên khác và hiển thị kết quả của các so sánh.
Ví dụ 4:
#include <stdio.h>
#include <string.h>
void main()
{
char name1[15] = "Geena";
char name2[15] = "Dorothy";
char name3[15] = "Shania";
char name4[15] = "Geena";
int i;
i = strcmp(name1, name2);
printf("%s so sánh với %s trả về %d\n", name1, name2, i);
i = strcmp(name1, name3);
printf("%s so sánh với %s trả về %d\n", name1, name3, i);
i = strcmp(name1, name4);
printf("%s so sánh với %s trả về %d\n", name1, name4, i);
}
Kết quả mẫu cho chương trình trên sẽ là:
Geena so sánh với Dorothy trả về 3
Geena so sánh với Shania trả về -12
Geena so sánh với Geena trả về 0
Lưu ý giá trị trả về cho mỗi so sánh. Đó là sự khác biệt giữa các giá trị ASCII của các ký tự đầu tiên khác nhau gặp trong hai chuỗi.
Hàm ‘strchr()’
Hàm ‘strchr()’ xác định sự xuất hiện của một ký tự trong một chuỗi. Cú pháp của hàm:
strchr(str, chr);
Trong đó, ‘str’ là một mảng ký tự hoặc chuỗi và ‘chr’ là một biến ký tự chứa giá trị cần tìm kiếm.
Hàm trả về một con trỏ đến vị trí của giá trị trong chuỗi hoặc NULL nếu giá trị không tồn tại.
Dưới đây là một chương trình xác định xem ký tự ‘a’ có xuất hiện trong hai tên thành phố được chỉ định:
#include <stdio.h>
#include <string.h>
int main() {
char str1[15] = "New York";
char str2[15] = "Washington";
char chr = 'a';
char *loc;
// Kiểm tra sự xuất hiện của ký tự 'a' trong tên thành phố đầu tiên
loc = strchr(str1, chr);
if (loc != NULL) {
printf("%c xuất hiện trong %s\n", chr, str1);
} else {
printf("%c không xuất hiện trong %s\n", chr, str1);
}
// Kiểm tra sự xuất hiện của ký tự 'a' trong tên thành phố thứ hai
loc = strchr(str2, chr);
if (loc != NULL) {
printf("%c xuất hiện trong %s\n", chr, str2);
} else {
printf("%c không xuất hiện trong %s\n", chr, str2);
}
return 0;
}
Đầu ra của chương trình trên là:
a does not occur in New York
a occurs in Washington
Hàm ‘strcpy()’
Trong ngôn ngữ lập trình C, không có toán tử để xử lý một chuỗi như một đối tượng duy nhất. Do đó, để gán giá trị của một chuỗi cho một chuỗi khác, bạn cần sử dụng hàm ‘strcpy()’. Cú pháp của hàm như sau:
strcpy(str1, str2);
Trong đó, ‘str1’ và ‘str2’ là các mảng ký tự đã được khai báo và khởi tạo. Hàm này sao chép giá trị của ‘str2’ vào ‘str1’ và trả về ‘str1’.
Dưới đây là một chương trình minh họa sử dụng hàm ‘strcpy()’ và hiển thị tên mới của một khách sạn:
#include <stdio.h>
#include <string.h>
int main() {
char hotelname1[15] = "Sea View";
char hotelname2[15] = "Sea Breeze";
printf("Tên cũ là %s\n", hotelname1);
strcpy(hotelname1, hotelname2);
// Thay đổi tên của khách sạn
printf("Tên mới là %s\n", hotelname1);
// Hiển thị tên mới
return 0;
}
Kết quả sau khi chạy chương trình sẽ như sau:
Tên cũ là Sea View
Tên mới là Sea Breeze
Chương trình đã thay đổi tên của khách sạn từ “Sea View” thành “Sea Breeze” bằng cách sử dụng hàm ‘strcpy()’.
Hàm ‘strlen()’
Hàm ‘strlen()’ trả về độ dài của một chuỗi. Độ dài của một chuỗi có thể hữu ích trong các chương trình truy cập từng ký tự của chuỗi trong một vòng lặp. Cú pháp của hàm như sau:
strlen(str);
Trong đó, ‘str’ là một mảng ký tự đã được khai báo và khởi tạo. Hàm này trả về độ dài của chuỗi.
Dưới đây là một chương trình đơn giản thực hiện hàm ‘strlen()’. Nó xác định độ dài của tên công ty và hiển thị tên cùng với các ký tự bổ sung.
#include <stdio.h>
#include <string.h>
int main() {
char compname[20] = "Microsoft";
int len, ctr;
len = strlen(compname); // Xác định độ dài của chuỗi
for (ctr = 0; ctr < len; ctr++) {
// Truy cập và hiển thị từng ký tự của chuỗi
printf("Ký tự %d: %c\n", ctr + 1, compname[ctr]);
}
return 0;
}
Chương trình trên sử dụng hàm ‘strlen()’ để xác định độ dài của chuỗi “Microsoft” và sau đó sử dụng một vòng lặp để truy cập và hiển thị từng ký tự của chuỗi. Kết quả sau khi chạy chương trình sẽ tương tự như sau:
Ký tự 1: M
Ký tự 2: i
Ký tự 3: c
Ký tự 4: r
Ký tự 5: o
Ký tự 6: s
Ký tự 7: o
Ký tự 8: f
Ký tự 9: t
Truyền mảng cho hàm
Trong C, khi một mảng được truyền vào một hàm dưới dạng đối số, chỉ địa chỉ của mảng được truyền vào hàm. Tên của mảng mà không có chỉ mục đề cập đến địa chỉ của mảng. Đoạn mã sau đây minh họa việc truyền địa chỉ của mảng ary vào hàm fn_ary():
void main()
{
int ary[10];
...
fn_ary(ary);
...
}
Khi một hàm nhận một mảng một chiều, các tham số hình thức (formal parameters) có thể được khai báo theo một trong những cách sau:
fn_ary (int ary (10]) /* sized array */
{
:
}
or
fn_arry (int ary []) /* unsized array */
{
:
}
Cả hai phương pháp khai báo trong trường hợp trước đó đều tạo ra kết quả tương tự và cho phép bạn truyền mảng vào hàm. Phiên bản thứ hai sử dụng một cách khai báo mảng tường minh hơn, cho biết chỉ cần một mảng kiểu int, nhưng không xác định kích thước cụ thể. Cả hai phiên bản đều cho phép bạn truyền mảng vào hàm và xử lý dữ liệu mảng một cách hiệu quả.
Dưới đây là một ví dụ minh họa về việc nhập dữ liệu vào một mảng số nguyên và sau đó tính tổng các số trong mảng thông qua hàm sum_array():
#include <stdio.h>
int sum_arr(int num_arr[], int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += num_arr[i];
}
return total;
}
int main() {
int num[5], ctr, sum;
printf("Nhập 5 số nguyên:\n");
for (ctr = 0; ctr < 5; ctr++) {
printf("Nhập số thứ %d: ", ctr + 1);
scanf("%d", &num[ctr]); // Nhập từng số vào mảng
}
sum = sum_arr(num, 5); // Gọi hàm tính tổng và truyền mảng và kích thước của mảng vào hàm
printf("\nTổng của mảng là %d\n", sum);
return 0;
}
Kết quả của chương trình trên sẽ là:
Nhập 1: 5
Nhập 2: 10
Nhập 3: 13
Nhập 4: 26
Nhập 5: 21
Tổng của mảng là 75
Truyền chuỗi cho hàm
Chuỗi, hoặc mảng ký tự, cũng có thể được truyền vào hàm trong ngôn ngữ lập trình C. Ví dụ dưới đây cho thấy một chương trình nhận chuỗi vào một mảng ký tự hai chiều, sau đó truyền mảng này vào một hàm để xác định chuỗi dài nhất trong mảng.
Ví dụ 9:
#include <stdio.h>
#include <string.h>
int longest(char lines_arr[][20]) {
int prev_len = 0;
int longest_index = 0;
for (int i = 0; i < 5; i++) {
int new_len = strlen(lines_arr[i]);
if (new_len > prev_len) {
longest_index = i;
prev_len = new_len;
}
}
return longest_index;
}
int main() {
char Lines[5][20];
int longest_str = 0;
printf("Nhập 5 chuỗi:\n");
for (int ctr = 0; ctr < 5; ctr++) {
printf("Nhập chuỗi %d: ", ctr + 1);
scanf("%s", Lines[ctr]);
}
longest_str = longest(Lines);
printf("\nChuỗi dài nhất là: %s\n", Lines[longest_str]);
return 0;
}
Một ví dụ về kết quả của chương trình được đưa ra bên dưới đây:
Enter string 1: The
Enter string 2: Sigma
Enter string 3: Protocol
Enter string 4: Robert
Enter string 5: Ludlum
The longest string is Protocol