[Tự học C++] Giới thiệu về std::string trong C++ » Cafedev.vn

1. String là gì?

Chương trình C ++ đầu tiên bạn viết có lẽ trông giống như thế này:

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: [email protected]
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

#include <iostream>
 
int main()
{
    std::cout << "Hello, world!" << std::endl;
    return 0;
}

Vậy thì “Hello, world!” chính xác là gì? “Hello, world!” là một tập hợp các ký tự liên tiếp được gọi là một string. Trong C++, chúng ta sử dụng các chuỗi để thể hiện văn bản như tên, địa chỉ, từ và câu. Các chuỗi ký tự (chẳng hạn như “Hello, world!”) được đặt giữa các dấu ngoặc kép để xác định chúng là một chuỗi(string).

Vì các chuỗi(string) thường được sử dụng trong các chương trình, hầu hết các ngôn ngữ hiện đại đều có kiểu dữ liệu chuỗi(string) tích hợp. C++ bao cũng gồm một chuỗi, không phải là một phần cốt lỗi của ngôn ngữ, mà là một phần của thư viện chuẩn.

2. std::string

Để sử dụng các chuỗi trong C++, trước tiên chúng ta cần #include header của nó là std :: string. Khi đã xong, chúng ta có thể định nghĩa các biến kiểu std :: string.

#include <string>
 
std::string myName;

Giống như các biến thông thường, bạn có thể khởi tạo hoặc gán giá trị cho chuỗi(string) như bạn mong đợi:

std::string myName{ "Alex" }; // initialize myName with string literal "Alex"
myName = "John"; // assign variable myName the string literal "John"

Lưu ý rằng các chuỗi(string) cũng có thể giữ số:

std::string myID{ "45" }; // "45" is not the same as integer 45!

Ở dạng chuỗi(string), các số được coi là văn bản, không phải là số và do đó chúng không thể được thao tác dưới dạng số. C++ sẽ không tự động chuyển đổi số chuỗi thành giá trị số nguyên hoặc dấu phẩy động.

3. Nhập và in String

Chuỗi(String) có thể được in ra như mong đợi bằng cách sử dụng std :: cout:

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: [email protected]
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/


#include <string>
#include <iostream>
 
int main()
{
    std::string myName{ "Alex" };
    std::cout << "My name is: " << myName << '\n';
 
    return 0;
}

Kết quả là:

My name is: Alex

Tuy nhiên, sử dụng chuỗi(string) với std :: cin có thể mang lại một số bất ngờ! Hãy xem xét ví dụ sau:

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: [email protected]
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

#include <string>
#include <iostream>
 
int main()
{
    std::cout << "Enter your full name: ";
    std::string name;
    std::cin >> name; // this won't work as expected since std::cin breaks on whitespace
 
    std::cout << "Enter your age: ";
    std::string age;
    std::cin >> age;
 
    std::cout << "Your name is " << name << " and your age is " << age << '\n';
 
    return 0;
}

Đây là kết quả từ một lần chạy của chương trình này:

Enter your full name: John Doe
Enter your age: Your name is John and your age is Doe

Hmmm, đó là đúng! Chuyện gì đã xảy ra? Hóa ra khi sử dụng toán tử >> để trích xuất một chuỗi từ cin, toán tử >> chỉ trả về các ký tự cho đến khoảng trắng đầu tiên mà nó gặp. Bất kỳ từ nào khác được để lại bên trong cin, chờ đợi lần trích xuất tiếp theo.

Vì vậy, khi chúng ta sử dụng toán tử >> để trích xuất một chuỗi thành tên biến, chỉ trích xuất John, bỏ lại Doe trong std :: cin, chờ đợi lần trích xuất tiếp theo. Sau đó, khi chúng ta sử dụng toán tử >> để lấy tuổi thay đổi, nó đã trích xuất Doe, thay vì chờ chúng ta nhập tuổi. Chúng ta không bao giờ có cơ hội để nhập tuổi.

4. Sử dụng std::getline() để nhập String

Để đọc toàn bộ dòng đầu vào thành một chuỗi(String), thay vào đó, bạn nên sử dụng hàm std::getline(). std::getline() có hai tham số: đầu tiên là std :: cin và thứ hai là biến chuỗi của bạn.

Ở đây, chương trình tương tự như trên sử dụng std::getline ():

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: [email protected]
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

#include <string>
#include <iostream>
 
int main()
{
    std::cout << "Enter your full name: ";
    std::string name{};
    std::getline(std::cin, name); // read a full line of text into name
 
    std::cout << "Enter your age: ";
    std::string age{};
    std::getline(std::cin, age); // read a full line of text into age
 
    std::cout << "Your name is " << name << " and your age is " << age << '\n';
 
    return 0;
}

Bây giờ chương trình của chúng ta hoạt động như mong đợi:

Enter your full name: John Doe
Enter your age: 23
Your name is John Doe and your age is 23

5. Sử dụng std::cin and std::getline()

Đọc đầu vào với cả std :: cin và std :: getline() có thể gây ra một số hành vi không mong muốn. Hãy xem xét những điều sau đây:

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: [email protected]
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

#include <string>
#include <iostream>
 
int main()
{
    std::cout << "Pick 1 or 2: ";
    int choice{};
    std::cin >> choice;
 
    std::cout << "Now enter your name: ";
    std::string name{};
    std::getline(std::cin, name);
 
    std::cout << "Hello, " << name << ", you picked " << choice << '\n';
 
    return 0;
}

Chương trình này trước tiên yêu cầu bạn nhập 1 hoặc 2 và chờ bạn thực hiện. Tất cả đều tốt. Sau đó, nó sẽ yêu cầu bạn nhập tên của bạn. Tuy nhiên, thay vào đó, nó in dòng Hello và sau đó thoát. Chuyện gì đã xảy ra?

Hóa ra, khi bạn nhập một giá trị bằng cin, cin không chỉ nắm bắt giá trị, nó còn nắm bắt được dòng mới. Vì vậy, khi chúng ta nhập 2, cin thực sự có chuỗi Chuỗi 2 \ n. Sau đó, nó trích xuất lựa chọn 2 thành biến, khiến dòng mới bị kẹt trong luồng đầu vào. Sau đó, khi std :: getline () đọc tên, nó sẽ thấy tên \ nỏ đã có trong luồng và các số liệu chúng ta phải nhập vào một chuỗi trống! Chắc chắn không phải là những gì chúng ta muốn.

Một nguyên tắc nhỏ là sau khi đọc một giá trị với std :: cin, hãy xóa dòng mới khỏi luồng. Điều này có thể được thực hiện bằng cách sử dụng như sau:

std::cin.ignore(32767, '\n'); // ignore up to 32767 characters until a \n is removed

Nếu chúng ta chèn dòng này trực tiếp sau khi đọc 1 chuỗi, dòng mới không liên quan sẽ bị xóa khỏi luồng và chương trình sẽ hoạt động như mong đợi!

int main()
{
	std::cout << "Pick 1 or 2: ";
	int choice{};
	std::cin >> choice;
 
	std::cin.ignore(32767, '\n'); // ignore up to 32767 characters until a \n is removed
 
	std::cout << "Now enter your name: ";
	std::string name;
	std::getline(std::cin, name);
 
	std::cout << "Hello, " << name << ", you picked " << choice << '\n';
 
	return 0;
}

Quy tắc: Nếu đọc các giá trị với std :: cin, bạn nên loại bỏ dòng mới mà không sử dụng bằng cách dùng std :: cin.ignore ().

6. Số ảo diệu 32767 là gì?

Điều đó cho biết std :: cin.ignore () có bao nhiêu phần tử cần bỏ qua. Chúng ta đã chọn con số đó bởi vì nó có giá trị chứa một ký tự lớn nhất được đảm bảo phù hợp với số nguyên (2 byte) trên tất cả các nền tảng.

Về mặt kỹ thuật, cách chính xác để bỏ qua số lượng đầu vào không giới hạn như sau:

#include <limits>
 
...
 
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore unlimited characters until a \n is removed

Nhưng điều này đòi hỏi phải nhớ (hoặc tìm kiếm) dòng code khủng khiếp đó, cũng như ghi nhớ header cần include. vì vậy với mục đích thực tế, 32767 cũng hoạt động tốt và có lợi ích là thứ bạn thực sự có thể giúp bạn dễ nhớ trong đầu.

Trong suốt các hướng dẫn này, chúng tôi sử dụng 32767 vì lý do này. Tuy nhiên, đó là sự lựa chọn của bạn về việc bạn muốn thực hiện nó theo cách tối nghĩa, phức tạp và chính xác, hay cách dễ dàng, thực tế, nhưng không lý tưởng.

7. Cộng strings

Bạn có thể sử dụng toán tử + để nối hai chuỗi với nhau (trả về một chuỗi mới) hoặc toán tử + = để nối một chuỗi vào cuối chuỗi hiện có).

Dưới đây, một ví dụ về cả hai, cũng cho thấy điều gì xảy ra nếu bạn cố gắng sử dụng toán tử + để thêm hai chuỗi số với nhau:

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: [email protected]
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

#include <string>
#include <iostream>
 
int main()
{
    std::string a{ "45" };
    std::string b{ "11" };
 
    std::cout << a + b << '\n'; // a and b will be concatenated
    a += " volts";
    std::cout << a;
 
    return 0;
}

This prints:

4511
45 volts

Lưu ý rằng toán tử + nối chuỗi các chuỗi 45 45 và 1111 thành chuỗi 4511. Nó không thêm chúng dưới dạng số.

8. Độ dài của chuổi(String length)

Nếu chúng ta muốn biết một chuỗi dài bao nhiêu, chúng ta có thể hỏi chuỗi về độ dài của nó. Cú pháp để thực hiện việc này khác với bạn đã thấy trước đây, nhưng khá đơn giản:

#include <string>
#include <iostream>
 
int main()
{
    std::string myName{ "Alex" };
    std::cout << myName << " has " << myName.length() << " characters\n";
    return 0;
}

Kết quả:

Alex has 4 characters

Lưu ý rằng thay vì yêu cầu độ dài chuỗi là độ dài (myName), chúng ta nói myName.length ().

Hàm length không phải là một hàm độc lập bình thường như chúng ta đã sử dụng cho đến thời điểm này – nó là một loại hàm đặc biệt thuộc std ::string được gọi là hàm thành viên.

9. Phần kết luận

std :: string rất phức tạp, tận dụng nhiều tính năng ngôn ngữ mà chúng ta đã đề cập đến. Nó cũng có rất nhiều khả năng khác mà chúng ta đã tìm hiểu ở đây. May mắn thay, bạn không cần phải hiểu những phức tạp này để sử dụng std :: string cho các tác vụ đơn giản, như đầu vào và đầu ra của chuỗi cơ bản. Chúng tôi khuyến khích bạn bắt đầu thử nghiệm các chuỗi ngay bây giờ và bao gồm các chức năng nó.

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!