Tác giả phạm hồng thái bài giảng ngôn ngữ LẬp trình c/C++



tải về 1.98 Mb.
trang17/55
Chuyển đổi dữ liệu07.07.2016
Kích1.98 Mb.
1   ...   13   14   15   16   17   18   19   20   ...   55

Xâu kí tự


Một xâu kí tự là một dãy bất kỳ các kí tự (kể cả dấu cách) do vậy nó có thể được lưu bằng mảng kí tự. Tuy nhiên để máy có thể nhận biết được mảng kí tự này là một xâu, cần thiết phải có kí tự kết thúc xâu, theo qui ước là kí tự có mã 0 (tức '\0') tại vị trí nào đó trong mảng. Khi đó xâu là dãy kí tự bắt đầu từ phần tử đầu tiên (thứ 0) đến kí tự kết thúc xâu đầu tiên (không kể các kí tự còn lại trong mảng).

0

1

2

3

4

5

6

7

H

E

L

L

O

\0







H

E

L

\0

L

O

\0




\0

H

E

L

L

O

\0



Hình vẽ trên minh hoạ 3 xâu, mỗi xâu được chứa trong mảng kí tự có độ dài tối đa là 8. Nội dung xâu thứ nhất là "Hello" có độ dài thực tế là 5 kí tự, chiếm 6 ô trong mảng (thêm ô chứa kí tự kết thúc '\0'). Xâu thứ hai có nội dung "Hel" với độ dài 3 (chiếm 4 ô) và xâu cuối cùng biểu thị một xâu rỗng (chiếm 1 ô). Chú ý mảng kí tự được khai báo với độ dài 8 tuy nhiên các xâu có thể chỉ chiếm một số kí tự nào đó trong mảng này và tối đa là 7 kí tự.


Khai báo


char [độ dài] ; // không khởi tạo

char [độ dài] = xâu kí tự ; // có khởi tạo

char [] = xâu kí tự ; // có khởi tạo

Độ dài mảng là số kí tự tối đa có thể có trong xâu. Độ dài thực sự của xâu chỉ tính từ đầu mảng đến dấu kết thúc xâu (không kể dấu kết thúc xâu ‘\0’).

Do một xâu phải có dấu kết thúc xâu nên trong khai báo độ dài của mảng cần phải khai báo thừa ra một phần tử. Thực chất độ dài tối đa của xâu = độ dài mảng - 1. Ví dụ nếu muốn khai báo mảng s chứa được xâu có độ dài tối đa 80 kí tự, ta cần phải khai báo char s[81].

Cách khai báo thứ hai có kèm theo khởi tạo xâu, đó là dãy kí tự đặt giữa cặp dấu nháy kép. Ví dụ:

char hoten[26] ; // xâu họ tên chứa tối đa 25 kí tự

char monhoc[31] = "NNLT C++" ;

xâu môn học chứa tối đa 30 kí tự, được khởi tạo với nội dung "NNLT C++" với độ dài thực sự là 10 kí tự (chiếm 11 ô đầu tiên trong mảng monhoc[31]).

Cách khai báo thứ 3 tự chương trình sẽ quyết định độ dài của mảng bởi xâu khởi tạo (bằng độ dài xâu + 1). Ví dụ:

char thang[] = "Mười hai" ; // độ dài mảng = 9

Cách sử dụng


Tương tự như các mảng dữ liệu khác, xâu kí tự có những đặc trưng như mảng, tuy nhiên chúng cũng có những điểm khác biệt. Dưới đây là các điểm giống và khác nhau đó.

Truy cập một kí tự trong xâu: cú pháp giống như mảng. Ví dụ:

char s[50] = "I\'m a student" ; // chú ý kí tự ' phải được viết là \'

cout << s[0] ; // in kí tự đầu tiên, tức kí tự 'I'

s[1] = 'a' ; // đặt lại kí tự thứ 2 là 'a'

Không được thực hiện các phép toán trực tiếp trên xâu như:

char s[20] = "Hello", t[20] ; // khai báo hai xâu s và t

t = "Hello" ; // sai, chỉ gán được khi khai báo

t = s ; // sai, không gán được toàn bộ mảng

if (s < t) … // sai, không so sánh được hai mảng

Toán tử nhập dữ liệu >> vẫn dùng được nhưng có nhiều hạn chế. Ví dụ



char s[60] ;

cin >> s ;

cout << s ;

nếu xâu nhập vào là "Tin học hoá" chẳng hạn thì toán tử >> chỉ nhập "Tin" cho s (bỏ tất cả các kí tự đứng sau dấu trắng), vì vậy khi in ra trên màn hình chỉ có từ "Tin".

Vì các phép toán không dùng được trực tiếp trên xâu nên các chương trình dịch đã viết sẵn các hàm thư viện được khai báo trong file nguyên mẫu string.h. Các hàm này giải quyết được hầu hết các công việc cần thao tác trên xâu. Nó cung cấp cho NSD phương tiện để thao tác trên xâu như gán, so sánh, sao chép, tính độ dài xâu, nhập, in, … Để sử dụng được các hàm này đầu chương trình cần có khai báo string.h. Phần lớn các hàm này sẽ được giới thiệu trong phần tiếp sau.

Phương thức nhập xâu (#include )


Do toán tử nhập >> có hạn chế đối với xâu kí tự nên C++ đưa ra hàm riêng (còn gọi là phương thức) cin.getline(s,n) để nhập xâu kí tự. Hàm có 2 đối với s là xâu cần nhập nội dung và n-1 là số kí tự tối đa của xâu. Giống phương thức nhập kí tự cin.get(c), khi gặp hàm cin.getline(s,n) chương trình sẽ nhìn vào bộ đệm bàn phím lấy ra n-1 kí tự (nếu đủ hoặc lấy tất cả kí tự còn lại, trừ kí tự enter) và gán cho s. Nếu tại thời điểm đó bộ đệm đang rỗng, chương trình sẽ tạm dừng chờ NSD nhập dữ liệu (dãy kí tự) vào từ bàn phím. NSD có thể nhập vào dãy với độ dài bất kỳ cho đến khi nhấn Enter, chương trình sẽ lấy ra n-1 kí tự đầu tiên gán cho s, phần còn lại vẫn được lưu trong bộ đệm (kể cả kí tự Enter) để dùng cho lần nhập sau. Hiển nhiên, sau khi gán các kí tự cho s, chương trình sẽ tự động đặt kí tự kết thúc xâu vào ô tiếp theo của xâu s.

: Xét đoạn lệnh sau

char s[10] ;

cin.getline(s, 10) ;

cout << s << endl ;

cin.getline(s, 10) ;

cout << s << endl ;

giả sử ta nhập vào bàn phím dòng kí tự: 1234567890abcd ¿. Khi đó lệnh cin.getline(s,10) đầu tiên sẽ gán xâu "123456789" (9 kí tự) cho s, phần còn lại vẫn lưu trong bộ đệm bàn phím. Tiếp theo s được in ra màn hình. Đến lệnh cin.getline(s,10) thứ hai NSD không phải nhập thêm dữ liệu, chương trình tự động lấy nốt số dữ liệu còn lại (vì chưa đủ 9 kí tự) "0abcd" để gán cho s. Sau đó in ra màn hình. Như vậy trên màn hình sẽ xuất hiện hai dòng:

123456789

0abcd


: Nhập một ngày tháng dạng Mỹ (mm/dd/yy), đổi sang ngày tháng dạng Việt Nam rồi in ra màn hình.

#include

main()

{

char US[9], VN[9] = " / / " ; // khởi tạo trước hai dấu /



cin.getline(US, 9) ; // nhập ngày tháng, ví dụ "05/01/99"

VN[0] = US[3]; VN[1] = US[4] ; // ngày

VN[3] = US[0]; VN[4] = US[1] ; // tháng

VN[6] = US[6]; VN[7] = US[7] ; // năm

cout << VN << endl ;

}

Một số hàm xử lí xâu (#include )


strcpy(s, t) ;

Gán nội dung của xâu t cho xâu s (thay cho phép gán = không được dùng). Hàm sẽ sao chép toàn bộ nội dung của xâu t (kể cả kí tự kết thúc xâu) vào cho xâu s. Để sử dụng hàm này cần đảm bảo độ dài của mảng s ít nhất cũng bằng độ dài của mảng t. Trong trường hợp ngược lại kí tự kết thúc xâu sẽ không được ghi vào s và điều này có thể gây treo máy khi chạy chương trình.

Ví dụ:

char s[10], t[10] ;



t = "Face" ; // không được dùng

s = t ; // không được dùng

strcpy(t, "Face") ; // được, gán "Face" cho t

strcpy(s, t) ; // được, sao chép t sang s

cout << s << " to " << t ; // in ra: Face to Face

strncpy(s, t, n) ;

Sao chép n kí tự của t vào s. Hàm này chỉ làm nhiệm vụ sao chép, không tự động gắn kí tự kết thúc xâu cho s. Do vậy NSD phải thêm câu lệnh đặt kí tự '\0' vào cuối xâu s sau khi sao chép xong.

Ví dụ:

char s[10], t[10] = "Steven";



strncpy(s, t, 5) ; // copy 5 kí tự "Steve" vào s

s[5] = '\0' ; // đặt dấu kết thúc xâu

// in câu: Steve is young brother of Steven

cout << s << " is young brother of " << t ;

Một sử dụng có ích của hàm này là copy một xâu con bất kỳ của t và đặt vào s. Ví dụ cần copy xâu con dài 2 kí tự bắt đầu từ kí tự thứ 3 của xâu t và đặt vào s, ta viết strncpy(s, t+3, 2). Ngoài ra xâu con được copy có thể được đặt vào vị trí bất kỳ của s (không nhất thiết phải từ đầu xâu s) chẳng hạn đặt vào từ vị trí thứ 5, ta viết: strncpy(s+5, t+3, 2). Câu lệnh này có nghĩa: lấy 2 kí tự thứ 3 và thứ 4 của xâu t đặt vào 2 ô thứ 5 và thứ 6 của xâu s. Trên cơ sở này chúng ta có thể viết các đoạn chương trình ngắn để thay thế một đoạn con bất kỳ nào đó trong s bởi một đoạn con bất kỳ (có độ dài tương đương) trong t. Ví dụ các dòng lệnh chuyển đổi ngày tháng trong ví dụ trước có thể viết lại bằng cách dùng hàm strncpy như sau:

strncpy(VN+0, US+3, 2) ; // ngày

strncpy(VN+3, US+0, 2) ; // tháng

strncpy(VN+6, US+6, 2); // năm



strcat(s, t);

Nối một bản sao của t vào sau s (thay cho phép +). Hiển nhiên hàm sẽ loại bỏ kí tự kết thúc xâu s trước khi nối thêm t. Việc nối sẽ đảm bảo lấy cả kí tự kết thúc của xâu t vào cho s (nếu s đủ chỗ) vì vậy NSD không cần thêm kí tự này vào cuối xâu. Tuy nhiên, hàm không kiểm tra xem liệu độ dài của s có đủ chỗ để nối thêm nội dung, việc kiểm tra này phải do NSD đảm nhiệm. Ví dụ:

char a[100] = "Mẫn", b[4] = "tôi";

strcat(a, “ và ”);

strcat(a, b);

cout << a // Mẫn và tôi


char s[100] , t[100] = "Steve" ;

strncpy(s, t, 3); s[3] = '\0'; // s = "Ste"

strcat(s, "p"); // s = "Step"

cout << t << " goes "<< s << " by " <

strncat(s, t, n);

Nối bản sao n kí tự đầu tiên của xâu t vào sau xâu s. Hàm tự động đặt thêm dấu kết thúc xâu vào s sau khi nối xong (tương phản với strncpy()). Cũng giống strcat hàm đòi hỏi độ dài của s phải đủ chứa kết quả. Tương tự, có thể sử dụng cách viết strncat(s, t+k, n) để nối n kí tự từ vị trí thứ k của xâu t cho s.

Ví dụ:

char s[20] = "Nhà " ;



char t[] = "vua chúa"

strncat(s, t, 3) ; // s = "Nhà vua"

hoặc:

strncat(s, t+4, 4) ; // s = "Nhà chúa"



strcmp(s, t);

Hàm so sánh 2 xâu s và t (thay cho các phép toán so sánh). Giá trị trả lại là hiệu 2 kí tự khác nhau đầu tiên của s và t. Từ đó, nếu s1 < s2 thì hàm trả lại giá trị âm, bằng 0 nếu s1==s2, và dương nếu s1 > s2. Trong trường hợp chỉ quan tâm đến so sánh bằng, nếu hàm trả lại giá trị 0 là 2 xâu bằng nhau và nếu giá trị trả lại khác 0 là 2 xâu khác nhau.

Ví dụ:

if (strcmp(s,t)) cout << "s khác t"; else cout << "s bằng t" ;



strncmp(s, t) ;

Giống hàm strcmp(s, t) nhưng chỉ so sánh tối đa n kí tự đầu tiên của hai xâu.

Ví dụ:

char s[] = "Hà Nội" , t[] = "Hà nội" ;



cout << strcmp(s,t) ; // -32 (vì 'N' = 78, 'n' = 110)

cout << strncmp(s, t, 3) ; // 0 (vì 3 kí tự đầu của s và t là như nhau)



strcmpi(s, t) ;

Như strcmp(s, t) nhưng không phân biệt chữ hoa, thường.

Ví dụ:

char s[] = "Hà Nội" , t[] = "hà nội" ;



cout << strcmpi(s, t) ; // 0 (vì s = t)

strupr(s);

Hàm đổi xâu s thành in hoa, và cũng trả lại xâu in hoa đó.

Ví dụ:

char s[10] = "Ha noi" ;



cout << strupr(s) ; // HA NOI

cout << s ; // HA NOI (s cũng thành in hoa)



strlwr(s);

Hàm đổi xâu s thành in thuờng, kết quả trả lại là xâu s.

Ví dụ:

char s[10] = "Ha Noi" ;



cout << strlwr(s) ; // ha noi

cout << s ; // ha noi (s cũng thành in thường)



strlen(s) ;

Hàm trả giá trị là độ dài của xâu s.

Ví dụ:

char s[10] = "Ha Noi" ;



cout << strlen(s) ; // 5
Sau đây là một số ví dụ sử dụng tổng hợp các hàm trên.

: Thống kê số chữ 'a' xuất hiện trong xâu s.

main()

{

const int MAX = 100;



char s[MAX+1];

int sokitu = 0;

cin.getline(s, MAX+1);

for (int i=0; i < strlen(s); i++) if (s[i] = 'a ') sokitu++;

cout << "Số kí tự = " << sokitu << endl ;

}

: Tính độ dài xâu bằng cách đếm từng kí tự (tương đương với hàm strlen())



main()

{

char s[100]; // độ dài tối đa là 99 kí tự



cin.getline(s, 100); // nhập xâu s

for (int i=0 ; s[i] != '\0' ; i++) ; // chạy từ đầu đến cuối xâu

cout << "Độ dài xâu = " << i ;

}

: Sao chép xâu s sang xâu t (tương đương với hàm strcpy(t,s))



void main()

{

char s[100], t[100];



cin.getline(s, 100); // nhập xâu s

int i=0;

while ((t[i] = s[i]) != '\0') i++; // copy cả dấu kết thúc xâu '\0'

cout << t << endl ;

}

: Cắt dấu cách 2 đầu của xâu s. Chương trình sử dụng biến i chạy từ đầu xâu đến vị trí đầu tiên có kí tự khác dấu trắng. Từ vị trí này sao chép từng kí tự còn lại của xâu về đầu xâu bằng cách sử dụng thêm biến j để làm chỉ số cho xâu mới. Kết thúc sao chép j sẽ ở vị trí cuối xâu (mới). Cho j chạy ngược về đầu xâu cho đến khi gặp kí tự đầu tiên khác dấu trắng. Đặt dấu kết thúc xâu tại đây.



main()

{

char s[100];



cin.getline(s, 100); // nhập xâu s

int i, j ;

i = j = 0;

while (s[i++] == ' '); i-- ; // bỏ qua các dấu cách đầu tiên

while (s[i] != '\0') s[j++] = s[i++] ; // sao chép phần còn lại vào s

while (s[--j] == ' ') ; // bỏ qua các dấu cách cuối

s[j+1] = '\0' ; // đặt dấu kết thúc xâu

cout << s ;

}
: Chạy dòng chữ quảng cáo vòng tròn từ phải sang trái giữa màn hình.

Giả sử hiện 30 kí tự của xâu quảng cáo. Ta sử dụng vòng lặp. Cắt 30 kí tự đầu tiên của xâu cho vào biến hien, hiện biến này ra màn hình. Bước lặp tiếp theo cắt ra 30 kí tự của xâu nhưng dịch sang phải 1 kí tự cho vào biến hien và hiện ra màn hình. Quá trình tiếp tục, mỗi bước lặp ta dịch chuyển nội dung cần hiện ra màn hình 1 kí tự, do hiệu ứng của mắt ta thấy dòng chữ sẽ chạy từ biên phải về biên trái của màn hình. Để quá trình chạy theo vòng tròn (khi hiện đến kí tự cuối của xâu sẽ hiện quay lại từ kí tự đầu của xâu) chương trình sử dụng biến i đánh dấu điểm đầu của xâu con cần cắt cho vào hien, khi i bằng độ dài của xâu chương trình đặt lại i = 0 (cắt lại từ đầu xâu). Ngoài ra, để phần cuối xâu nối với phần đầu (tạo thành vòng tròn) ngay từ đầu chương trình, xâu quảng cáo sẽ được nối thành gấp đôi.

Vòng lặp tiếp tục đến khi nào NSD ấn phím bất kỳ (chương trình nhận biết điều này nhờ vào hàm kbhit() thuộc file nguyên mẫu conio.h) thì dừng. Để dòng chữ chạy không quá nhanh chương trình sử dụng hàm trễ delay(n) (thuộc dos.h, tạm dừng trong n phần nghìn giây) với n được điều chỉnh thích hợp theo tốc độ của máy. Hàm gotoxy(x, y) (thuộc conio.h) trong chương trình đặt con trỏ màn hình tại vị trí cột x dòng y để đảm bảo dòng chữ luôn luôn hiện ra tại đúng một vị trí trên màn hình.

#include

#include

#include

main()

{

char qc[100] = "Quảng cáo miễn phí: Không có tiền thì không có kem. ";



int dd = strlen(qc);

char tam[100] ; strcpy(tam, qc) ;

strcat(qc, tam) ; // nhân đôi dòng quảng cáo

clrscr(); // xoá màn hình

char hien[31] ; // chứa xâu dài 30 kí tự để hiện

i = 0;


while (!kbhit()) { // trong khi chưa ấn phím bất kỳ

strncpy(hien, s+i, 30);

hien[30] = '\0'; // copy 30 kí tự từ qc[i] sang hien

gotoxy(20,10); cout << hien ; // in hien tại dòng 10 cot 20

delay(100); // tạm dừng 1/10 giây

i++; if (i==dd) i = 0; // tăng i

}

}

: Nhập mật khẩu (không quá 10 kí tự). In ra "đúng" nếu là "HaNoi2000", "sai" nếu ngược lại. Chương trình cho phép nhập tối đa 3 lần. Nhập riêng rẽ từng kí tự (bằng hàm getch()) cho mật khẩu. Hàm getch() không hiện kí tự NSD gõ vào, thay vào đó chương trình chỉ hiện kí tự 'X' để che giấu mật khẩu. Sau khi NSD đã gõ xong (9 kí tự) hoặc đã Enter, chương trình so sánh xâu vừa nhập với "HaNoi2000", nếu đúng chương trình tiếp tuc, nếu sai tăng số lần nhập (cho phép không quá 3 lần).



#include

#include

#include

void main()

{

char pw[11]; int solan = 0; // Cho phep nhap 3 lan



do {

clrscr(); gotoxy(30,12) ;

int i = 0;

while ((pw[i]=getch()) != 13 && ++i < 10) cout << 'X' ; // 13 = Enter

pw[i] = '\0' ;

cout << endl ;

if (!strcmp(pw, "HaNoi2000")) { cout << "Mời vào" ; break; }

else { cout << "Sai mật khẩu. Nhập lại") ; solan++ ; }

} while (solan < 3);

}

1   ...   13   14   15   16   17   18   19   20   ...   55


Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2016
được sử dụng cho việc quản lý

    Quê hương