주어진 말 ...
std::string x = "hello";
`string`에서`char *`또는`const char *`얻기
x
범위 내에 있고 더 이상 수정되지 않는 동안 유효한 문자 포인터를 얻는 방법
C ++ 11 은 일을 단순화합니다. 다음은 모두 동일한 내부 문자열 버퍼에 대한 액세스를 제공합니다.
const char* p_c_str = x.c_str();
const char* p_data = x.data();
char* p_writable_data = x.data(); // for non-const x from C++17
const char* p_x0 = &x[0];
char* p_x0_rw = &x[0]; // compiles iff x is not const...
위의 모든 포인터는 버퍼에서 첫 번째 문자의 주소 와 동일한 값을 갖습니다 . 빈 문자열조차도 "버퍼의 첫 문자"를 갖습니다. C ++ 11은 명시 적으로 지정된 문자열 내용 뒤에 항상 여분의 NUL / 0 종료 문자를 유지하도록 보장합니다 (예 : std::string("this\0that", 9)
버퍼 보유 "this\0that\0"
).
위의 포인터 중 하나가 주어지면 :
char c = p[n]; // valid for n <= x.size()
// i.e. you can safely read the NUL at p[x.size()]
만 비에 대한 const
포인터 p_writable_data
와에서 &x[0]
:
p_writable_data[n] = c;
p_x0_rw[n] = c; // valid for n <= x.size() - 1
// i.e. don't overwrite the implementation maintained NUL
문자열에 다른 곳에 NUL을 쓰기 않습니다 없는 변화 string
의를 size()
; string
의 개수에 제한없이 NUL을 포함 할 수 있습니다 std::string
(C ++ 03에서와 동일).
에서 C ++ 03 , 상황은 훨씬 더 (키 차이가 복잡하고 강조 ) :
x.data()
- 표준에서 NUL로 결론을 내릴 필요가없는
const char*
문자열의 내부 버퍼로 돌아갑니다 (즉 , 정의되지 않은 동작을 갖는 우발적 인 액세스와 함께 초기화되지 않은 또는 가비지 값 이 이어질 수 있음 ).
['h', 'e', 'l', 'l', 'o']
x.size()
문자를 읽을 안전, 즉 x[0]
통해x[x.size() - 1]
- 빈 문자열의 경우 0이 안전하게 추가 될 수있는 NULL이 아닌 포인터 (hurray!)가 보장되지만 해당 포인터를 역 참조해서는 안됩니다.
&x[0]
- 빈 문자열의 경우 정의되지 않은 동작이 있습니다 (21.3.4).
- 예를 들어 , 그냥 사용할 때
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
전화하면 안됩니다 .f(&x[0], x.size());
x.empty()
f(x.data(), ...)
- 그렇지 않으면 다음과 같이
x.data()
:
- 비-
const
x
이것에 대한 const
char*
포인터 가 아닌 ; 문자열 내용을 덮어 쓸 수 있습니다
x.c_str()
const char*
값의 ASCIIZ (NUL 종료) 표현으로 돌아갑니다 (예 : [ 'h', 'e', 'l', 'l', 'o', '\ 0']).
- 모든 구현은 그렇게하도록 선택한 경우 약간의 C ++ 03 표준이 작성하는 문자열 구현에게 자유를 허용하는 말로되었지만 별개의 NUL 종료 버퍼를 즉석에서 잠재적으로 비 NUL에서에 의해 "노출"완충액을 종료
x.data()
하고&x[0]
x.size()
+ 1 문자는 읽기 안전합니다.
- 빈 문자열 ([ '\ 0'])에도 안전합니다.
법정 지수 외부에 액세스 한 결과
포인터를 얻는 방법에 관계없이 위 설명에서 보장 된 문자보다 포인터에서 메모리에 더 이상 액세스해서는 안됩니다. 그렇게하려고 시도 할 때 정의되지 않은 동작 이 발생합니다. 읽기에도 응용 프로그램 충돌 및 가비지 결과가 발생할 가능성이 높으며 쓰기에 대한 데이터, 스택 손상 및 / 또는 보안 취약점이 추가로 발생할 수 있습니다.
해당 포인터는 언제 무효화됩니까?
추가 용량 string
을 수정 string
하거나 추가 용량을 예약 하는 일부 멤버 함수 를 호출 하면 위의 메소드 중 하나에 의해 미리 리턴 된 포인터 값이 무효화 됩니다. 해당 메소드를 다시 사용하여 다른 포인터를 얻을 수 있습니다. (규칙은 string
s의 반복자와 동일합니다 .)
범위를 벗어난 후에도 문자 포인터를 유효하게 x
하거나 아래에서 추가로 수정 하는 방법 도 참조하십시오 .
그렇다면 어느 것이 더 나은 가요?
C ++ 11부터는 .c_str()
ASCIIZ 데이터 및 .data()
"이진"데이터 (아래에 자세히 설명)에 사용하십시오.
C ++ 03에서 사용하는 .c_str()
특정하지 않는 한 .data()
적절한이며, 선호 .data()
이상 &x[0]
이 빈 문자열에 대한 안전으로 ....
... data()
필요할 때 사용하기에 충분한 프로그램을 이해하려고 노력하십시오 . 그렇지 않으면 다른 실수를 저지를 것입니다 ...
ASCII NUL '\ 0'문자가 보장하는 .c_str()
것은 많은 기능에서 관련되고 액세스하기 쉬운 데이터의 끝을 나타내는 센티넬 값으로 사용됩니다. 이것은 say fstream::fstream(const char* filename, ...)
와 같은 C ++ 전용 함수 및 strchr()
, 및 C와 공유 기능에 모두 적용됩니다 printf()
.
.c_str()
반환 된 버퍼에 대한 C ++ 03의 보증이의 상위 집합이므로 .data()
항상 안전하게 사용할 수 .c_str()
있지만 사람들은 때때로 그렇지 않기 때문에 :
- 를 사용
.data()
하면 데이터가 ASCIIZ가 아닌 소스 코드를 읽는 다른 프로그래머와 통신합니다 (대신 문자열을 사용하여 데이터 블록을 저장하거나 (때로는 텍스트가 아닌 경우도 있음)) "이진"데이터 블록으로 취급하는 다른 함수. 이것은 다른 프로그래머의 코드 변경이 데이터를 올바르게 처리하도록 보장하는 데 중요한 통찰력이 될 수 있습니다.
- C ++ 03 전용 :
string
구현에서 NUL 종료 버퍼를 준비하기 위해 추가 메모리 할당 및 / 또는 데이터 복사를 수행해야 할 가능성이 약간 있습니다.
추가 힌트로, 함수의 파라미터는 (필요한 경우 const
) char*
하지만 점점 주장하지 않는 x.size()
, 함수가 아마 ASCIIZ 입력을 필요로하므로 .c_str()
어떻게 든 텍스트 종료가, 그렇지 않은 그렇다면 어디에 좋은 선택이다 (기능 요구 알고 별도의 매개 변수는 길이 접두사 또는 센티넬 또는 고정 길이와 같은 규칙 일 수 있습니다.
x
범위를 벗어난 후에도 문자 포인터를 유효하게 하거나 추가로 수정하는 방법
의 내용을 외부의 새 메모리 영역 에 복사 해야합니다 . 이 외부 버퍼는 다른 또는 문자 배열 변수 와 같은 여러 위치에있을 수 있으며 다른 범위 (예 : 네임 스페이스, 전역, 정적, 힙, 공유 메모리, 메모리 매핑 된 파일)에 있기 때문에 수명이 다를 수도 있고 그렇지 않을 수도 있습니다. .string
x
x
string
x
텍스트를 std::string x
독립 문자 배열로 복사하려면
// USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE
std::string old_x = x;
// - old_x will not be affected by subsequent modifications to x...
// - you can use `&old_x[0]` to get a writable char* to old_x's textual content
// - you can use resize() to reduce/expand the string
// - resizing isn't possible from within a function passed only the char* address
std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL
// Copies ASCIIZ data but could be less efficient as it needs to scan memory to
// find the NUL terminator indicating string length before allocating that amount
// of memory to copy into, or more efficient if it ends up allocating/copying a
// lot less content.
// Example, x == "ab\0cd" -> old_x == "ab".
// USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03
std::vector<char> old_x(x.data(), x.data() + x.size()); // without the NUL
std::vector<char> old_x(x.c_str(), x.c_str() + x.size() + 1); // with the NUL
// USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N"
// (a bit dangerous, as "known" things are sometimes wrong and often become wrong)
char y[N + 1];
strcpy(y, x.c_str());
// USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (e.g. Hello\0->Hel\0)
char y[N + 1];
strncpy(y, x.c_str(), N); // copy at most N, zero-padding if shorter
y[N] = '\0'; // ensure NUL terminated
// USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH
char* y = alloca(x.size() + 1);
strcpy(y, x.c_str());
// USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION)
char y[x.size() + 1];
strcpy(y, x.c_str());
// USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = new char[x.size() + 1];
strcpy(y, x.c_str());
// or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str());
// use y...
delete[] y; // make sure no break, return, throw or branching bypasses this
// USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE
// see boost shared_array usage in Johannes Schaub's answer
// USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = strdup(x.c_str());
// use y...
free(y);
다른 이유는를하려는 char*
또는 const char*
A로부터 생성 된string
당신이 본 것보다 그래서, 어떻게이 (얻을 const
) char*
, 어떻게 원래의 텍스트 독립의 사본을 만들기 위해 string
,하지만 당신은 무엇을 할 수 할 함께? 예제의 무작위 찌그러짐 ...
- 다음과 같이 "C"코드에 C ++
string
텍스트에 대한 액세스 권한을 부여하십시오 .printf("x is '%s'", x.c_str());
- 복사
x
함수의 호출에 의해 지정된 버퍼의 텍스트 (예 strncpy(callers_buffer, callers_buffer_size, x.c_str())
) 또는 휘발성 메모리 장치에 사용되는 I / O (예 for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
)
x
ASCIIZ 텍스트가 이미 포함 된 문자 배열에 텍스트를 추가 합니다 (예 : strcat(other_buffer, x.c_str())
버퍼를 오버런하지 않도록주의하십시오 (많은 상황에서 사용해야 할 수도 있음 strncat
)).
- 함수에서
const char*
또는 char*
함수에서 반환 (아마도 역사적 이유로 클라이언트가 기존 API를 사용 중이거나 C 호환성을 위해을 반환하고 std::string
싶지 않지만 string
호출자의 데이터를 어딘가에 복사하려는 경우)
string
포인터가 가리키는 로컬 변수가 범위를 벗어난 후 호출자가 참조 해제 할 수있는 포인터를 반환하지 않도록주의하십시오.
- 서로 다른
std::string
구현을 위해 컴파일 / 링크 된 공유 객체가있는 일부 프로젝트 (예 : STLport 및 컴파일러 네이티브)는 충돌을 피하기 위해 데이터를 ASCIIZ로 전달할 수 있습니다.