순서

I. String이란?

II. 문자열 입력받기
1. 문자열 정의 및 변경
2. 문자열 입력받기

III. 활용하기
1. std::string 사용법
2. 문제에서의 입력 포맷들

+) 애먹었던 배열 특정 값 채우기


I. String이란?

자료형 char은 아스키코드로 지정된 하나의 문자를 나타낸다.('a')

문자열(string)은 말 그대로 문자들의 집합이다.("abcd")

이 문자열을 처리하는 데에는 3가지가 있다.

 

  char str[] or char str[buf] char * str (c언어)
const char* str (c++)
std::string
장 점 scanf, cin등 입력받기 가능 문자열 전체로 변수 수정 가능 다 된다.
단 점 변수 수정시 글자 하나하나
변경해야함.
scanf, cin등 입력받기 불가
(주소 접근이기 때문)
-> 동적할당 필요하다.
사용 방식에 따라 속도차이
및 메모리 차이 발생

 


II. 문자열 입력받기


1. 문자열 정의 및 변경

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

char arrstr[] = "hello1";
const char* ptrstr = "hello2";
std::string stdstr = "hello3";

int main()
{
    cout<<arrstr<<ptrstr<<stdstr<<endl;
    
    //arrstr = "hello4"; // ERROR 하나하나 접근해서 바꿔야함!
    ptrstr = "hello5";
    stdstr = "hello6";
    
    cout<<arrstr<<ptrstr<<stdstr<<endl;
    
    return 0;
}

 


2. 문자열 입력받기

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

char arrstr[] = "hello1";
const char* ptrstr = "hello2";
std::string stdstr = "hello3";

int main()
{
    cout<<arrstr<<ptrstr<<stdstr<<endl;
    
    cin>>arrstr; // OK
    //cin>>ptrstr; // ERROR
    cin>>stdstr; // OK
    
    cout<<arrstr<<ptrstr<<stdstr<<endl;
    
    return 0;
}

 


III. 활용


1. std::string 사용법

std::string(표준 문자열)은 자료형이 아닌 클래스이다.
<string> 헤더가 필요하다.

따라서 우리가 생각하는대로 컨트롤할 수 있다는게 큰 장점이다.
예를 들면 다음과 같이 가능하다.

#include <string>

//선언
std::string mystr;

int main()
{
    //정의
    mystr = "hello1";
    
    //c++ 표준입력
    std::cin >> mystr; //"input"을 넣었다고 해보자
    
    // 하나의 글자에 접근 (배열처럼!)
    
    char char1 = mystr[0]; // 'i'
    char char2 = mystr[1]; // 'n'
    
    // 뒤에 문자열 합치기
    mystr + " sumstr"; "input sumstr"
    
    return 0;
}

2. 문제에서의 입력 포맷들

알고리즘 문제에서는 std::string 말고 char [buf] 형도 사용하고,
속도 차이로 인해 scanf도 많이 사용하기 때문에
모두 메모해두자..


a. 연속된 문자열

입력 포맷 중 연속된 문자열을 받는 방법
ex) "(()())()())"

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string>

std::string stdstr; // scanf불가능
char chrstr[100];

void input()
{
    memset(chrstr,0,sizeof(chrstr)); // 메모리초기화
    
    //1. c++ 표준입력 (std::cin)
    std::cin>>stdstr; // stdstr에 입력
    std::cin>>chrstr; // chrstr에 입력 100글자 제한
    
    //2. c 표준입력 (scanf)
    scnaf("%s", chrstr); // chrstr에 입력 100글자 제한
    
    return;
}

 


b. 연속된 숫자열

연속된 숫자열을 문자로 받는 것은 위와 동일
BUT
연속된 숫자열을 각각 int배열로 받는 방법 (scanf "%1d")
ex) 123456 -> {1,2,3,4,5,6}

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string>

std::string stdstr; // scanf불가능
int intarr[100];

void input()
{
    memset(intarr,0,sizeof(intarr)); // 메모리초기화
    
    // c 표준입력 (scanf)
    // 해당 배열 idx주소에 값을 반복하여 하나씩 넣어준다
    for(int i=0;i<6;i++)
    {
        scanf("%1d", &intstr[i]); // 입력 : 123456
    }
    
    //intarr = {1,2,3,4,5,6}로 받아진다.
    return;
}

 


c. 2차원 문자/숫자열

2차원의 string 입력은 보통 map을 입력받을 때 나타난다.
예를 들어 이런 느낌

1번 경우   2번 경우
ooxxoox    112132
xxoxoxo    221323
oxoxxox    232424
xoxoxox    123512
ooxxoxo    434252

우리는 3가지 경우를 생각해볼 수 있다.

1. std::string stdmap[N];
2. char chrmap[N][M];
3. int intmap[N][M]; --> 2번 경우만

#include <stdio.h>
#include <iostream>
#include <string>
#include <cstring>

/* 
입력
12345
67890
12345
*/

N=3;
M=5;

std::string stdstrmap[N+2];
char chrstrmap[N+2][M+2];
int intmap[N+2][M+2];

void input()
{
    1. std::string의 경우
    // 한줄 전체를 받으니 높이 N번만 반복하면 된다.
    for(int i=0;i<N;i++)
    {
        //12345, 67890, 12345 단위로 입력됨. scanf동일
        cin<<stdstrmap;
    }
    
    2. char[][]의 경우
    for(int i=0;i<N;i++)
    {
        //12345, 67890, 12345 단위로 입력됨. scanf동일
        cin<<chrstrmap;
    }
    
    3. int[][]의 경우
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<M;j++)
        {
            scanf("%1d",&intmap[i][j]); // 하나씩 다 끊어서 받아줘야함.
        }
    }
    
    return;
}

 


+) 추가로 애먹었던 부분은 다음과 같다.

buffer를 실제 데이터보다 크게 잡을 때,
특정 값으로 초기화를 하는 과정에 있다.

만약 5x5가 실제 사용할 범위인데 내 배열이 100x100인 경우

실제 데이터가 있는 5x5부분만 초기화가 하고 싶은 경우,
배열이 2차원 이어도 주소가 연속적인 이유에서 불가능하다.

보통 아래와 같이 시도할 것이다. (std::fill() 이용)

#include <iostream>
#include <algorithm>

int chrstr[10][10];


int main()
{
    // 보통 이렇게 채울 것이다.
    
	std::fill(&chrstr[0][0], &chrstr[5][5], 9);
	
	for (int i = 0; i < 10; i++) {
		for (int j = 0; j < 10; j++) {
			std::cout << chrstr[i][j] << " ";
		}
		std::cout << std::endl;
	}
	return 0;
}

결과

심지어 마지막 (5,5)는 채워지지도 않았다.

대부분 std에서 제공하는 알고리즘들은
<vector>, <queue>등의 STL에서 사용하는 vec.end()의 멤버 함수를 대상으로 하고
end()의 위치는 마지막 주소의 다음 std::iterator이기 때문이다.
vec.begin()은 처음 주소이다.

따라서 배열을 사용할 때는 마지막 주소의 다음 주소를 넣어주어야 한다.

이 부분만 주의하자.
주로 BFS나 DFS문제
배열에 최솟값을 업데이트해야 할 때 애 먹었다.

 

+ Recent posts