your programing

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

lovepro 2020. 9. 28. 09:47
반응형

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


어떻게 변환 할 수 있습니다 std::stringA와 char*const char*?


std::string필요한 함수에 a 를 전달 하려면 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()

주어진 말 ...

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이 아닌 포인터가 보장되지만 해당 포인터를 역 참조해서는 안됩니다.
  • &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()같습니다.
      • non-의 경우 const x이것은 non- 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()있지만 사람들은 때때로 다음과 같은 이유로 사용하지 않습니다.

  • using .data()은 소스 코드를 읽는 다른 프로그래머에게 데이터가 ASCIIZ가 아님 (대신 문자열을 사용하여 데이터 블록 (때로는 실제로 텍스트가 아님)을 저장하는 데 사용함) 또는이를 전달하고 있음을 전달합니다. "바이너리"데이터 블록으로 처리하는 또 다른 함수입니다. 이것은 다른 프로그래머의 코드 변경이 계속해서 데이터를 적절하게 처리하도록하는 데 중요한 통찰력이 될 수 있습니다.
  • C ++ 03 만 해당 : stringNUL 종료 버퍼를 준비하기 위해 구현에서 추가 메모리 할당 및 / 또는 데이터 복사를 수행해야 할 가능성이 약간 있습니다.

추가 힌트로, 함수의 파라미터는 (필요한 경우 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*생성 해야하는 다른 이유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의 데이터를 호출자를 위해 어딘가에 복사하고 싶습니다 )
    • be careful not to return a pointer that may be dereferenced by the caller after a local string variable to which that pointer pointed has left scope
    • some projects with shared objects compiled/linked for different std::string implementations (e.g. STLport and compiler-native) may pass data as ASCIIZ to avoid conflicts

Use the .c_str() method for const char *.

You can use &mystring[0] to get a char * pointer, but there are a couple of gotcha's: you won't necessarily get a zero terminated string, and you won't be able to change the string's size. You especially have to be careful not to add characters past the end of the string or you'll get a buffer overrun (and probable crash).

There was no guarantee that all of the characters would be part of the same contiguous buffer until C++11, but in practice all known implementations of std::string worked that way anyway; see Does “&s[0]” point to contiguous characters in a std::string?.

Note that many string member functions will reallocate the internal buffer and invalidate any pointers you might have saved. Best to use them immediately and then discard.


C++17

C++17 (upcoming standard) changes the synopsis of the template basic_string adding a non const overload of data():

charT* data() noexcept;

Returns: A pointer p such that p + i == &operator for each i in [0,size()].


CharT const * from std::basic_string<CharT>

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

CharT * from std::basic_string<CharT>

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

C++11

CharT const * from std::basic_string<CharT>

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

CharT * from std::basic_string<CharT>

From C++11 onwards, the standard says:

  1. The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0 <= n < s.size().

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

    Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type CharT with value CharT(); the referenced value shall not be modified.


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

    Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].

There are severable possible ways to get a non const character pointer.

1. Use the contiguous storage of C++11

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

Pro

  • Simple and short
  • Fast (only method with no copy involved)

Cons

  • Final '\0' is not to be altered / not necessarily part of the non-const memory.

2. Use std::vector<CharT>

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

Pro

  • Simple
  • Automatic memory handling
  • Dynamic

Cons

  • Requires string copy

3. Use std::array<CharT, N> if N is compile time constant (and small enough)

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

Pro

  • Simple
  • Stack memory handling

Cons

  • Static
  • Requires string copy

4. Raw memory allocation with automatic storage deletion

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

Pro

  • Small memory footprint
  • Automatic deletion
  • Simple

Cons

  • Requires string copy
  • Static (dynamic usage requires lots more code)
  • Less features than vector or array

5. Raw memory allocation with manual handling

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;
}

Pro

  • Maximum 'control'

Con

  • Requires string copy
  • Maximum liability / susceptibility for errors
  • Complex

I am working with an API with a lot of functions get as an input a char*.

I have created a small class to face this kind of problem, I have implemented the RAII idiom.

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_; }
};

And you can use it as:

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

I have called the class DeepString because it is creating a deep and unique copy (the DeepString is not copyable) of an existing string.


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

Just see this :

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

However , note that this will return a const char *.For a char *, use strcpy to copy it into another char array.


Try this

std::string s(reinterpret_cast<const char *>(Data), Size);

참고URL : https://stackoverflow.com/questions/347949/how-to-convert-a-stdstring-to-const-char-or-char

반응형