chuỗi c_str () so với data ()


102

Tôi đã đọc một số nơi rằng sự khác biệt giữa c_str()data()(trong STL và các triển khai khác) c_str()là luôn luôn bị kết thúc bằng rỗng trong khi data()thì không. Theo như tôi đã thấy trong các triển khai thực tế, chúng hoặc thực hiện giống nhau hoặc data()gọi c_str().

Tôi còn thiếu gì ở đây? Cái nào đúng hơn để sử dụng trong các trường hợp?

Câu trả lời:


105

Các tài liệu là chính xác. Sử dụng c_str()nếu bạn muốn một chuỗi kết thúc null.

Nếu người thực hiện happend để thực hiện data()trong điều kiện của c_str()bạn không cần phải lo lắng, vẫn sử dụng data()nếu bạn không cần chuỗi để được null chấm dứt, trong một số thực hiện nó có thể bật ra để thực hiện tốt hơn so với c_str ().

chuỗi không nhất thiết phải bao gồm dữ liệu ký tự, chúng có thể được tạo bằng các phần tử thuộc bất kỳ loại nào. Trong những trường hợp đó data()có ý nghĩa hơn. c_str()theo quan điểm của tôi chỉ thực sự hữu ích khi các phần tử của chuỗi của bạn dựa trên ký tự.

Thêm : Trong C ++ 11 trở đi, cả hai hàm bắt buộc phải giống nhau. tức datalà bây giờ bắt buộc phải được kết thúc bằng null. Theo cppreference : "Mảng được trả về là kết thúc bằng null, tức là dữ liệu () và c_str () thực hiện cùng một chức năng."


4
Bổ sung 2: Trong C ++ 17 trở đi, giờ đây cũng có quá tải không phải const cho .data(), vì vậy chúng không còn tương đương với các chuỗi không phải là hằng số.
Deduplicator

29

Trong C ++ 11 / C ++ 0x , data()c_str()không còn khác nữa. Và do đó data()cũng cần phải có một chấm dứt vô hiệu ở cuối.

21.4.7.1 trình truy cập basic_string[string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Trả về: Một con trỏ p sao p + i == &operator[](i)cho mỗi itrong [0,size()].


21.4.5 truy cập phần tử basic_string [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Yêu cầu: pos <= size (). 2 Trả về:, *(begin() + pos) if pos < size()nếu không thì một tham chiếu đến một đối tượng kiểu T có giá trị charT();thì giá trị được tham chiếu sẽ không bị thay đổi.


Điều gì sẽ xảy ra nếu chuỗi bao gồm dữ liệu không phải ký tự, dữ liệu này hợp pháp đối với dữ liệu chuỗi AFAIK, bao gồm cả giá trị rỗng?
taz

3
@taz Ngay cả khi lưu trữ dữ liệu nhị phân, C ++ 11 yêu cầu std::stringphân bổ thêm charcho một dấu '\0'. Khi bạn làm std::string s("\0");, cả hai s.data()[0]s.data()[1]được đảm bảo để ước lượng tới 0.
bcrist

19

Ngay cả khi biết rằng bạn đã thấy rằng họ làm như vậy, hoặc .data () gọi .c_str (), sẽ không đúng khi cho rằng điều này sẽ xảy ra với các trình biên dịch khác. Cũng có thể trình biên dịch của bạn sẽ thay đổi với bản phát hành trong tương lai.

2 lý do để sử dụng std :: string:

std :: string có thể được sử dụng cho cả văn bản và dữ liệu nhị phân tùy ý.

//Example 1
//Plain text:
std::string s1;
s1 = "abc";

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);

Bạn nên sử dụng phương thức .c_str () khi bạn đang sử dụng chuỗi của mình như ví dụ 1.

Bạn nên sử dụng phương thức .data () khi bạn đang sử dụng chuỗi của mình như ví dụ 2. Không phải vì việc sử dụng .c_str () trong những trường hợp này là vô ích, mà vì rõ ràng hơn là bạn đang làm việc với dữ liệu nhị phân để người khác xem xét. ma cua ban.

Cạm bẫy có thể xảy ra khi sử dụng .data ()

Mã sau sai và có thể gây ra lỗi mặc định trong chương trình của bạn:

std::string s;
s = "abc";   
char sz[512]; 
strcpy(sz, s.data());//This could crash depending on the implementation of .data()

Tại sao những người triển khai thường làm cho .data () và .c_str () làm điều tương tự?

Vì làm như vậy sẽ hiệu quả hơn. Cách duy nhất để làm cho .data () trả về một cái gì đó không bị kết thúc bằng null, là có .c_str () hoặc .data () sao chép bộ đệm bên trong của chúng hoặc chỉ sử dụng 2 bộ đệm. Có một bộ đệm kết thúc null duy nhất luôn có nghĩa là bạn luôn có thể chỉ sử dụng một bộ đệm bên trong khi triển khai std :: string.


6
Trên thực tế, điểm của .data () là nó không nên sao chép bộ đệm bên trong. Điều này có nghĩa là việc triển khai không phải lãng phí một ký tự trên \ 0 cho đến khi nó cần. Bạn sẽ không bao giờ muốn có hai bộ đệm: nếu bạn DO gọi .c_str (), hãy thêm \ 0 vào bộ đệm. .data () vẫn có thể trả về bộ đệm đó.
MSalters 13/10/08

2
Đồng ý hoàn toàn sẽ là vô lý nếu sử dụng 2 bộ đệm. Làm thế nào để bạn biết đó là lý do tại sao .data được sử dụng?
Brian R. Bondy 13/10/08

@ BrianR.Bondy Tôi đã thử mã này: .. auto str = string {"Test \ 0String!" } cout << "DATA:" << str.data () << endl; Đầu ra là "Kiểm tra" chứ không phải toàn bộ chuỗi, Tôi đã làm gì sai?
lập trình viên

Phần cuối cùng là sai, dữ liệu và c_str có thể sử dụng cùng một bộ đệm mà không bị kết thúc bằng 0 - c_str có thể chỉ cần thêm số 0 vào lần gọi đầu tiên.
Nhớ Monica

người đứng đầu lên, c ++ 11 .data thực hiện () một bí danh cho .c_str ()
hanshenrik

3

Nó đã được trả lời rồi, một số lưu ý về mục đích: Tự do thực hiện.

std::stringcác phép toán - ví dụ như lặp, nối và đột biến phần tử - không cần dấu chấm hết. Trừ khi bạn chuyển stringđến một hàm mong đợi một chuỗi kết thúc bằng 0, nó có thể bị bỏ qua.

Điều này sẽ cho phép thực hiện để có chuỗi con chia sẻ dữ liệu chuỗi thực tế: string::substrtrong nội bộ có thể giữ một tham chiếu đến dữ liệu chuỗi chia sẻ, và phạm vi bắt đầu / kết thúc, tránh sao chép (và cấp bổ sung) của dữ liệu chuỗi thực tế. Việc triển khai sẽ trì hoãn bản sao cho đến khi bạn gọi c_str hoặc sửa đổi bất kỳ chuỗi nào. Sẽ không có bản sao nào được tạo ra nếu chỉ đọc.

(việc triển khai copy-on-write không thú vị lắm trong môi trường đa luồng, cộng với việc tiết kiệm bộ nhớ / phân bổ điển hình không đáng với mã phức tạp hơn ngày nay, vì vậy nó hiếm khi được thực hiện).


Tương tự, string::datacho phép một biểu diễn bên trong khác, ví dụ như một sợi dây (danh sách liên kết của các đoạn chuỗi). Điều này có thể cải thiện đáng kể hoạt động chèn / thay thế. một lần nữa, danh sách các phân đoạn sẽ phải được thu gọn thành một phân đoạn duy nhất khi bạn gọi c_strhoặc data.


2

Trích dẫn từ ANSI ISO IEC 14882 2003(Chuẩn C ++ 03):

    21.3.6 basic_string string operations [lib.string.ops]

    const charT* c_str() const;

    Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
    Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.

    const charT* data() const;

    Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
    Requires: The program shall not alter any of the values stored in the character array. Nor shall the program
treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.

2

Tất cả các commments trước đều nhất quán, nhưng tôi cũng muốn thêm rằng bắt đầu từ c ++ 17, str.data () trả về một char * thay vì const char *


1
Cả hai constnon-constquá tải đều có sẵn kể từ C ++ 17.
Gupta
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.