문자열 c_str () 대 data ()


102

c_str()data()(STL 및 기타 구현에서) 의 차이점 c_str()은 항상 null로 종료되는 반면 data()그렇지 않은 경우 여러 곳을 읽었습니다 . 내가 실제 구현에서 본 한, 그들은 동일하거나 data()호출합니다 c_str().

내가 여기서 무엇을 놓치고 있습니까? 어떤 시나리오에서 사용하는 것이 더 정확합니까?

답변:


105

문서가 정확합니다. c_str()널로 끝나는 문자열을 원하는 경우 사용하십시오 .

구현자가 당신의 data()관점 에서 구현 한 경우 c_str()걱정할 data()필요가 없습니다. 문자열이 null로 종료 될 필요가 없다면 여전히 사용 하십시오. 일부 구현에서는 c_str ()보다 더 나은 성능을 보일 수 있습니다.

문자열은 반드시 문자 데이터로 구성 될 필요는 없으며 모든 유형의 요소로 구성 될 수 있습니다. 이 경우 data()더 의미가 있습니다. c_str()제 생각에는 문자열의 요소가 문자 기반 일 때만 정말 유용합니다.

Extra : C ++ 11부터는 두 함수가 동일해야합니다. 즉, data이제 null로 끝나야합니다. cppreference 에 따르면 : "반환 된 배열은 null로 종료됩니다. 즉, data () 및 c_str ()은 동일한 기능을 수행합니다."


4
추가 2 : C ++ 17 이후부터는에 .data()대한 상수가 아닌 오버로드가 있으므로 상수가 아닌 문자열에 대해 더 이상 동일하지 않습니다.
Deduplicator

29

에서 C ++ 11 / C ++ 0X , data()그리고 c_str()더 이상 다릅니다. 따라서 data()끝에도 null 종료가 필요합니다.

21.4.7.1 basic_string접근 자 [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 개 반환 값 : 포인터 p를되도록 p + i == &operator[](i)i에서 [0,size()].


21.4.5 basic_string 요소 액세스 [string.access]

const_reference operator[](size_type pos) const noexcept;

1 필요 : pos <= size (). 2 반환 값 : *(begin() + pos) if pos < size(), 그렇지 않으면 charT();참조 된 값이 있는 값을 가진 T 유형의 객체에 대한 참조가 수정되지 않습니다.


문자열이 문자가 아닌 데이터로 구성된 경우 null을 포함하여 문자열 데이터 AFAIK에 합법적입니까?
taz

3
이진 데이터를 저장하는 경우에도 @taz, C ++ (11)는 필요한 std::string추가 할당 char후행 대한 '\0'. 그렇게하면 및 std::string s("\0");둘 다 0으로 평가됩니다.s.data()[0]s.data()[1]
bcrist

19

.data ()가 .c_str ()을 호출한다는 것을 알고 있더라도 이것이 다른 컴파일러의 경우라고 가정하는 것은 옳지 않습니다. 컴파일러가 향후 릴리스에서 변경 될 수도 있습니다.

std :: string을 사용하는 2 가지 이유 :

std :: string은 텍스트 및 임의의 이진 데이터 모두에 사용할 수 있습니다.

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

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

예제 1과 같이 문자열을 사용할 때는 .c_str () 메서드를 사용해야합니다.

예제 2와 같이 문자열을 사용할 때는 .data () 메서드를 사용해야합니다. 이러한 경우 .c_str ()을 사용하는 것이 위험하기 때문이 아니라 다른 사람이 검토 할 수 있도록 바이너리 데이터로 작업하는 것이 더 명확하기 때문입니다. 귀하의 코드.

.data () 사용시 가능한 함정

다음 코드는 잘못되었으며 프로그램에서 segfault를 일으킬 수 있습니다.

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

구현자가 .data ()와 .c_str ()이 같은 일을하도록 만드는 것이 일반적인 이유는 무엇입니까?

그렇게하는 것이 더 효율적이기 때문입니다. .data ()가 null로 끝나지 않은 것을 반환하도록하는 유일한 방법은 .c_str () 또는 .data ()가 내부 버퍼를 복사하도록하거나 2 개의 버퍼를 사용하는 것입니다. null로 끝나는 단일 버퍼가 있다는 것은 std :: string을 구현할 때 항상 내부 버퍼를 하나만 사용할 수 있음을 의미합니다.


6
사실 .data ()의 요점은 내부 버퍼를 복사해서는 안된다는 것입니다. 이것은 구현이 필요할 때까지 \ 0에 문자를 낭비 할 필요가 없음을 의미합니다. 두 개의 버퍼를 원하지 않을 것입니다. .c_str ()을 호출하면 버퍼에 \ 0을 추가하십시오. .data ()는 여전히 해당 버퍼를 반환 할 수 있습니다.
MSalters

2
2 개의 버퍼를 사용하는 것은 어리석은 일입니다. 그것이 .data가 의도 된 이유라는 것을 어떻게 알 수 있습니까?
Brian R. Bondy

@ BrianR.Bondy 나는이 코드를 시도했다 : .. auto str = string { "Test \ 0String!" }; cout << "데이터 :"<< str.data () << endl; 출력은 전체 문자열이 아니라 "Test"입니다. 내가 뭘 잘못 했나요?
프로그래머

마지막 부분이 잘못되었습니다. data와 c_str은 0으로 끝나지 않고 동일한 버퍼를 사용할 수 있습니다. c_str은 첫 번째 호출에서 단순히 0을 추가 할 수 있습니다.
모니카 기억

머리 위로, C ++ (11) 만든 .DATA () .c_str ()의 별칭
hanshenrik

3

이미 답변을 받았으며 목적에 대한 몇 가지 메모 : 구현의 자유.

std::string작업 (예 : 반복, 연결 및 요소 변형)에는 0 종결자가 필요하지 않습니다. string0으로 끝나는 문자열을 예상하는 함수에을 전달하지 않는 한 생략 할 수 있습니다.

이를 통해 구현에서 하위 문자열이 실제 문자열 데이터 string::substr를 공유 할 수 있습니다. 내부적으로 공유 문자열 데이터에 대한 참조와 시작 / 종료 범위를 보유 할 수 있으므로 실제 문자열 데이터 의 복사 (및 추가 할당)를 피할 수 있습니다. 구현은 c_str을 호출하거나 문자열을 수정할 때까지 복사를 연기합니다. 관련된 strigns를 읽은 경우에는 사본이 만들어지지 않습니다.

(기록 중 복사 구현은 다중 스레드 환경에서 그다지 재미가 없으며, 일반적인 메모리 / 할당 절약은 오늘날 더 복잡한 코드의 가치가 없으므로 거의 수행되지 않습니다).


마찬가지로 string::data로프 (문자열 세그먼트의 링크 된 목록)와 같은 다른 내부 표현을 허용합니다. 이는 삽입 / 교체 작업을 크게 향상시킬 수 있습니다. 다시, 세그먼트의 목록은 호출 할 때 하나의 세그먼트에 붕괴되어야 할 것이다 c_strdata.


2

ANSI ISO IEC 14882 2003(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

이전의 모든 주석은 일관성이지만 C ++ 17부터 str.data ()가 const char * 대신 char *를 반환한다는 것을 추가하고 싶습니다.


1
모두 constnon-const오버로드 C ++ 17부터 사용할 수 있습니다.
Gupta
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.