Nối hai chuỗi ký tự


121

Tôi đang đọc Accelerated C ++ của Koenig. Ông viết rằng "ý tưởng mới là chúng ta có thể sử dụng + để nối một chuỗi và một chuỗi theo nghĩa đen - hoặc, đối với vấn đề đó, hai chuỗi (nhưng không phải là hai ký tự chuỗi).

Tốt thôi, tôi cho là có lý. Bây giờ chuyển sang hai bài tập riêng biệt nhằm làm sáng tỏ điều này.

Các định nghĩa sau đây có hợp lệ không?

const string hello = "Hello";

const string message = hello + ",world" + "!";

Bây giờ, tôi đã cố gắng thực hiện ở trên và nó đã hoạt động! Vì vậy, tôi đã rất vui.

Sau đó, tôi cố gắng làm bài tập tiếp theo;

const string exclam = "!";

const string message = "Hello" + ",world" + exclam;

Điều này đã không hoạt động. Bây giờ tôi hiểu nó có liên quan đến thực tế là bạn không thể nối hai chuỗi ký tự, nhưng tôi không hiểu sự khác biệt về ngữ nghĩa giữa lý do tại sao tôi quản lý để lấy ví dụ đầu tiên hoạt động (không phải là ", world" và "! "hai ký tự chuỗi? Điều này không nên đã hoạt động?) nhưng không phải là thứ hai.


4
const string message = "Hello" ",world" + exclam(ví dụ: bỏ qua đầu tiên +) công việc tốt.
n0rd

1
@Joe - Tại sao mọi người lại viết "Hello" + ", world!"khi bạn có thể làm được "Hello, world!". Như thường lệ, C ++ có một cách giải quyết tuyệt vời và đơn giản cho một vấn đề được nhận thức. :-)
Bo Persson

2
@Bo Điều duy nhất tôi có thể nghĩ đến là nếu bạn sử dụng một định nghĩa (#define)
Joe Phillips

@Joe Ngay cả sau đó, bạn có nhiều khả năng viết "Hello" ", world!"(không có +) hơn. Có một số phàn nàn về C ++, nhưng tôi không nghĩ việc xử lý ở đây là một trong số đó. Nó giống hệt như khi bạn viết 1 / 3 + 1.5, và phàn nàn vì phép chia là phép chia tích phân. Dù tốt hơn hay tệ hơn, đây là cách hoạt động của hầu hết các ngôn ngữ.
James Kanze

2
@Bo Persson Trên thực tế, tính năng "hello" " world" == "hello world"này hữu ích nếu bạn phải viết một chuỗi dài và không muốn nó đi ra khỏi cửa sổ của bạn hoặc bạn muốn ở trong một số giới hạn độ dài dòng. Hoặc nếu một trong các chuỗi được xác định trong macro.
Dimitar Slavchev 12/12/12

Câu trả lời:


140
const string message = "Hello" + ",world" + exclam;

Các +nhà điều hành đã để lại sang phải associativity, vì vậy biểu thức trong ngoặc đơn tương đương là:

const string message = (("Hello" + ",world") + exclam);

Như bạn có thể thấy, hai chuỗi ký tự "Hello"",world"được "thêm vào" đầu tiên, do đó lỗi.

Một trong hai chuỗi đầu tiên được nối phải là một std::stringđối tượng:

const string message = string("Hello") + ",world" + exclam;

Ngoài ra, bạn có thể buộc +đánh giá thứ hai trước bằng cách đặt ngoặc đơn cho phần đó của biểu thức:

const string message = "Hello" + (",world" + exclam);

Có nghĩa là ví dụ đầu tiên của bạn ( hello + ",world" + "!") hoạt động vì std::string( hello) là một trong những đối số ở ngoài cùng bên trái +. Điều đó +được đánh giá, kết quả là một std::stringđối tượng với chuỗi được nối và kết quả std::stringđó sau đó được nối với "!".


Đối với lý do tại sao bạn không thể nối hai chuỗi ký tự bằng cách sử dụng +, đó là bởi vì một chuỗi ký tự chỉ là một mảng các ký tự ( const char [N]ở đó Nđộ dài của chuỗi cộng với một, đối với dấu chấm hết null). Khi bạn sử dụng một mảng trong hầu hết các ngữ cảnh, nó sẽ được chuyển đổi thành một con trỏ tới phần tử ban đầu của nó.

Vì vậy, khi bạn cố gắng làm "Hello" + ",world" , những gì bạn thực sự đang cố gắng làm là thêm hai chữ cái const char*lại với nhau, điều này là không thể (cộng hai con trỏ lại với nhau có nghĩa là gì?) Và nếu nó sẽ không làm được điều bạn muốn nó làm.


Lưu ý rằng bạn có thể nối các ký tự chuỗi bằng cách đặt chúng bên cạnh nhau; ví dụ: hai cái sau là tương đương:

"Hello" ",world"
"Hello,world"

Điều này rất hữu ích nếu bạn có một chuỗi ký tự dài mà bạn muốn chia thành nhiều dòng. Tuy nhiên, chúng phải là chuỗi ký tự: điều này sẽ không hoạt động với const char*con trỏ hoặc const char[N]mảng.


3
Ngoài ra, const string message = "Hello" + (",world"+exclam);cũng sẽ hoạt động, vì dấu ngoặc đơn rõ ràng (đó có phải là một từ không?).
Chinmay Kanchi

1
Thậm chí có thể đầy đủ hơn nếu bạn chỉ ra lý do tại sao ví dụ đầu tiên hoạt động:const string message = ((hello + ",world") + "!");
Mark Ransom vào

Cảm ơn bạn! Tôi nghi ngờ nó có liên quan gì đó đến sự liên tưởng từ trái sang phải nhưng không chắc chắn và sự khác biệt về ngữ nghĩa này không có nhiều ý nghĩa đối với tôi. Tôi đánh giá cao câu trả lời!
Arthur Collé

2
Tôi muốn đề cập đến "Hello" ",world"cú pháp không chỉ hữu ích để ngắt thành nhiều dòng mà còn khi một trong các chuỗi ký tự là macro (hoặc thậm chí cả hai). Sau đó, nối xảy ra trong thời gian biên dịch.
Melebius

8

Bạn nên luôn chú ý đến các loại .

Mặc dù tất cả chúng có vẻ giống như chuỗi "Hello"",world"là nghĩa đen .

Và trong ví dụ của bạn, exclamlà một std::stringđối tượng.

C ++ có một quá tải toán tử lấy một std::stringđối tượng và thêm một chuỗi khác vào nó. Khi bạn nối một std::stringđối tượng với một ký tự, nó sẽ thực hiện ép kiểu thích hợp cho ký tự.

Nhưng nếu bạn cố gắng nối hai ký tự, trình biên dịch sẽ không thể tìm thấy một toán tử nhận hai ký tự.


Hãy xem std :: operator + cung cấp các quá tải để nối một ký tự std::stringkhác std::string, một mảng ký tự hoặc một ký tự đơn lẻ.
DavidRR

7

Ví dụ thứ hai của bạn không hoạt động vì không có operator +cho hai chuỗi ký tự. Lưu ý rằng một chuỗi ký tự không phải là kiểu string, nhưng thay vào đó là kiểu const char *. Ví dụ thứ hai của bạn sẽ hoạt động nếu bạn sửa đổi nó như thế này:

const string message = string("Hello") + ",world" + exclam;

4

Kể từ C ++ 14, bạn có thể sử dụng hai ký tự chuỗi thực :

const string hello = "Hello"s;

const string message = hello + ",world"s + "!"s;

hoặc là

const string exclam = "!"s;

const string message = "Hello"s + ",world"s + exclam;

2

Trong trường hợp 1, do thứ tự của các hoạt động bạn nhận được:

(xin chào + ", world") + "!" giải quyết thành hello + "!" và cuối cùng là xin chào

Trong trường hợp 2, như James đã lưu ý, bạn nhận được:

("Xin chào" + ", world") + dấu chấm than là kết hợp của 2 chuỗi ký tự.

Hy vọng nó rõ ràng :)


1

Sự khác biệt giữa một chuỗi (hay nói chính xác là std::string) và một ký tự theo nghĩa đen là đối với cái sau không có +toán tử nào được định nghĩa. Đây là lý do tại sao ví dụ thứ hai không thành công.

Trong trường hợp đầu tiên, trình biên dịch có thể tìm thấy một operator+đối số phù hợp với đối số đầu tiên là a stringvà đối số thứ hai là một ký tự Lite ( const char*) để nó sử dụng đối số đó. Kết quả của phép toán đó lại là a string, vì vậy nó lặp lại thủ thuật tương tự khi thêm "!"vào nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.