bestsource

scanf를 사용하여 std:: 문자열로 읽습니다.

bestsource 2023. 11. 5. 14:50
반응형

scanf를 사용하여 std:: 문자열로 읽습니다.

제목 그대로 스캔프로 C++ 문자열을 읽을 수 있는 방법이 있는지 궁금합니다.

각 문자를 읽고 해당 문자열에 삽입할 수 있다는 것을 알고 있지만 다음과 같은 것을 원합니다.

string a;
scanf("%SOMETHING", &a);

gets()또한 작동하지 않습니다.

미리 감사드립니다!

될 수 있습니다.

char tmp[101];
scanf("%100s", tmp);
string a = tmp;

그 아래에는 어떤 상황도 없습니다.gets()사용됩니다!사용하는 것은 항상 잘못된 것입니다.gets()그리고 C11로부터 제거되고 C++14로부터 제거됩니다.

scanf()C++ 클래스를 지원하지 않습니다.그러나 결과를 저장할 수 있습니다.scanf()std::string:

편집자 참고 사항:아래 코드는 댓글로 설명한 것과 같이 잘못된 코드입니다.정확한 접근 방법은 파타토, 톰, 다니엘 트러그먼의 답변을 참조하십시오.

std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
    // ...
}

버퍼 길이를 지정하는 방법에 대해 완전히 확신할 수 없습니다.scanf()그리고 매개변수들이 어떤 순서로 가느냐에 따라 ( 매개변수들이&str[0]그리고.str.size()다시 돌려야 하는데 제가 놓쳤을 수도 있습니다..(형식 문자열로 입력합니다.그 결과는 다음과 같습니다.std::string종료 Null 문자가 포함되며 크기가 변경되지 않습니다.

물론이죠, 저는 그냥.if (std::cin >> str) { ... }하지만 그건 다른 질문입니다.

문제 설명:

의 기본 버퍼를 채울 수 있습니다.std::string사용.scanf, 하지만(!) 관리자가std::string개체는 변경 내용을 인식하지 못합니다.

const char *line="Daniel 1337"; // The line we're gonna parse

std::string token;
token.reserve(64); // You should always make sure the buffer is big enough

sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
          << " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
          << " (size = " << strlen(token.data()) << ")" << std::endl;

출력:

Managed string:  (size = 0)
Underlying buffer: Daniel (size = 6)

여기서 무슨 일이 있었던 거지?내보낸 공식 API를 통해 수행되지 않은 변경 사항을 개체가 인식하지 못합니다.

기본 버퍼를 통해 개체에 쓸 때 데이터가 변하지만 문자열 개체는 이를 인식하지 못합니다.

원래 호출을 대체할 경우:token.reseve(64)와 함께token.resize(64), 관리되는 문자열의 크기를 변경하는 호출의 결과는 달라졌을 것입니다.

const char *line="Daniel 1337"; // The line we're gonna parse

std::string token;
token.resize(64); // You should always make sure the buffer is big enough

sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
          << " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
          << " (size = " << strlen(token.data()) << ")" << std::endl;

출력:

Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)

다시 한 번 말하지만 결과는 차선입니다.출력은 맞지만 사이즈는 맞지 않습니다.

해결책:

이렇게 하려면 다음 단계를 수행합니다.

  1. 불러resize완충장치가 충분한지 확인할 수 있을 겁니다사용.#define최대 길이(이유는 2단계 참조):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
  1. 사용하다scanf"width modifier"를 사용하여 스캔한 문자열의 크기를 제한하고 반환 값(반환 값은 스캔한 토큰의 수)을 확인하는 동안:
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
  1. 안전한 방법으로 관리되는 문자열 크기를 실제 크기로 재설정합니다.
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));

아래 토막글이 작동합니다.

string s(100, '\0');
scanf("%s", s.c_str());

길이 제한이 없는 버전(입력 길이를 알 수 없는 경우)입니다.

std::string read_string() {
  std::string s; unsigned int uc; int c;
  // ASCII code of space is 32, and all code less or equal than 32 are invisible.
  // For EOF, a negative, will be large than 32 after unsigned conversion
  while ((uc = (unsigned int)getchar()) <= 32u);
  if (uc < 256u) s.push_back((char)uc);
  while ((c = getchar()) > 32) s.push_back((char)c);
  return s;
}

성능을 고려하여,getchar보다 확실히 더 빠릅니다.scanf, 그리고 std::string::reserve는 버퍼를 미리 allocate하여 잦은 재할당을 방지할 수 있습니다.

적절한 크기의 std:: 문자열을 구성하고 기본 문자 저장소로 읽을 수 있습니다.

std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));

str.resize()에 대한 호출이 중요합니다. 그렇지 않으면 std::string 개체의 길이가 업데이트되지 않습니다.이것을 지적해주신 다니엘 트러그먼씨께 감사드립니다.

(문자열에 예약된 크기와 전달된 너비 간의 순서대로 오류는 없습니다.scanf, 왜냐하면 C++11이기 때문에 std::string의 문자 데이터에 null 터미네이터가 뒤따르는 것이 보장되므로 크기+1 문자를 사용할 수 있습니다.)

int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string

언급URL : https://stackoverflow.com/questions/20165954/read-into-stdstring-using-scanf

반응형