std :: string을 const char * 또는 char *로 변환하는 방법은 무엇입니까?


893

std::string를 a char*또는 a 로 변환하려면 어떻게 해야 const char*합니까?


2
대신 : char * 쓰기 가능 = 새 char [str.size () + 1]; char writable [str.size () + 1];을 사용할 수 있습니다. 그런 다음 쓰기 가능 또는 예외 처리 삭제에 대해 걱정할 필요가 없습니다.

7
컴파일 타임에 크기를 알지 않는 한 str.size ()를 사용할 수 없으며 고정 크기 값이 크면 스택이 오버플로 될 수 있습니다.
paulm

1
char * 결과 = strcpy ((char *) malloc (str.length () + 1), str.c_str ());
cegprakash

7
@cegprakash strcpymalloc정말 C ++ 방법이 없습니다.
boycy

4
아니요, 그러나 char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)더 관용적 인 C ++입니다. strcpy()그리고 malloc()잘못이나 문제가 아니지만, 동일한 코드 블록에서 C ++ 등가물와 C ++ 문자열과 C 라이브러리 기능을 사용하는 일관성이 보인다.
boycy

답변:


1055

당신은 단지를 전달하려는 경우 std::string필요로하는 기능에 const char*사용할 수있는

std::string str;
const char * c = str.c_str();

와 같은 쓰기 가능한 사본을 얻으려면 다음과 같이 char *하십시오.

std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0

// don't forget to free the string after finished using it
delete[] writable;

편집 : 위의 예외는 안전하지 않습니다. new호출과 호출 사이에 무언가 delete가 발생 delete하면 자동으로 호출되는 것이 없으므로 메모리가 누출 됩니다. 이를 해결하기위한 두 가지 즉각적인 방법이 있습니다.

boost :: scoped_array

boost::scoped_array 범위를 벗어나면 메모리가 삭제됩니다.

std::string str;
boost::scoped_array<char> writable(new char[str.size() + 1]);
std::copy(str.begin(), str.end(), writable.get());
writable[str.size()] = '\0'; // don't forget the terminating 0

// get the char* using writable.get()

// memory is automatically freed if the smart pointer goes 
// out of scope

std :: vector

이것은 표준 방식입니다 (외부 라이브러리가 필요하지 않음). 를 사용 std::vector하면 메모리를 완전히 관리 할 수 ​​있습니다.

std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()

41
간단히 char * result = strdup (str.c_str ())를 사용하십시오;
Jasper Bekkers

63
당신은 할 수 있지만에서는 StrDup, 그것은 : POSIX에서의 AC 또는 C ++ 표준 함수가 아니다
litb - 요하네스 SCHAUB

14
내가 일반적으로 선호하는 것은 std :: vector <char> writable (str.begin (), str.end ()); writable.push_back ( '\ 0'); char * c = 쓰기 가능 [0];
Johannes Schaub-litb

17
std :: copy는 문자열 포인터를 얻을 필요없이 이것을 수행하는 C ++ 방법입니다. 가능한 한 C 함수를 사용하지 않으려 고합니다.
Johannes Schaub-litb

16
C ++ 17 std::string::data()부터는 이제 a CharT*대신을 반환 합니다 const CharT*. 이 답변을 업데이트하는 것이 좋습니다 :)
Rakete1111 03. 31. 17.

192

주어진 말 ...

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하거나 추가 용량을 예약 하는 일부 멤버 함수 를 호출 하면 위의 메소드 중 하나에 의해 미리 리턴 된 포인터 값이 무효화 됩니다. 해당 메소드를 다시 사용하여 다른 포인터를 얻을 수 있습니다. (규칙은 strings의 반복자와 동일합니다 .)

범위를 벗어난 후에도 문자 포인터를 유효하게 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 xxstringx

텍스트를 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;)
  • xASCIIZ 텍스트가 이미 포함 된 문자 배열에 텍스트를 추가 합니다 (예 : strcat(other_buffer, x.c_str())버퍼를 오버런하지 않도록주의하십시오 (많은 상황에서 사용해야 할 수도 있음 strncat)).
  • 함수에서 const char*또는 char*함수에서 반환 (아마도 역사적 이유로 클라이언트가 기존 API를 사용 중이거나 C 호환성을 위해을 반환하고 std::string싶지 않지만 string호출자의 데이터를 어딘가에 복사하려는 경우)
    • string포인터가 가리키는 로컬 변수가 범위를 벗어난 후 호출자가 참조 해제 할 수있는 포인터를 반환하지 않도록주의하십시오.
    • 서로 다른 std::string구현을 위해 컴파일 / 링크 된 공유 객체가있는 일부 프로젝트 (예 : STLport 및 컴파일러 네이티브)는 충돌을 피하기 위해 데이터를 ASCIIZ로 전달할 수 있습니다.

4
좋은데 char * (비 const)를 원하는 또 다른 이유는 MPI 브로드 캐스트로 작동하기 때문입니다. 앞뒤로 복사 할 필요가 없으면 더 좋아 보입니다. 나는 개인적으로 문자열에 char * const getter를 제공했을 것입니다. 상수 포인터이지만 편집 가능한 문자열 const char *에서 문자열로의 암묵적인 변환으로 혼란
스러울

33

에 대한 .c_str()방법을 사용하십시오 const char *.

포인터 &mystring[0]를 얻는 데 사용할 수 char *있지만 몇 가지 문제가 있습니다. 반드시 0으로 끝나는 문자열을 얻을 필요는 없으며 문자열의 크기를 변경할 수 없습니다. 특히 문자열 끝을 지나서 문자를 추가하지 않도록주의해야합니다. 그렇지 않으면 버퍼 오버런 (및 충돌 가능성)이 발생합니다.

C ++ 11까지 모든 문자가 동일한 연속 버퍼의 일부라는 보장은 없었지만 실제로는 알려진 모든 구현이 std::string어쨌든 그렇게 작동했습니다. 참조 표준 : : 문자열에 연속 문자합니까 "& S [0]"포인트? .

많은 string멤버 함수는 내부 버퍼를 재 할당하고 저장 한 모든 포인터를 무효화합니다. 즉시 사용하고 버리는 것이 가장 좋습니다.


1
data ()는 const char * :)를 반환한다는 것을 명심해야합니다. 의미하는 것은 & str [0]이며, 연속적이지만 불필요한 null 종료 문자열을 반환합니다.
Johannes Schaub-litb

1
@litb, 아아! 그것이 바로 빠른 답변을 얻기 위해 얻는 것입니다. 과거에 귀하의 솔루션을 사용했지만 왜 이것이 처음이 아닌지 모릅니다. 내 답변을 편집했습니다.
Mark Ransom

2
기술적으로 std :: string 스토리지는 C ++ 0x에서만 연속적입니다.
MSalters

1
@MSalters, 감사합니다-나는 그것을 몰랐습니다. 그래도 그렇지 않은 구현을 찾기가 어려울 것입니다.
Mark Ransom

2
char * 결과 = strcpy (malloc (str.length () + 1), str.c_str ());
cegprakash

21

C ++ 17

C ++ 17 (다가오는 표준)은 basic_stringconst가 아닌 오버로드를 추가 하여 템플릿의 개요를 변경합니다 data().

charT* data() noexcept;

결과 : [0, size ()]의 각 i에 대해 p + i == & operator와 같은 포인터 p.


CharT const * ...에서 std::basic_string<CharT>

std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()

CharT * ...에서 std::basic_string<CharT>

std::string str = { "..." };
char * p = str.data();

C ++ 11

CharT const * ...에서 std::basic_string<CharT>

std::string str = { "..." };
str.c_str();

CharT * ...에서 std::basic_string<CharT>

C ++ 11부터 표준은 다음과 같이 말합니다.

  1. 물체의 숯 같은 물체는 basic_string연속적으로 보관해야한다. 즉, 어떤 basic_string대상 에 대해서도 s, 정체성 &*(s.begin() + n) == &*s.begin() + nn그러한 모든 가치를 보유해야한다 0 <= n < s.size().

  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    반환 값 : *(begin() + pos)if pos < size(), 그렇지 않은 경우는 CharTvalue 형의 객체에의 참조 CharT(). 참조 된 값은 수정되지 않아야한다.


  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    반환 값 : 포인터 P 등이 p + i == &operator[](i)각각 i에서 [0,size()].

비 const 문자 포인터를 얻는 방법은 여러 가지가 있습니다.

1. C ++ 11의 연속 저장소를 사용하십시오.

std::string foo{"text"};
auto p = &*foo.begin();

찬성

  • 간단하고 짧은
  • 빠름 (복사본이없는 방법 만)

단점

  • 최종 '\0'메모리는 메모리가 아닌 메모리의 일부일 필요는 없습니다.

2. 사용 std::vector<CharT>

std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();

찬성

  • 단순한
  • 자동 메모리 처리
  • 동적

단점

  • 문자열 복사가 필요합니다

3. 컴파일 시간이 일정하고 충분한 std::array<CharT, N>경우 if를 사용하십시오.N

std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

찬성

  • 단순한
  • 스택 메모리 처리

단점

  • 공전
  • 문자열 복사가 필요합니다

4. 자동 스토리지 삭제를 통한 원시 메모리 할당

std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);

찬성

  • 작은 메모리 공간
  • 자동 삭제
  • 단순한

단점

  • 문자열 복사가 필요합니다
  • 정적 (동적 사용에는 더 많은 코드가 필요함)
  • 벡터 또는 배열보다 적은 기능

5. 수동 처리를 통한 원시 메모리 할당

std::string foo{ "text" };
char * p = nullptr;
try
{
  p = new char[foo.size() + 1u];
  std::copy(foo.data(), foo.data() + foo.size() + 1u, p);
  // handle stuff with p
  delete[] p;
}
catch (...)
{
  if (p) { delete[] p; }
  throw;
}

찬성

  • 최대 '제어'

범죄자

  • 문자열 복사가 필요합니다
  • 오류에 대한 최대 책임 / 감수성
  • 복잡한

9

많은 기능을 가진 API를 입력으로 사용하고 char*있습니다.

이런 종류의 문제에 직면하기 위해 작은 수업을 만들었고 RAII 관용구를 구현했습니다.

class DeepString
{
        DeepString(const DeepString& other);
        DeepString& operator=(const DeepString& other);
        char* internal_; 

    public:
        explicit DeepString( const string& toCopy): 
            internal_(new char[toCopy.size()+1]) 
        {
            strcpy(internal_,toCopy.c_str());
        }
        ~DeepString() { delete[] internal_; }
        char* str() const { return internal_; }
        const char* c_str()  const { return internal_; }
};

그리고 당신은 그것을 다음과 같이 사용할 수 있습니다 :

void aFunctionAPI(char* input);

//  other stuff

aFunctionAPI("Foo"); //this call is not safe. if the function modified the 
                     //literal string the program will crash
std::string myFoo("Foo");
aFunctionAPI(myFoo.c_str()); //this is not compiling
aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string 
                                                //implement reference counting and 
                                                //it may change the value of other
                                                //strings as well.
DeepString myDeepFoo(myFoo);
aFunctionAPI(myFoo.str()); //this is fine

기존 문자열 DeepString의 깊고 독특한 사본 (복사 DeepString불가능)을 생성하기 때문에 클래스를 호출했습니다 .


3
이 명명 규칙을 피할 것입니다. c_str()에 의해 사용되는 std"C-문자열"없습니다 "const를 문자열"의 약자이며, str()항상 반환 std::basic_string하지 char*(예를 들어 std::stringstream::str())
bcrist

8
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

1
... 공상하지만 정말 열심히 이해 보이는 간단한은 IMO 최고
나임 A. 말릭

4
strcpy (), malloc (), length () 및 c_str ()은 기본 함수이며 이에 어려운 것은 없습니다. 메모리를 할당하고 복사하기 만하면됩니다.
cegprakash

5
예 기능은 기본적인하지만 당신은 트위스트 한 스파게티 그릇 또는 1 라이너 프랑켄슈타인의 괴물 :처럼 그들을 구부러진
나임 A. 말릭

4
예, 기능은 기본이지만 프로그래밍 언어를 다룰 때 기억하십니까? 일부 설명은 더 설명하고 신생 생물이 예를
들어이

2
@ cegprakash : malloc ()이있을 때마다 free ()가 있어야합니다. 그렇지 않으면 코드가 메모리를 누출하여 답변의 솔루션도 누출됩니다. 필요한 할당 해제를 암시하지 않고 메모리를 할당하는 것은 그러한 질문에 대한 나쁜 습관입니다.
Striezel

7

이것을 참조하십시오 :

string str1("stackoverflow");
const char * str2 = str1.c_str();

그러나이 경우 a가 반환 const char *됩니다.

A의 char *사용 strcpy다른에 복사 할 char배열입니다.


23
안녕하세요, 귀하가 게시 한 내용은 이미 5 세 질문에 대한 다른 답변에서 여러 번 언급되었습니다. 오래된 질문에 대답하는 것이 좋지만 새로운 정보를 추가하는 경우에만 가능합니다. 그렇지 않으면 소음 일뿐입니다.
Mat

7
개인적으로, 나는 단순함에 감사한다.
TankorSmash

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.