Đến thời điểm này, các kiểu dữ liệu cơ bản mà chúng ta đã tìm hiểu để sử dụng cho việc giữ các số (số nguyên và dấu phẩy động) hoặc giá trị đúng / sai (booleans). Nhưng nếu chúng ta muốn lưu trữ chữ thì sao? Kiểu dữ liệu char được thiết kế cho mục đích như vậy.
Kiểu dữ liệu char là một kiểu tích phân, có nghĩa là giá trị cơ bản được lưu trữ dưới dạng một số nguyên và nó được đảm bảo có kích thước 1 byte. Tuy nhiên, tương tự như cách giá trị boolean được hiểu là true hay false, giá trị char được hiểu là ký tự ASCII.
ASCII là viết tắt của Code tiêu chuẩn của Mỹ để trao đổi thông tin và nó định nghĩa một cách cụ thể để biểu thị các ký tự tiếng Anh (cộng với một vài ký hiệu khác) là các số từ 0 đến 127 (được gọi là code ASCII). Ví dụ, code ASCII 97 được hiểu là ký tự ‘a.
Ký tự char luôn được đặt giữa các dấu nhấy đơn.
Ở đây, một bảng đầy đủ các ký tự ASCII:
Code | Symbol | Code | Symbol | Code | Symbol | Code | Symbol |
---|---|---|---|---|---|---|---|
0 | NUL (null) | 32 | (space) | 64 | @ | 96 | ` |
1 | SOH (start of header) | 33 | ! | 65 | A | 97 | a |
2 | STX (start of text) | 34 | ” | 66 | B | 98 | b |
3 | ETX (end of text) | 35 | # | 67 | C | 99 | c |
4 | EOT (end of transmission) | 36 | $ | 68 | D | 100 | d |
5 | ENQ (enquiry) | 37 | % | 69 | E | 101 | e |
6 | ACK (acknowledge) | 38 | & | 70 | F | 102 | f |
7 | BEL (bell) | 39 | ’ | 71 | G | 103 | g |
8 | BS (backspace) | 40 | ( | 72 | H | 104 | h |
9 | HT (horizontal tab) | 41 | ) | 73 | I | 105 | i |
10 | LF (line feed/new line) | 42 | * | 74 | J | 106 | j |
11 | VT (vertical tab) | 43 | + | 75 | K | 107 | k |
12 | FF (form feed / new page) | 44 | , | 76 | L | 108 | l |
13 | CR (carriage return) | 45 | – | 77 | M | 109 | m |
14 | SO (shift out) | 46 | . | 78 | N | 110 | n |
15 | SI (shift in) | 47 | / | 79 | O | 111 | o |
16 | DLE (data link escape) | 48 | 0 | 80 | P | 112 | p |
17 | DC1 (data control 1) | 49 | 1 | 81 | Q | 113 | q |
18 | DC2 (data control 2) | 50 | 2 | 82 | R | 114 | r |
19 | DC3 (data control 3) | 51 | 3 | 83 | S | 115 | s |
20 | DC4 (data control 4) | 52 | 4 | 84 | T | 116 | t |
21 | NAK (negative acknowledge) | 53 | 5 | 85 | U | 117 | u |
22 | SYN (synchronous idle) | 54 | 6 | 86 | V | 118 | v |
23 | ETB (end of transmission block) | 55 | 7 | 87 | W | 119 | w |
24 | CAN (cancel) | 56 | 8 | 88 | X | 120 | x |
25 | EM (end of medium) | 57 | 9 | 89 | Y | 121 | y |
26 | SUB (substitute) | 58 | : | 90 | Z | 122 | z |
27 | ESC (escape) | 59 | ; | 91 | [ | 123 | { |
28 | FS (file separator) | 60 | < | 92 | \ | 124 | | |
29 | GS (group separator) | 61 | = | 93 | ] | 125 | } |
30 | RS (record separator) | 62 | > | 94 | ^ | 126 | ~ |
31 | US (unit separator) | 63 | ? | 95 | _ | 127 | DEL (delete) |
Code 0-31 được gọi là ký tự không thể in được và chúng chủ yếu được sử dụng để thực hiện định dạng và điều khiển máy in. Hầu hết trong số này đã lỗi thời.
Code 32-127 được gọi là các ký tự có thể in được và chúng đại diện cho các chữ cái, ký tự số và dấu chấm câu mà hầu hết các máy tính sử dụng để hiển thị văn bản tiếng Anh cơ bản.
Nội dung chính
1. Khởi tạo ký tự
Bạn có thể khởi tạo các biến char bằng cách sử dụng các ký tự:
char ch2{ 'a' }; // initialize with code point for 'a' (stored as integer 97) (preferred)
Bạn cũng có thể khởi tạo ký tự bằng số nguyên, nhưng điều này nên tránh nếu có thể
char ch1{ 97 }; // initialize with integer 97 ('a') (not preferred)
Cẩn thận không trộn lẫn số ký tự với số nguyên. Hai khởi tạo sau không giống nhau:
char ch{5}; // initialize with integer 5 (stored as integer 5)
char ch{'5'}; // initialize with code point for '5' (stored as integer 53)
Số dưới dạng ký tự sẽ được sử dụng khi chúng ta muốn biểu diễn số dưới dạng văn bản, thay vì số để áp dụng các phép toán.
in ký tự
Khi sử dụng std :: cout để in char, std :: cout xuất ra biến char dưới dạng ký tự ASCII:
/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* 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()
{
char ch1{ 'a' }; // (preferred)
std::cout << ch1; // cout prints a character
char ch2{ 98 }; // code point for 'b' (not preferred)
std::cout << ch2; // cout prints a character
return 0;
}
Điều này tạo ra kết quả:
ab
Chúng ta cũng có thể xuất chữ char trực tiếp:
cout << 'c';
Điều này tạo ra kết quả:
c
Số nguyên chiều rộng cố định int8_t thường được xử lý giống như một char trong C ++, do đó, nó thường sẽ in dưới dạng char thay vì số nguyên.
2. In ký tự dưới dạng số nguyên thông qua static_cast
Nếu chúng ta muốn xuất một char dưới dạng một số thay vì một ký tự, chúng ta phải nói với std :: cout để in char như thể nó là một số nguyên. Một cách để làm điều này là gán char cho một số nguyên và in số nguyên:
#include <iostream>
int main()
{
char ch{97};
int i(ch); // assign the value of ch to an integer
std::cout << i; // print the integer value
return 0;
}
Tuy nhiên, điều này là khó khăn. Một cách tốt hơn là sử dụng một kiểu cast. Một cast sẽ tạo ra một giá trị cho một kiểu nào đó từ một giá trị của kiểu khác. Để chuyển đổi giữa các kiểu dữ liệu cơ bản (ví dụ: từ char thành int hoặc ngược lại), chúng ta sử dụng static_cast.
Cú pháp cho cast như sau:
static_cast<new_type>(expression)
static_cast lấy giá trị từ một biểu thức làm đầu vào và chuyển đổi nó thành bất kỳ loại cơ bản nào new_type đại diện (ví dụ: int, bool, char, double).
Ở đây, sử dụng static_cast để tạo giá trị nguyên từ giá trị char của chúng ta:
#include <iostream>
int main()
{
char ch{ 'a' };
std::cout << ch << '\n';
std::cout << static_cast<int>(ch) << '\n';
std::cout << ch << '\n';
return 0;
}
Kết quả này trong:
a
97
a
Điều quan trọng cần lưu ý là tham số tới static_cast đánh giá là một biểu thức. Khi chúng ta truyền vào một biến, biến đó được ước tính để tạo ra giá trị của nó, sau đó được chuyển đổi sang kiểu mới. Biến không bị ảnh hưởng bằng cách chuyển giá trị của nó sang kiểu mới. Trong trường hợp trên, biến ch vẫn là char và vẫn giữ nguyên giá trị.
Cũng lưu ý rằng việc static_cast không thực hiện bất kỳ kiểm tra phạm vi(độ lớn), vì vậy nếu bạn truyền một số nguyên lớn vào một char, bạn sẽ tràn kiểu char của mình.
Chúng ta sẽ nói nhiều hơn về các static_cast và các kiểu khác nhau trong một bài học trong tương lai.
3. Nhập ký tự
Chương trình sau đây yêu cầu người dùng nhập một ký tự, sau đó in ra cả ký tự và code ASCII của nó:
/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* 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 << "Input a keyboard character: ";
char ch{};
std::cin >> ch;
std::cout << ch << " has ASCII code " << static_cast<int>(ch) << '\n';
return 0;
}
Đây là đầu ra từ một lần chạy:
Input a keyboard character: q
q has ASCII code 113
Lưu ý rằng std :: cin sẽ cho phép bạn nhập nhiều ký tự. Tuy nhiên, biến ch chỉ có thể chứa 1 ký tự. Do đó, chỉ có ký tự đầu vào đầu tiên được trích xuất thành biến ch. Phần còn lại của đầu vào người dùng được để lại trong bộ đệm đầu vào mà std :: cin sử dụng và có thể được trích xuất bằng các lệnh gọi tiếp theo đến std :: cin.
Bạn có thể thấy hành vi này trong ví dụ sau:
/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* 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 << "Input a keyboard character: "; // assume the user enters "abcd" (without quotes)
char ch{};
std::cin >> ch; // ch = 'a', "bcd" is left queued.
std::cout << ch << " has ASCII code " << static_cast<int>(ch) << '\n';
// Note: The following cin doesn't ask the user for input, it grabs queued input!
std::cin >> ch; // ch = 'b', "cd" is left queued.
std::cout << ch << " has ASCII code " << static_cast<int>(ch) << '\n';
return 0;
}
Input a keyboard character: abcd
a has ASCII code 97
b has ASCII code 98
4. Kích thước Char, phạm vi và dấu hiệu mặc định
Char được định nghĩa bởi C ++ để luôn có kích thước 1 byte. Theo mặc định, một char có thể được có dấu hoặc không dấu (mặc dù nó thường được có dấu). Nếu bạn sử dụng ký tự để giữ các ký tự ASCII, bạn không cần chỉ định một ký hiệu (vì cả hai ký tự có ký hiệu và không dấu có thể giữ các giá trị trong khoảng từ 0 đến 127).
Nếu bạn sử dụng char để giữ các số nguyên nhỏ (điều bạn không nên làm trừ khi bạn tối ưu hóa rõ ràng cho không gian), bạn phải luôn chỉ định xem nó có dấu hay không dấu. Một char có dấunhân vật có thể giữ một số trong khoảng từ -128 đến 127. Một char không dấu có thể giữ một số trong khoảng từ 0 đến 255.
5. Trình tự thoát khỏi một dòng nào đó
Có một số ký tự trong C ++ có ý nghĩa đặc biệt. Những ký tự này được gọi là trình tự thoát. Một chuỗi thoát bắt đầu bằng một ký tự ‘\ (dấu gạch chéo ngược) và sau đó là một chữ cái hoặc số sau đây.
Bạn đã thấy trình tự thoát phổ biến nhất: ‘\ n, có thể được sử dụng để nhúng một dòng mới trong một chuỗi văn bản:
#include <iostream>
int main()
{
std::cout << "First line\nSecond line\n";
return 0;
}
Kết quả này:
First line
Second line
Một chuỗi thoát thường được sử dụng khác là ‘\ t, trong đó nhúng một tab ngang:
#include <iostream>
int main()
{
std::cout << "First part\tSecond part";
return 0;
}
Đầu ra nào:
First part Second part
Ba chuỗi thoát đáng chú ý khác là:
\ In in một trích dẫn
\ ‘. In một trích dẫn kép
\\ In dấu gạch chéo ngược
Ở đây, một bảng của tất cả các chuỗi để giúp chúng ta thoát trong 1 line:
Name | Symbol | Ý nghĩa |
---|---|---|
Alert | \a | Tạo ra một cảnh báo, chẳng hạn như tiếng bíp |
Backspace | \b | Di chuyển con trỏ trở lại một khoảng trắng |
Formfeed | \f | Di chuyển con trỏ đến trang logic tiếp theo |
Newline | \n | Di chuyển con trỏ đến dòng tiếp theo |
Carriage return | \r | Di chuyển con trỏ đến đầu dòng |
Horizontal tab | \t | In một tab ngang |
Vertical tab | \v | In một tab dọc |
Single quote | \’ | In một trích dẫn |
Double quote | \” | In một trích dẫn kép |
Backslash | \\ | In dấu gạch chéo ngược. |
Question mark | \? | In một dấu hỏi. |
Octal number | \(number) | Dịch sang char từ số bát phân |
Hex number | \x(number) | Dịch sang char từ số hex |
Dưới đây là một số ví dụ:
/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* 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 << "\"This is quoted text\"\n";
std::cout << "This string contains a single backslash \\\n";
std::cout << "6F in hex is char '\x6F'\n";
return 0;
}
Bản in
"This is quoted text"
This string contains a single backslash \
6F in hex is char 'o'
6. Dòng mới (\ n) với std :: endl
Chúng ta đã tìm hiểu tại bài Giới thiệu về iostream: cout, cin và endl.
7. Điều khác biệt giữa việc đặt ký hiệu trong dấu ngoặc đơn hay dấu ngoặc kép
Các ký tự độc lập luôn được đặt trong các trích dẫn đơn (ví dụ: ’a’,’+’, ‘5’). Một char chỉ có thể đại diện cho một ký hiệu (ví dụ: chữ a, ký hiệu cộng, số 5). Ví dụ sau đây là sai:
char ch('56'); // a char can only hold one symbol
Văn bản đặt giữa hai dấu ngoặc kép (ví dụ: “Hello, world!”) được gọi là một chuỗi. Chuỗi là một tập hợp các ký tự liên tiếp (và do đó, một chuỗi có thể chứa nhiều ký hiệu).
Hiện tại, bạn có thể sử dụng chuỗi ký tự trong code của mình:
std::cout << "Hello, world!"; // "Hello, world!" is a string literal
Tuy nhiên, các chuỗi không phải là kiểu dữ liệu cơ bản trong C ++ và nó phức tạp hơn một chút, vì vậy chúng ta sẽ bảo lưu thảo luận về các kiểu dữ liệu đó cho đến khi chúng tôi đề cập đến các kiểu dữ liệu ghép.
Luôn đặt các ký tự độc lập trong các dấu ngoặc đơn. Điều này giúp trình biên dịch tối ưu hóa hiệu quả hơn.
8. Còn các loại char khác, wchar_t, char16_t và char32_t thì sao?
Nên tránh sử dụng wchar_t trong hầu hết các trường hợp (trừ khi giao tiếp với API Windows). Kích thước của nó được xác định, và không đáng tin cậy. Nó phần lớn đã bị phản đối khi dùng.
Giống như ASCII ánh xạ các số nguyên 0-127 sang các ký tự tiếng US, các tiêu chuẩn code hóa ký tự khác tồn tại để ánh xạ các số nguyên (có kích thước khác nhau) sang các ký tự trong các ngôn ngữ khác. Ánh xạ nổi tiếng nhất bên ngoài ASCII là tiêu chuẩn Unicode, ánh xạ hơn 110.000 số nguyên sang các ký tự trong nhiều ngôn ngữ khác nhau. Vì Unicode chứa rất nhiều điểm code, một điểm code Unicode duy nhất cần 32 bit để thể hiện một ký tự (được gọi là UTF-32). Tuy nhiên, các ký tự Unicode cũng có thể được mã hóa bằng nhiều ký tự 16 bit hoặc 8 bit (được gọi là UTF-16 và UTF-8 tương ứng).
char16_t và char32_t đã được thêm vào C ++ 11 để cung cấp hỗ trợ rõ ràng cho các ký tự Unicode 16 bit và 32 bit. char8_t đã được thêm vào trong C ++ 20.
Bạn có nhu cầu sử dụng char8_t, char16_t hoặc char32_t trừ khi bạn có kế hoạch làm một chương trình có liên quan tới Unicode. Unicode và ngôn ngữ bản địa nói chung nằm ngoài phạm vi của các hướng dẫn này, vì vậy chúng ta sẽ tìm hiểu trong phần tiếp theo.
Trong khi đó, bạn chỉ nên sử dụng các ký tự ASCII khi làm việc với các ký tự (và chuỗi). Sử dụng các ký tự từ các bộ ký tự khác có thể khiến các ký tự của bạn hiển thị không chính xác.