C++ Language/C++ Errors

<C++ - Errors> String 멤버함수 find를 사용할 때 에러가 나는 이유

WooJi 2022. 8. 17. 18:52
반응형

안녕하세요.

WooJi입니다.

C++에 대한 첫 글이네요! 여러 일정이 많다 보니 블로그를 자꾸 미루게 됩니다... 하핳

날씨가 굉장히 덥습니다. 모두 건강 조심하시길 바랍니다.

 

오늘은 코딩하다가 find함수를 사용할 때 에러가 발생해서 화가 나있다가 해결을 하여 여러분께 도움이 될까 해 써봅니다.


우선 주의할 것이 있습니다.

find 함수는 string 객체의 멤버 함수입니다.  string 객체를 생성하고 멤버 함수를 사용하기 위해서는 문자열 헤더 파일을 반드시 포함시켜야 하겠죠? 여기서 에러가 발생할 수 있습니다. 매우 기본적인 에러지만 가끔 잊어버릴 때가 있습니다.

  • #include <string>을 작성했는지 확인!

두 번째로 에러가 발생하는 이유는  find함수를 알아야 나오게 됩니다.

 

그래서 find함수에 대해 알아봅시다.

find함수 : 문자열에서 어떠한 문자나 문자열을 찾는 함수

 

find 함수는 2가지로 사용될 수 있습니다.

1. int find(const string& str)  형태

  하나의 인자에 찾고 싶은 문자나 문자열(str)을 넣으면 찾을 문자열의 처음부터 str을 검색하여 발견한 처음 인덱스를 리턴하고, 없으면 -1을 리턴합니다. 

#include <iostream>
#include <string>
using namespace std;
int main(){
    string a = "Hello";
    int num = a.find('l');
    cout << num << endl;

    num = a.find('k');
    cout << num << endl;
}

문자열 a에는 아래 그림과 같이 저장이 되어 있을 겁니다. 배열과 마찬가지로 인덱스가 0부터 시작하고요.

위 코드처럼 작성을 해보면 6번 줄에서 문자열 a에서 l를 찾습니다. 그런데  Hello에는 l이 두 개인데  2가 출력됩니다?? 이는 처음 문자의 인덱스를 리턴하기 때문입니다. 처음 나오는 l의 인덱스가 2이기 때문에 2를 출력하                                                                              고 뒤에는 l이 있든 없든 상관하지 않고 2를 반환하는 것이죠. 

 

9번 줄처럼 작성하면 문자열 a에서 k를 찾습니다. 그러나 k가 없기 때문에 -1을 반환합니다. 따라서 -1이 실제로 출력되는 것을 알 수 있습니다. 

 

 

 

2. int find(const string& str, int pos)  형태

  각 인자에 순서대로 찾고 싶은 문자열(str)과 찾을 문자열에서의 위치(pos)를 전달하면 문자열의 pos 위치부터 str을 검색하여 발견한 처음 인덱스를 리턴하고, 없으면 -1을 반환합니다.

#include <iostream>
#include <string>
using namespace std;
int main(){
    string a = "Hello";
    int num = a.find("llo",1);
    cout << num << endl;

    num = a.find('k',3);
    cout << num << endl;
}

 1번과 마찬가지이나 인자가 하나 더 추가된 것뿐입니다. 6번 줄처럼 작성하면 1번 위치 즉, e부터 llo라는 문자열을 찾는다는 의미입니다. 따라서 l이 시작되는 인덱스인 2가 출력되는 것입니다.

 

9번 줄과 같이 작성할 경우 3번 위치(두 번째 l)부터 k를 찾는 것이지만 k가 존재하지 않기 때문에 -1을 반환합니다. 

   

결론부터 말하자면 에러는 찾기 바라는 문자가 없을 때 -1을 반환하면서 발생할 수 있습니다.

 

코딩 책의 실습 문제 중에 문자열을 입력받아 문자열 내의 a 개수를 찾는 문제가 있어 아래와 같이 작성했습니다.

#include <iostream>
using namespace std;
#include <string>

int main(){
    string a;
    cout <<"문자열 입력>>";
    getline(cin,a);             //아무 영문 문자열을 입력받음
    int check = 0, index = 0;   //a 개수를 세어줄 check, a의 위치를 나타내는 index 변수 선언
    while (1)                   
    { 
        if (a.find('a',index) > 0 )         //문자열에 a가 있으면
        {
            ++check;                        //개수를 1 더하고
            index = a.find('a',index)+1;    //인덱스를 1 더해 다음으로 넘기기
        }else{
            break;
        }
    }
    cout << check << endl;
}

 

실행시켰더니 무한루프에 걸렸는지 출력을 안 하는데 틀린 것은 없는 것 같죠,,,? a를 찾지 못하면 -1을 반환할 테니 0보다 작아서 break 하겠지라고 생각해 위와 같이 짰습니다.

 

문제는 문자열에서 a를 찾지 못할 때 -1을 반환한다는 것이었습니다. 

공식적인 C++문서에 그 이유가 있었습니다. 

이유는 find함수는 해당 문자열을 찾지 못하면 -1을 반환하는 것이 맞지만 정확히는 string::npos를 반환한다는 것이었습니다. 

string::npos를 이해하기 위해서는 size_t라는 개념을 알아야 합니다. 

size_t : 모든 객체의 크기를 의미하며 우리가 흔히 아는 sizeof 연산자의 반환형이라고 합니다. 
string::npos : string 멤버 함수에서 찾지 못했을 때 반환하는 static 멤버

size_t가 unsigned int형인데 string::npos는 size_t의 최댓값인 것이 문제입니다. unsigned int형이면 부호가 없는 정수형인데 이 자료형의 최댓값이라면 당연히 0보다 큰 값입니다. 이를 통해 위 코드의 if 문 조건을 잘못 작성했음을 알 수 있습니다. 문자열이 있을 때를 반환값이 0보다 클 때로 두었으니 while문이 끝나지 않아 무한루프에 걸리는 것이었습니다.

 

그런데 이상하죠? 분명 찾지 못하면 -1을 반환했는데 말이죠,,,,

 

This constant is defined with a value of -1, which because size_t is an unsigned integral type,
it is the largest possible representable value for this type.

실제 C++ 문서의 string::npos에 대한 문장입니다. size_t가 unsigned int형이고 size_t의 가장 큰 값이 string::npos다. 라네요,,,

아마 size_t가 모든 자료형의 크기를 대표하다 보니 최댓값이 일정한 상수로 정해진 것이 아니기 때문에 -1로 정의한 것 같습니다. 

결론적으로 -1을 반환하는 것이 맞지만 그렇다고 음수는 아니다 정도로 이해하면 될 것 같습니다. 해서 '0보다 작다'를 조건에 넣기보다 string::npos를 애용하는 걸로,,,

#include <iostream>
using namespace std;
#include <string>

int main(){
    string a;
    cout <<"문자열 입력>>";
    getline(cin,a);             //아무 영문 문자를 입력받음
    int check = 0, index = 0;   //a 개수를 세어줄 check, a의 위치를 나타내는 index 변수 선언
    while (1)                   
    { 
        if (a.find('a',index) != string::npos )         //문자열에 a가 있으면
        {
            ++check;                        //개수를 1 더하고
            index = a.find('a',index)+1;    //인덱스를 1 더해 다음으로 넘기기
        }else{
            break;
        }
    }
    cout << check << endl;
}

 

아까 코드도 if문의 조건을 string::npos를 이용하여 바꾸었더니 잘 되는 것을 알 수 있습니다.

  • 찾지 못하면 string::npos 를 기억!!

더 궁금하신 분들은 <참고 문서>란의 세 개의 문서를 읽어보시기 바랍니다. 


오늘은 string 객체의 멤버 함수 find에 대해 진득하게 알아보았습니다. 코딩은 이렇게 에러 나면 해결해나가는 맛에 하는 것 같습니다. 다들 코딩에 재미 붙여보시길 바랍니다.

다음 글에서 뵙도록 하겠습니다~


내용에 오류가 있을 수 있음에 양해 부탁드리며 오류를 발생하시면 댓글 등으로 꼭 알려주시기 바랍니다.

또 읽다가 모르는 점이 있으면 언제든 댓글 달아주세요.


<참고 문서>

https://cplusplus.com/reference/string/string/find/

 

string::find - C++ Reference

buffer (3)size_t find (const char* s, size_t pos, size_type n) const;

cplusplus.com

 

 

https://cplusplus.com/reference/string/string/npos/

 

string::npos - C++ Reference

public static member constant <string> static const size_t npos = -1; Maximum value for size_t npos is a static member constant value with the greatest possible value for an element of type size_t. This value, when used as the value for a len (or sublen) p

cplusplus.com

https://cplusplus.com/reference/cstddef/size_t/

 

size_t - C++ Reference

type <cstddef> <cstdio> <cstdlib> <cstring> <ctime> <cwchar> size_t Unsigned integral type Alias of one of the fundamental unsigned integer types. It is a type able to represent the size of any object in bytes: size_t is the type returned by the sizeof ope

cplusplus.com

 

<참고 도서>

명품 C++ 프로그래밍,  황기태 지음, 194쪽 참고

반응형