문제

다음과 같은 선으로 std :: 문자열을 구성하려면 다음과 같습니다.

std::string my_string("a\0b");

결과 문자열 (a, null, b)에 세 문자가있는 경우 하나만 얻습니다. 적절한 구문은 무엇입니까?

도움이 되었습니까?

해결책

C ++ 14 이후

우리는 문자를 만들 수있었습니다 std::string

#include <iostream>
#include <string>

int main()
{
    using namespace std::string_literals;

    std::string s = "pl-\0-op"s;    // <- Notice the "s" at the end
                                    // This is a std::string literal not
                                    // a C-String literal.
    std::cout << s << "\n";
}

C ++ 14 이전

문제는 std::string a const char* 입력이 C- 스트링이라고 가정합니다. C- 스트링은 \0 종료되고 따라서 구문 분석이 멈 춥니 다 \0 캐릭터.

이를 보상하려면 숯 배열에서 문자열을 빌드하는 생성자를 사용해야합니다 (C- 스트링이 아님). 배열에 대한 포인터와 길이의 두 매개 변수가 필요합니다.

std::string   x("pq\0rs");   // Two characters because input assumed to be C-String
std::string   x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.

참고 : C ++ std::string ~이다 아니다 \0-종료 (다른 게시물에서 제안 된대로). 그러나 방법과 함께 C- 스트링을 포함하는 내부 버퍼에 대한 포인터를 추출 할 수 있습니다. c_str().

또한 체크 아웃하십시오 Doug T의 답변 아래에서 a vector<char>.

또한 체크 아웃하십시오 리아드 C ++ 14 용액 용.

다른 팁

C 스타일 문자열 (char 배열)으로 조작하는 경우 사용을 고려하십시오.

std::vector<char>

C- 스트링을 처리하는 것과 같은 방식으로 배열처럼 취급 할 수있는 자유가 더 있습니다. copy ()를 사용하여 문자열로 복사 할 수 있습니다.

std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());

그리고 C- 스트링을 사용할 수있는 동일한 장소에서 사용할 수 있습니다.

printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';

그러나 당연히 C- 스트링과 같은 문제로 고통받습니다. 널 터미널을 잊어 버리거나 할당 된 공간을 지나서 쓸 수 있습니다.

나는 모른다 그런 일을하고 싶지만 이것을 시도하십시오.

std::string my_string("a\0b", 3);

사용자 정의 리터럴이 C ++에 추가되는 새로운 기능은 무엇입니까? 우아한 대답을 제시합니다 : 정의

std::string operator "" _s(const char* str, size_t n) 
{ 
    return std::string(str, n); 
}

그런 다음이 방법으로 문자열을 만들 수 있습니다.

std::string my_string("a\0b"_s);

또는 그렇게 :

auto my_string = "a\0b"_s;

"구식"방법이 있습니다.

#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string

그런 다음 정의 할 수 있습니다

std::string my_string(S("a\0b"));

다음이 작동합니다 ...

std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');

당신은 이것에주의해야합니다. 'b'를 숫자 문자로 바꾸면 대부분의 메소드를 사용하여 잘못된 문자열을 조용히 생성합니다. 보다: C ++ 문자 리터럴에 대한 규칙 탈출 문자.

예를 들어, 나는 프로그램의 중간 에이 무고한 스 니펫을 떨어 뜨 렸습니다.

// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
    std::cerr << c;
    // 'Q' is way cooler than '\0' or '0'
    c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
    std::cerr << c;
}
std::cerr << "\n";

이 프로그램은 다음과 같습니다.

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

그것은 나의 첫 번째 프린트 진술, 두 번의 인쇄 문자, 그리고 새로운 라인, 그리고 내부 메모리에 무언가가 뒤 따른다. 나는 방금 덮어 쓰고 인쇄하여 그것을 덮어 썼다는 것을 보여준다). 무엇보다도, 이것을 컴파일하는 것조차도 철저하고 장악 GCC 경고 나에게 잘못된 것을 나타내지 않았고 Valgrind를 통해 프로그램을 실행하는 것은 부적절한 메모리 액세스 패턴에 대해 불평하지 않았습니다. 다시 말해, 현대적인 도구는 완전히 감지 할 수 없습니다.

훨씬 더 단순 하게이 동일한 문제를 얻을 수 있습니다. std::string("0", 100);, 그러나 위의 예는 조금 까다 롭기 때문에 무엇이 잘못되었는지보기가 어렵습니다.

다행히 C ++ 11은 초기화 목록 구문을 사용하여 문제에 대한 좋은 솔루션을 제공합니다. 이렇게하면 문자 수를 지정하지 않아도됩니다 (위에 표시된대로 잘못 수행 할 수 있음). 이스케이프 숫자를 결합하지 않습니다. std::string str({'a', '\0', 'b'}) 배열을 취하는 버전과 달리 모든 문자열 컨텐츠에 안전합니다. char 그리고 크기.

C ++ 14에서는 이제 리터럴을 사용할 수 있습니다

using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3

std :: 벡터를 사용하는 것이 좋습니다u003Cchar> 이 질문이 단지 교육 목적을위한 것이 아니라면.

Anonym의 답변은 우수하지만 C ++ 98에도 비 Macro 솔루션이 있습니다.

template <size_t N>
std::string RawString(const char (&ch)[N])
{
  return std::string(ch, N-1);  // Again, exclude trailing `null`
}

이 기능으로 RawString(/* literal */) 동일한 문자열을 생성합니다 S(/* literal */):

std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;

또한 매크로에는 문제가 있습니다. 표현은 실제로 std::string 서면으로, 따라서 간단한 할당 개시 화를 위해 예를 들어 사용할 수 없습니다.

std::string s = S("a\0b"); // ERROR!

... 따라서 사용하는 것이 바람직 할 수 있습니다.

#define std::string(s, sizeof s - 1)

분명히 프로젝트에서 하나 또는 다른 솔루션 만 사용하여 적절하다고 생각하는 모든 것을 불러야합니다.

나는 그것이 오랜 시간이라는 것을 알고 있습니다. 그러나 비슷한 문제가있는 사람은 다음 코드에 관심이있을 수 있습니다.

CComBSTR(20,"mystring1\0mystring2\0")

STD :: 문자열의 거의 모든 구현은 무효가 종결되므로 아마도 그렇게해서는 안됩니다. "A 0B"는 자동 널 터미네이터 (A, NULL, B, NULL)로 인해 실제로 4 자 길이입니다. 정말로이 작업을 수행하고 STD :: String의 계약을 중단하려면 다음을 수행 할 수 있습니다.

std::string s("aab");
s.at(1) = '\0';

그러나 당신이 그렇게한다면, 모든 친구들이 당신을 비웃을 것이고, 당신은 결코 진정한 행복을 찾지 못할 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top