Lập trình C: Bài 10 – Chuỗi ký tự trong c
Nội dung
Ở bài Nhập xuất trong c chúng ta đã làm quen với cách khai báo, nhập xuất chuỗi ký tự trong C một cách đơn giản. Trong bài này chúng ta sẽ nói nhiều hơn về các ví dụ, bài tập về chuỗi .
1. Tổng quan
Chuỗi được xem như là một mảng 1 chiều gồm các phần tử có kiểu char như ký tự, con số và bất cứ ký tự đặc biệt như +, -, *, /, $, #,…
Theo quy ước, một chuỗi sẽ được kết thúc bởi ký tự null (‘\0’ : kí tựrỗng).
Ví dụ: chuỗi “Infoworld” được lưu trữ như sau:
2. Một số cách khai báo, khởi tạo chuỗi
Chúng ta xét ví dụ sau:
// e.g about string - code by nguyenvanquan7826 #include <stdio.h> int main() { // khai bao chuoi co toi da 50 ky tu char name[50]; printf("Hi, What is your name? \nMy name is: "); gets(name); printf("Hi %s, welcome to C language\n", name); // khoi tao chuoi ngay khi khai bao char myLove[] = "Nguyen Thi Lap Lanh"; puts(myLove); return 0; }
Kết quả:
Hi, What is your name?
My name is: Nguyen Van Quan
Hi Nguyen Van Quan, welcome to C language
Nguyen Thi Lap Lanh
Trong chương trình trên, mình có dùng hàm puts để in chuỗi myLove ra, đây cũng là hàm để xuất chuỗi.
Như trên chúng ta có thể thấy là khai báo chuỗi sau đó nhập chuỗi hoặc vừa khai báo vừa gán giá trị cho chuỗi ngay. Tuy nhiên chúng ta không thể khai báo sau đó mới gán giá trị như sau:
char name[50]; name = "Nguyen Van Quan"; // error
Trong trường muốn khai báo sau đó mới gán giá trị, chúng ta phải dùng hàm copy chuỗi strcpy nằm trong thư viện string.h để lưu giá trị như sau:
// e.g about string - code by nguyenvanquan7826 #include <stdio.h> #include <string.h> int main() { char name[50]; strcpy(name, "Nguyen Van Quan"); puts(name); return 0; }
3. Một số ví dụ về chuỗi ký tự trong C
3.1 Ví dụ 1: Đếm số từ trong chuỗi
Hãy nhập vào một chuỗi ký tự và đếm số từ trong chuỗi. VD chuỗi “Nguyen Van Quan” có 3 từ.
Để làm bài này, chúng ta thấy mỗi từ là các ký tự liên tiếp nhau và phân tách các từ bằng các dấu cách. Do vậy bài này sẽ quy về đếm số dấu cách trong chuỗi. Nếu chuỗi có 1 từ thì không có dấu cách, chuỗi có 2 từ thì có 1 dấu cách giữa 2 từ đó. Tổng quát là có n từ thì sẽ có n-1 dấu cách.
Vấn đề tiếp theo là làm sao đếm được các dấu cách? Đơn giản, như mở đầu ta đã biết chuỗi là một mảng các ký tự, do vậy chúng ta có thể duyệt lần lượt các ký tự của chuỗi để kiếm tra ký tự nào là dấu cách. Nhưng muốn duyệt hết các ký trong chuỗi (mảng ký tự) thì phải biết số lượng ký tự có trong chuỗi (số lượng phần tử có trong mảng).
May mắn là trong thư viện string.h chúng ta có một hàm để lấy độ dài của chuỗi là hàm strlen. (str – string, len – length).
// e.g about string - code by nguyenvanquan7826 #include <stdio.h> #include <string.h> // for strlen function int main() { char s[50]; printf("Enter a string: "); gets(s); int i, count = 0; // count - bien dem so luong dau cach for (i = 0; i < strlen(s); i++ ) { if(s[i] == ' ') { count++; } } printf("Number word in string is: %d\n", count + 1 ); return 0; }
Code khá đơn giản, các bạn đọc, hiểu và chạy thử nhé.
Tuy nhiên code trên chúng ta có một số lưu ý:
- Để biểu diễn ký tự thì ta đặt trong cặp nháy đơn, chuỗi thì chúng ta đặt trong cặp nháy kép. Nên ở trên dấu cách đặt trong cặp nháy đơn và chúng ta có thể so sánh 2 ký tự bằng các phép so sánh như với 2 số, còn 2 chuỗi thì không thể so sánh được như vậy, các bạn có thể đọc thêm về cách so sánh chuỗi.
- Do chuỗi là một mảng các ký tự, nên muốn lấy ký tự thứ i trong chuỗi s thì ta truy cập như với mảng là s[i].
- Ví dụ này chỉ áp dụng khi chuỗi có độ dài lớn hơn 0 và không có dấu trắng thừa ở đầu, cuối hoặc giữa các từ.
- Như vòng lặp for ở trên, chúng ta có điều kiện
i < strlen(s)
, tuy nhiên bản chất của hàm strlen là một vòng lặp nữa để đếm số lượng ký tự của chuỗi s. Nên nếu chúng ta viết trực tiếp điều kiện như trên thì trong mỗi lần lặp, chương trình lại phải chạy lại lệnh strlen lặp để đếm số lượng ký tự của s. Điều này là thừa và làm chương trình chạy lâu hơn. Do vậy chúng ta sẽ đặt 1 biến là độ dài của chuỗi ra ngoài như sau:
int len = strlen(s); for (i = 0; i < len; i++ ) { if(s[i] == ' ') { count++; } }
3.2 Ví dụ 2: Chuẩn hóa chuỗi
Hãy nhập vào một chuỗi và xóa bỏ toàn bộ các dấu cách thừa ở đầu, cuối và giữa các từ nếu có.
Bài toán này là bài toán quan trọng cho các phần mềm, sau này khi lưu trữ, nhập liệu cần lưu ý để dữ liệu được chuẩn, không thừa thiếu gây sai sót trong quá trình xử lý và tím kiếm.
- Ký tự đầu tiên của chuỗi s là dấu cách thì s[0] là dấu cách, chúng ta xóa nó là xong.
- Các ký tự cách giữa các từ nếu thừa tức là s[i] và s[i+1] cùng là dấu cách. Chúng ta xóa 1 trong 2 là ok, vì các từ sẽ phân tách nhau bởi 1 dấu cách nên ta phải dữ lại 1 dấu cách.
- Các ký tự ở cuối chuỗi là dấu cách thì chúng ta sẽ xóa bằng cách gán ký tự cuối cùng là ký tự rỗng
'\0'
là xong. Nhớ rằng ký tự cuối cùng của mảng n phần tử làa[n-1]
, do vậy ký tự của chuỗi làs[ strlen(s) - 1 ]
.
Vấn đề tiếp theo là làm sao xóa 1 ký tự trong chuỗi? Các bạn nhìn lại ví dụ trên chúng ta có dùng hàm copy chuỗi, và để xóa 1 hoặc một số ký tự trong chuỗi chúng ta sẽ dùng hàm này nhưng sẽ dùng theo copy địa chỉ.
Để xóa từ ký tự i đến ký tự j trong chuỗi s, chúng ta dùng lệnh strcpy(&s[i], &s[j+1]);
. Bản chất là chúng ta copy địa chỉ của s[j+1]
về địa chỉ của s[i]
.
// e.g about string - code by nguyenvanquan7826 #include <stdio.h> #include <string.h> int main() { char s[50]; printf("Enter a string: "); gets(s); // delete all space at start of string while( s[0] == ' ' ) strcpy(&s[0], &s[1]); // delete all space at end of string while( s[ strlen(s)-1 ] == ' ') s[ strlen(s)-1 ] = '\0'; // delete all space between two word int i; for(i = 0; i < strlen(s); i++) { if( s[i] == ' ' && s[i+1] == ' ') { strcpy(&s[i], &s[i+1]); i--; // why??? } } printf("s=%s.\n", s); return 0; }
Ok. Các bạn chạy thử nhé. Nhớ nhập chuỗi thừa các dấu cách ở đầu, cuối, giữa để kiểm tra.
Một câu hỏi nhỏ coi như bài tập làm thêm cho các bạn là hãy nhìn dòng code i--; // why???
và nghĩ tại sao lại có dòng này? Tại sao i phải giảm đi 1?
4. Một số hàm về chuỗi và ký tự
Các hàm kiểm tra ký tự. (các hàm này trong thư viện ctype.h) Nếu đúng thì hàm cho giá trị khác 0. Nếu sai thì hàm cho giá trị bằng 0.
- Int isalpha(int c) : kiểm tra ký tự có là chữ cái không.
- Int isdigit(int c) : kiểm tra xem ký tự có là chữ số không.
- Int islower(int c): kiểm tra ký tự có là chữ thường không.
- Int isupper(int c): kiểm tra ký tự có là chữ hoa không.
- Int ispace(int c): kiểm tra ký tự có là trống không (\n, dấu cách, \t).
Các hàm sử lý xâu ký tự. (các hàm này nằm trong thư viện string.h)
- Int strlen(char *s) trả về độ dài của xâu s;
- Char *strupr(char *s) đổi chữ thường trong xâu s sang chữ hoa.
- Char *strlwr(char *s) đổi chữ hoa sang chữ thường.
- Char *strcat(char *s1, char *s2) nối xâu s2 vào xâu s1;
- Int strcmp(char *s1, char *s2) cho giá trị âm nếu xâu s1 nhở hơn xâu s2. Và cho giá tị dương nếu xâu s1 lớn hơn xâu s2. Trả về giá trị bằng 0 nếu xâu s1 bằng xâu s2.
- Int strcmpi (char *s1, char *s2) so sánh 2 xâu nhưng không phân biệt chữ thường và chữ hoa.
- Char *strcpy(char *s1, char *s2) copy xâu s2 vào xâu s1.
- Char *strncpy(char *s1, char *s2, int n) sao chép n ký tự đầu của xâu s2 sang xâu s1
- Char *strnset(char *s ,int c, int n) dùng để sao chép n lần ký tự c vào xâu s.
- Char *strstr(char *s1, char *s2) tìm sự xuất hiện của xâu s2 trong xâu s1. Nếu tìm thấy hàm cho địa chỉ của xâu con trong xâu s1. Trái lại cho NULL.
- Char *strrev(char *s) dùng đảo ngược xâu s.Nếu thành công hàm cho địa chỉ xâu đã đảo.
Bài tập
- Viết chương trình tách tên từ một chuỗi cho trước. VD tên Nguyen Thi Lap Lanh => tách được Lanh
- Viết chương trình chuẩn hóa chuỗi tên riêng. VD:
ha noi
=>Ha Noi
.- Viết hàm chuyển đổi 1 chuỗi sang chữ thường và 1 hàm chuyển đổi sang chữ HOA.
- Viết chương trình nhập vào một chuỗi ký tự rồi đếm xem trong chuỗi đó có bao nhiêu chữ “ng”.
- Viết chương trình nhập vào một chuỗi ký tự. Kiểm tra xem chuỗi đó có đối xứng không? Chuỗi đối xứng là chuỗi khi viết ngược lại vẫn được như chuỗi ban đầu. VD level
- Viết chương trình nhập vào số có 3 chữ số. Cho biết dòng chữ mô tả giá trị con số đó. Ví dụ 123 -> một trăm hai mươi ba.
Anh ơi trong cái “char hoten[50]”. 50 là số ký tự hả anh ? Em thay bằng số 2 nhưng vẫn viết nhiều hơn bình thường.
Ukm, đúng rồi, đó là giới hạn số lượng ký tự. Còn tại sao mà em gõ quá vẫn không bị thì mình cũng không rõ.
blog của a rất chi tiết và dễ hiểu. e cảm ơn
A cho e xin bài tập c với ạ!! 🙂
minh muon ghep hai mang thanh mot mang minh đã dùng hàm strcpy() nhưng chương trình báo không có thư viện tring.h thì phải làm sao?
Bạn dùng thư viện string.h ko phải tring.h
Cách xóa ký tự trong xâu. Trong C không có hàm xóa nhưng ta có thể xóa bằng cách copy địa chỉ của ký tự sau đè lên địa chỉ của ký tự trước. VD ta có xâu ht = “Nguyen Van A”, muốn xóa ký tự “uy” ta làm như sau: strcpy(&ht[2],&ht[4]);
Anh ơi anh giải thích hộ em chổ này với em ko hiểu nó copy đè lên như thế nào.
Bạn cứ dùng đi là đk rồi.
Theo mình hiểu thì cái lệnh strcpy(&ht[2],&ht[4]); sẽ copy từ địa chỉ ht[4] đến ht[n] vào địa chỉ từ ht[2] đến hết. Lệnh này nó sẽ lưu các giá trị đè lên các địa chỉ mình cho, do đó nó cũng tương đương với việc xóa đi ht[2] và ht[3] cũ. Cụ thể ở đây thì nó đè phần “en Van A” vao phan “uyen Van A”. Như vậy “uy” sẽ bị đè lên và mất luôn.
Nếu như ghi đè, một xâu “en Van A” đè lên xâu “uyen Van A” , hai xâu này độ dài ko tương đương nhau vậy sao nó ko bị dư cái đoạn của xâu “uyen Van A” nhỉ ???
Vì chúng ta đang dùng copy địa chỉ, do vậy nó láy địa chỉ mới chứ không phải dạng thay thế từng ký tự.
@quan: bạn viết thì cũng giải thích cho người ta với chứ, học lập trình phải hiểu chứ vẹt thì khác gì học văn kiểu Việt Nam.
Nó giống bạn Thăng bên trên nói đó.
a ơi có bài này e k biết làm a giúp e vs:
Quy tắc Ceasar là lùi 3 kí tự: a->x, b->, c>z,…, z->w
input:
xâu s trước khi giải mã (0<s bill is watching
a viết hộ e bài code trong C vs ạ. e cảm ơn!
Bạn duyệt từng ký tự, sau đó đặt lại từng ký tự là đk.
ad ơi ko có phần tiệp cua c hả. trên lớp thầy dậy cả vấn đề đó
Ah trong loạt bài này không có bạn nhé. Mình sẽ cố gắng bổ xung.
a giúp e với ạ…..bây h e có bài này muốn nhờ a chỉ ra hướng giải được k ạ….
Đề bai: in ra hoán vị của chữ COMPUTER, e nên bắt đầu hướng nào ạ…
Bạn xem bài viết này nhé: https://www.cachhoc.net/2013/09/03/thuat-toan-liet-ke-hoan-vi/
anh có bài giảng nào về môn trí tuệ nhân tạo không anh
Rất tiếc mình không có bạn ah.
Anh cho vài ví dụ về hàm kiểm tra kí tự và cho xuất kí tự đó được ko anh
Chưa hiểu ý của bạn lắm @@ Kiểm tra và xuất?
cho em hỏi tí là câu lệnh này ý nghĩa là gì ạ hay nó trả về giá trị gì ạ
s[strlen(s)-1];
truy cập vào ký tự cuối cùng của chuỗi s.
vậy cái i– dùng để làm gì vậy ạ?
Để giảm biến i xuống 1 đơn vị.
ở cuối anh đưa ra các ví dụ về hàm xử lý mà không có cách dùng làm thế nào anh???
i–; // why???
Sau khi xoá dấu cách ở vị trí i, thì dấu cách ở vị trí i + 1 lại đc chuyển vào vị trí i,
Nếu ta ko i–; thì sẽ bỏ qua dấu cách này, khiến ko xoá đc hết dấu cách thừa( ví dụ 3 dấu cách liền nhau thì chỉ xoá đc 1 dấu cách thôi).
Em giải thích thế đúng ko a 😀
Đúng rồi bạn.
em van chua lam duoc bai nao hihu
Bạn có thể vào trang https://chamcode.net để làm nhé, có hệ thống chấm đúng sai luôn 😉
Anh cho em hỏi làm thế nào để nhập và in một mảng gồm tên của nhiều người khác nhau ạ?
Bạn khai báo char s[n][m] với n là số lượng người, m là số ký tự tối đa của 1 tên. sau đó nhập từng s[i] một.
Ví dụ này chỉ áp dụng khi chuỗi có độ dài lớn hơn 0 và không có dấu trắng thừa ở đầu, cuối hoặc giữa các từ.
em hỏi cái ạ ở bài đếm sốt ừ trong chuỗi vd:”nguyen van quan” có 3 từ có dáu cách mà anh ghi là chỉ áp dụng khi k có dấu trắng giữa các từ
ko có đấu trắng THỪA nhé.
cho em hỏi xâu ” hoc tap ” thì ký tự khoảng trắng trước và sau “hoc tap” có được tình là ký tự không ạ
Có tính nhé.
để mà chuyển chữ cái đầu tiên của tên riêng thành viết hoa thì dùng hàm nào vậy anh ?
Tự làm nhé, ko có hàm sẵn.
anh ơi hướng giải bài 6 là gì ạ ?
Bài này tương tự bài chuyển tiền từ số sang chữ. Bạn cần tách các chữ số ra, dựa vào thứ tự vị trí của chúng để đưa ra cách đọc phù hợp.
anh cho em hỏi tại sao e dùng thư viện ,sau đó khai báo hàm strcpy nhưng máy yêu cầu nhập lại là strcpy_s .sau đó e nhập strcpy_s mà vẫn sai là sao ạ??thank a nhieu
Bạn dùng phần mềm gì để code vậy?
Khái niệm về chuỗi sai rồi, chuỗi không thể có con số ad ơi!.
Chuỗi được xem như là một mảng 1 chiều gồm các phần tử có kiểu char như ký tự, con số và bất cứ ký tự đặc biệt như +, -, *, /, $, #,…
Theo quy ước, một chuỗi sẽ được kết thúc bởi ký tự null (‘\0’ : kí tựrỗng).
“nguyenvanquan7826” có là chuỗi không bạn?
Code đếm từ trong xâu mà admin làm bên trên là ko hợp lý(trong trường hợp input nhiều dấu ‘space’)
Ở trên mình có lưu ý rồi nhé: “Ví dụ này chỉ áp dụng khi chuỗi có độ dài lớn hơn 0 và không có dấu trắng thừa ở đầu, cuối hoặc giữa các từ.”
e nghĩ là i– dùng để khống chế cho mỗi chữ trong chuỗi chỉ cách nhau duy nhất 1 dấu cách
vì nếu như ng dùng nhập nhiều hơn hai dấu cách mà ta ko dùng i– thì nó chỉ giảm có 1 dấu cách mà thôi vd :Nguyen Van Quan thì =Nguyen Van Quan. ta đâu biết ng dùng họ nhập bao nhêu dau cách có thể là I+1,i+2,i+3,…I+n cho nên ta dùng I– trong for để giải quyết vấn đề
làm sao để chuyển kí tự số sang chữ số đc nhỉ ???
lấy địa chỉ của ký tự thuần hóa về chuỗi số
fflush(stdin); để dừng lại ký tự nhập đến với các ký tự tiếp theo nha