null이 포함 된 std :: string을 어떻게 구성합니까? 생성하려면 std::string my_string(“a\0b”); 결과

다음과 같은 줄로 std :: string을 생성하려면

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 이전

문제는 입력이 C- 문자열이라고 가정 하는 std::string생성자입니다 const char*. C- 문자열은 \0종료되므로 \0문자에 도달하면 구문 분석이 중지됩니다 .

이를 보완하려면 C-String이 아닌 char 배열에서 문자열을 작성하는 생성자를 사용해야합니다. 여기에는 배열에 대한 포인터와 길이의 두 매개 변수가 필요합니다.

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-String을 포함하는 내부 버퍼에 대한 포인터를 추출 할 수 있습니다 c_str().

사용에 대한 Doug T의 답변을 아래 에서 확인하십시오 vector<char>.

또한 RiaD 에서 C ++ 14 솔루션을 확인하십시오 .


답변

c 스타일 문자열 (문자 배열)과 같은 조작을 수행하는 경우 다음을 사용하는 것이 좋습니다.

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