오늘 2차원 문자 배열 문제를 풀면서 삽질 참 여러번 했다.
이전 같으면 그냥 char 타입을 담는 배열의 배열을 만들었겠지만 이번엔 좀 다른 시도를 해보고 싶었다.
그래서 string 타입을 담는 배열로 만들어봤는데 에러가 떴다.
std::string arr[8];
for(int i=0; i<8; i++) {
for(int j=0; j<8; j++) {
if((i+j) %2 == 0) {
arr[i][j] = 'B';
} else {
arr[i][j] = 'W';
}
}
}
그래서
arr[i] = "WBWBWBWB";
이런 식으로 string 변수에 그냥 문자열을 통째로 넣어주는 식으로 해결했다.
문자 하나하나 string 변수에 넣고 싶으면 arr[i].push_back('W') 이런 식으로 가능하다.
그렇다면 string 타입 변수는 operator[]로 주소에 접근이 불가능한 걸까?
NO
혹시 몰라 테스트를 해봤는데 이건 에러 없이 잘 작동한다.
string test_s[3] = { "abc", "def", "ghi" };
test_s[0][0] = 'F';
cout << test_s[0];
string 타입 원소의 원하는 인덱스에 값을 넣었다. 이게 가능하다.
string 타입 변수도 다른 변수와 마찬가지로 operator[]를 통해 주소에 접근해서 값을 변경할 수 있다.
그럼 왜 위에서는 에러가 뜬 걸까?
일단 arr 각각의 원소(string 타입)은 capacity는 기본 15로 할당되어있지만 size는 0이다.
한줄한줄 디버깅을 통해 알아냈다.
에러가 말해주길 범위 밖에 접근했단다.
cpp reference를 보니 빈 string를 생성하면 size 0이고 begin과 end가 같은 상태이다.
의도치 않은 것들이 메모리에 차있을텐데 size 0인 상태에서 원소에 접근 가능하다면 그것도 위험한 일일 것이다.
정확히 어떻게 작동하는가?
std::basic_string의 operator[]를 살펴봤다.
(1) reference operator[]( size_type pos );
(2) const_reference operator[]( size_type pos ) const;
c++20 까지는 이렇게 정의되어 있다.
정의만 봐서는 "reference 타입 리턴하면 값 바꿀 수 있잖아?" 이런 생각이 든다.
If pos == size(), a reference to the character with value CharT() (the null character) is returned.
For the first (non-const) version, the behavior is undefined if this character is modified to any value other than CharT() .
If pos > size(), the behavior is undefined.
c+11부터는 이렇게 된다고 설명이 되어있다.
해석해보면
pos==size()일 때 const_reference 리턴 타입이면 널 문자 값을 가지는 문자의 레퍼런스를 리턴한다.
reference 리턴 타입이면(다른 값으로 수정하려고 하면) 어떻게 할지 정의가 안되어있다.
pos > size()이면 역시 어떻게 할지 정의되어 있지 않다.
오류가 났던 코드에서 맨 처음에는 size가 0인 string에게 매개변수 pos 값으로 0을 넘겨준다.
pos==size() 상황인데 const_reference 타입을 리턴하면 값을 바꿀 수가 없다.
reference 타입을 리턴한다면 좋을텐데 값을 수정하려고 하면 함수 내용이 없다. 당연히 의미 있는 리턴도 없다.
그러니 빈 string에 인덱스로 접근해서 값을 바꿀 수가 없었던 거다.
참고로 int 배열은 빈 배열이어도 임의의 원소에 접근해 값을 바꾸는 게 가능하다.
int main() {
int arr[4];
arr[0] = 3;
cout << arr[0];
}
정리
빈 string의 인덱스 주소에 접근해 값을 변경하는 건 불가능하다.
빈 string에 값을 넣으려면 문자열을 대입하거나 push_back()으로 문자 하나씩 넣어야 한다.
인용
'백준 > 이걸 몰랐네' 카테고리의 다른 글
예제 입출력은 분명 맞는데 틀렸다고 할때 대처법 (0) | 2020.08.31 |
---|---|
배열을 fill()로 초기화해주자. (0) | 2020.08.31 |
백준 11720번 숫자의 합(문자로 안 받고 정수로 받기) (0) | 2020.08.30 |
[c++]리스트 sort 하는 방법 (0) | 2020.08.29 |
cin과 scanf는 공백 문자를 어떻게 인식하는가 (0) | 2020.08.25 |