본문 바로가기

메모장/C++

[C, C++] 표준 입출력 실험 (scanf)

입력 포맷

%[*][폭(width)][한정자(modifiers)]타입(type)

ex)
%d - 정수 입력
%*d - 정수 입력 1번 무시
%10s - 문자를 10개 까지만 입력받음
%10s%*s -문자를 10개 입력 받고 나머지 문자열은 버림
%[^\n] - \n이 나오기 전까지 문자열을 읽어 들인다. 이 경우 공백과 tab을 무시하지 않는다.

1. 문자

#include <iostream>

void manyChar() {
	char c1, c2, c3, c4, c5;

	scanf_s("%c", &c1);
	scanf_s("%c", &c2);
	scanf_s("%c", &c3);
	scanf_s("%c", &c4);
	scanf_s("%c", &c5);

	printf("%c%c%c%c%c", c1, c2, c3, c4, c5);
}

'a','b','c','d','e' 각각의 문자가 하나씩 입력된다.

Enter 키를 누르면 한꺼번에 입력이 된다.
나머지 문자들은 입력 버퍼에 남아있다가 다음 문자를 읽어 들일때 순서대로 입력된다.

입력을 위해 입력한 개행문자 '\n'도 읽어 들인다. 
위는 c5에 '\n'이 들어간 상태이다.

공백도 마찬가지로 읽어 들인다. 다른 아스키 코드도 마찬가지.
c2와 c4에 ' '이 들어갔다.

c2와 c4에 '\n'이 들어간 경우이다.

C/C++에서 char변수는 1byte이다.
한글같은 유니코드는 2byte의 크기를 가지고 있어서 char변수 2개가 필요하다.

만약 출력부분을 다음과 같이 바꾼다면,

printf("%c %c %c %c %c", c1, c2, c3, c4, c5);

공백으로 인해 유니코드 문자가 완성되지 못하고 예상치 못한 값이 출력된다.

 

입력부분을 다음과 같이 바꿔보겠다.

	scanf_s("%c\n", &c1);
	scanf_s("%c\n", &c2);
	scanf_s("%c\n", &c3);
	scanf_s("%c\n", &c4);
	scanf_s("%c\n", &c5);

abcde를 입력했는데, 결과가 나오지 않는다. 이유는 당연하게도 '\n' 때문이다.

scanf는 입력 포멧에 형식 지정자와 공백 문자이외에 다른 값이 들어가 있으면,
stdin에서 다음 문자를 읽은 후 적혀있는 값과 같다면,
무시한 후 형식 문자열의 다음 문자들을 처리하고,
다르다면 함수를 종료하고 stdin에는 읽히지 않은 문자들이 남아 있게 된다.

scanf는 입력 포멧의 앞부분 부터 처리하므로,
c1에 'a'가 들어간 후에 다음 문자가 '\n'이 아니기 때문에, 함수가 종료되고,
다음 scanf 호출 때, 남아있는 bcde를 처리한다.
'e'를 처리하고 다음 문자 '\n'이 입력포멧에 적혀있는 '\n'과 일치 하기 때문에,
\n이 무시돼서 마지막 scanf함수가 종료되지 않기 때문에 결과가 나오지 않는것이다.

 

	scanf_s("1%c", &c1);
	scanf_s("2%c", &c2);
	scanf_s("3%c", &c3);
	scanf_s("4%c", &c4);
	scanf_s("5%c", &c5);

코드를 이렇게 바꿀경우

다음과 같이 abcde앞에 있는 12345가 무시되고 abcde만 입력된다.

이 포멧을 지키지 않으면,

각 scanf함수가 12345를 처리하다가 종료되어 버렸기 때문에, c1~c5에는 아무런 값도 들어가 있지 않다.
따라서 출력시 쓰레기 값이 나온다.

 

void manyChar3() {
	char c1, c2, c3, c4, c5;

	scanf_s("%c%c%c%c%c", &c1, &c2, &c3, &c4, &c5);

	printf("%c%c%c%c%c", c1, c2, c3, c4, c5);
}

여러개의 문자, 문자열을 하나의 scanf함수로 입력 받을 시 위와 같이 작성하면 오류가 난다.

정수와 다르게 문자열은 주소 뒤에 길이를 설정해 주어야한다.

단일 문자, 문자열을 입력 받을 때에는 뒷부분을 생략해도 상관없지만,

여러개의 문자를 입력 받을 때에는 주소뒤에 또 주소를 적을 경우, 그 값을 길이로 인식해 런타임 에러가 난다.

void manyChar4() {
	char c1, c2, c3, c4, c5;

	scanf_s("%c%c%c%c%c", &c1, 1, &c2, 1, &c3, 1, &c4, 1, &c5, 1);

	printf("%c%c%c%c%c", c1, c2, c3, c4, c5);
}

다음과 같이 문자의 주소 뒤에, 입력받을 문자열의 길이를 적어줘야한다.

 

2. 문자열

#include <iostream>

void string() {	
	char *s1, *s2;

	s1 = new char[10]; // 초기화가 필요하다
	scanf_s("%s", s1); // 문자열의 경우 이미 주소 (char*)
	printf("%s\n", s1);

	s2 = new char[10];
	scanf_s("%s", s2);
	printf("%s\n", s2);
}

 

Enter키를 기준으로 입력을 받는다. 개행문자(\n)는 포함되지 않음.

Space Bar를 기준으로도 나눠진다. 마찬가지로 공백은 입력되지 않음.

공백을 입력 받고 싶다면 다음과 같이 작성한다.

void string2() {
	char *s1;

	s1 = new char[20];
	scanf_s("%[^\n]", s1);

	printf("%s", s1);
}

공백까지 포함하여 s1에 입력된 모습이다.

'메모장 > C++' 카테고리의 다른 글

[C++/etc] 키워드 사전 (수정중)  (0) 2022.11.23
[C++] 스마트 포인터 메모  (0) 2022.11.17
[c++] async 테스트  (0) 2021.12.15
[C++] 구조체의 크기 (size of struct)  (3) 2020.11.18
C++/STL List를 순회하는 방법  (0) 2019.05.24