본문 바로가기
[ CODING STUDY ]/》C언어 공부

C언어 6장(표준입출력 - getchar, putchar, _getch, _getche)

by MRG 2020. 4. 17.
728x90
반응형

안녕하세요. 저번 시간에 이야기한 숙제는 해보셨나요??
저번 시간에 했던걸 잠깐 이야기하면, 우린 변수와 상수, 그리고 연산자를 배웠습니다.
이걸 활용하여 텍스트 게임을 만들어보세요라고 했습니다. ^^ 꼭 해보셨을 거라 믿고 그럼 오늘 수업을 진행하겠습니다.

 

먼저 이렇게 코딩을 해 보도록 하겠습니다. 
저번 시간에 char 자료형으로 변수를 만드는 것도 해보셨죠? 조금 더 설명을 드리려고 합니다. 
char는 정수형 1byte == 8bit를 저장할 수 있습니다.
a에는 문자 한글자인 'A'를 대입했습니다.
b에는 65라는 숫자를 대입했습니다. 
그리고 printf에서 a에 형식과 b에 형식을 char = %c로 했습니다. 그럼 결과가 어떻게 나올까요?

 

놀랍게도 그렇게 나오게 됩니다. 그 이유는 char형으로 65라는 숫자 코드는 문자 A이기 때문입니다. 



▣ 그럼 질문해보겠습니다. 컴퓨터는 숫자만 알고 있습니다. 그럼 숫자만 아는 컴퓨터는 어떻게 문자를 표기할 수 있을까요?



예를 들어 모스부호를 한번 생각해보겠습니다.  



위키백과에서 모스 부호(Morse code)는 짧은 발신 전류(・)와 긴 발신 전류(-)을 적절히 조합하여[1] 알파벳과 숫자를 표기한 것으로 기본적인 형태는 국제적으로 비슷하다. 미국의 발명가 새뮤얼 핀리 브리즈 모스가 고안하였으며, 1844년 최초로 미국의 볼티모어와 워싱턴 D.C. 사이 전신 연락에 사용되었다.라고 합니다. 

 

출저 :https://ko.wikipedia.org/wiki/%EB%AA%A8%EC%8A%A4_%EB%B6%80%ED%98%B8

이런 모스부호를 활용하여 새로운 언어가 만들어지게 됩니다. 부호를 활용하여 언어를 조합하고 그걸로 소통을 하는 것입니다. 2차 세계대전 때에도 작전 사항을 전달할 때 도청에 위험을 방지하기 위해서 암호 형식으로 부호를 만들어내 용을 전달했습니다. 이건 컴퓨터 역사를 공부하시면 더 자세하게 알 수 있습니다.
그럼 여기에 왜 이 이야기를 하는지 아시겠나요??
바로 아스키코드를 설명하기 위해서입니다. 

 

출저 : https://namu.wiki/w/%EC%95%84%EC%8A%A4%ED%82%A4%20%EC%BD%94%EB%93%9C

위키백과에서는 아스키코드는 미국 ANSI에서 표준화한 정보교환용 7비트 부호체계이다. 000(0x00)부터 127(0x7F)까지 총 128개의 부호가 사용된다. 이는 영문 키보드로 입력할 수 있는 모든 기호들이 할당되어 있는 부호 체계입니다. 

1바이트를 구성하는 8비트 중에서 7비트만 쓰도록 제정된 이유는, 나머지 1비트를 통신 에러 검출을 위해 사용하기 때문이었다. Parity Bit라고 해서, 7개의 비트 중 1의 개수가 홀수면 1, 짝수면 0으로 하는 식의 패리티 비트를 붙여서, 전송 도중 신호가 변질된 것을 수신측에서 검출해낼 확률을 높인 것. 원시적인 CRC 체크섬이라고 할 수 있지만 당연히 이런 체크에 검출되지 않는 신호 에러도 얼마든지 생길 수 있고 현재는 더 이상 쓰이지 않는다. 현재는 8비트 문자 인코딩에서는 그냥 맨 앞 비트에 0을 붙이고 이어서 7비트가 이어지는 식의 인코딩이 일반적이다.



▣ 여기서 우리가 주목해야 할 건 모든 기호들이 할당되는 있는 부호 체계이고, 아스키코드는 7비트 부호이지만 8비트를 쓰는데 그중에 1비트는 통신 에러 검출을 위해 사용한다고 나와있습니다. 이 부분에 집중하면 좋을 거 같습니다.
쉽게 이야기하면 모스부호처럼 숫자에 따른 문자기호가 있다는 것과 char 자료형은 1 byte == 8bit라는 점입니다.
이런 공통점을 본다면 char형은 영문자 하나를 표현할 수 있다는 걸 볼 수 있습니다. 
10진수 65에 아스키코드 부호는 A라는 걸 알 수 있습니다.
결국 컴퓨터는 숫자로 모든 걸 해결한다는 걸 다시 한번 알 수 있게 되었네요.
그렇다고 해서 우리가 이 아스키코드를 다 외울 필요는 없습니다. 그리고 영문자 기존이고 우리 한글 같은 경우네는 영어보다 더 많은 글자가 필요합니다. 그럼 용량도 더 필요하겠죠? 그래서 특수한 기호나 한글이나 다른 언어 같은 경우네는 유니코드를 사용합니다. 이건 나중에 다루게 될 때 한번 이야기하도록 하겠습니다.
그렇게 해서 우리는 'A' 작은따옴표와 "ABC"큰 따옴표를 통해 아스키코드를 다 외우지 않아도 쉽게 문자로 적용할 수 있게 됩니다.
이렇게 이해를 하면 좋을 거 같습니다.
문자열을 이야기해야겠지만 문자열을 이야기하면 배열과 주소(포인터)를 이야기해야지 때문에 이정로까지만 알고 진행하겠습니다. 



▣ 그럼 이제부터 프로그램이 실행되는 중에 사용자한테 입력을 받아오는 함수를 사용해 보도록 하겠습니다. 입력을 받는 getchar함수와 출력을 하는 putchar를 사용해 보겠습니다.  

 

이렇게 먼저 코딩을 작성해보도록 하겠습니다. 그리고 디버그해보면

 

커서가 깜빡깜빡하는 걸 볼 수 있습니다. 우리가 엔터를 누리기까지 입력을 대기하는 겁니다. 무엇이든 그냥은 없습니다. 저렇게 하는 것도 그 함수 안에 저렇게 대기하는 것과 커서가 깜빡 깜박하는 것 모두 다 코딩이 되어 있기 때문에 저렇게 작동하는 것입니다. 그럼 A를 입력하고 엔터를 눌러보겠습니다.

 

 

이렇게 A와 A로 표시되는 거 볼 수 있습니다. 쉽게 이야기하면 우리가 스트림 입출력 과정을 생각해보겠습니다.

 

getchar로 엔터를 눌러 입력을 주게 되면 버퍼에 저장을 합니다. 그리고 출력을 할 때 putchar로 버퍼에 저장된 값을 받아와 출력해주게 됩니다. 그런데 여기서 중요한 건 getchar든 putchar 한 글자만 가지고 오게 된다라는 것입니다.
그럼 두 번 받아오게 해보도록 하겠습니다. 
두번 사용하면 되겠죠?

 

 

이렇게 코딩을 해보겠습니다. 처음에는 A를 입력하고 두 번째는 B를 입력해보면 AB 이렇게 나오겠죠? 한번 해보겠습니다.

 


놀랍게도 a를 입력하고 엔터를 누르면 a글자만 나오고 프로그램이 끝나는 모습을 볼 수 있습니다.
먼가 이상하죠? 분명히 a만 입력하고 엔터만 했는데 바로 다음 getchar를 입력받지 않습니다. 
그건 아까 우리가 그림에 보았던 버퍼를 생각하면 됩니다. 



a 누르고 엔터를 누르면 엔터라는 화이트 스페이스 언어가 남아 그걸 언어와 입력완료로 인식을 하고 가지고 와서 바로 putchar로 출력해주었기 때문에 이렇게 결과가 나오게 된 겁니다.
이걸 직접 눈으로 확인하려면 처음 입력할 문자를 A B 두 개를 입력해보면 알 수 있습니다.

 

이렇게 나오게 됩니다. 조금 이해가 되셨나요?

getchar는 한 글자만 버퍼에서 입력을 받아 그걸 putchar로 한글자만 꺼내오기 때문에 B라는 글자가 버퍼에 남아있습니다. 그래서 다음 getchar에는 B와 엔터 \n 화이트 스페이스가 남아있기 때문에 바로 B값을 주고 엔터를 받아 바로 출력이 되는 것 입니다. 



▣ 그럼 이걸 해결하는 방법이 무엇이 있을까요?
fflush(stdin)이라는 함수가 있지만 2015버전 이후로 사용이 불가합니다.
표준입력 버퍼를 비우겠다라는 생각하시면 됩니다. 그럼 어떻게 해결 할 수 있을까요?

 

▣ 간단하게 생각하면 첫번째 getchar에 주었던 엔터에 문자를 또 하나의 getchar로 받아와서 진행하는 방법도 있습니다.
그럼 a를 입력하면 a가 출력이되고 바로 두번째 getchar 버퍼에 엔터가 들어가고 다음으로 바로 진행이 되겠죠?
그런식으로 하는 방법도 있습니다. 

 


▣ 다음장에서 배울 scanf_s를 활용하면 됩니다.
이부분은 다음장이랑 연관해서 기억해주세요.
scanf_s 말 그대로 형식에 맞게 입력을 받는 함수라고 생각하시면 됩니다.
그래서 저렇게 형식과 변수 그리고 사이즈를 적어 줍니다.
그런데 형식앞에 공백이 있죠?
%c 앞에 공백을 추가하면 화이트 스페이스를 구분자로 인식합니다.
그래서 저렇게 엔터를 눌러도 구분해서 인식하기 때문에 바로 다음 버퍼에 저장되지 않고 b를 받아 출력할 수 있습니다.



▣ 또한 fgets(c, sizeof(c), stdin);
를 사용해서 할 수 도 있습니다.
c은 == c[7] 문자열 배열에 이름을 이야기합니다.
그리고 sizeof는 함수이고 c에 함수에 맞게 입력을 받아라라는 의미라고 생각하시면 될꺼같습니다.
그럼 abcdefghi이라고 입력하면 abcdefg\n 화이트스페이트 문자를 포함해서 7개를 가지고 오게 된다.
그럼 당연히 공백을 포함하기 때문에 c[strlen(c)-1] = '\0'; 넣어줘야 합니다.
조금 복잡해 보일 수도 있지만 다음장에 배운 sanf_s를 배우면 이해가 되실겁니다.
그리고 배열에 대한 부분과 strlen 문자에 길이에 대한 부분도 이런게 있구나라고 생각해주세요.
저희는 간단하게 getchar를 추가하겠습니다.



▣ 그럼 여기서 화이트스페이스가 무엇일까요?
위키백과에서 화이트스페이스(Whitespace)는 에드윈 브래디(Edwin Brady)와 크리스 모리스(Chris Morris, cim)가 2003년 4월 1일(만우절)에 발표한 난해한 프로그래밍 언어이다. 문법에는 오로지 공백과 탭, 그리고 개행 문자만이 의미가 있으며, 인터프리터는 이 3종류의 공백 문자를 뺀 모든 문자를 무시한다. 2004년 현재 이 언어의 최신 버전은 0.3이다.
이 언어는 스택 기반의 명령형 프로그래밍 언어이다. 프로그램이 실행되는 가상 머신은 스택과 힙을 가지고 있다. 프로그래머는 스택에 임의의 정수를 자유롭게 푸시할 수 있으며, (아직 부동 소수점이나 실수의 구현은 없다.) 또한 변수와 자료 구조를 계속 보존하기 위해서 힙에 접근할 수 있다.라고 나와있습니다.
어렵게 생각하지 마시고 엔터 탭도 문자에 하나라도 생각하시면 편할 거 같습니다. 

 

그리고 이렇게 바로 입력하고 출력하는 코드도 만들 수 있습니다. 변수 없이 가능하죠?
그럼 버퍼를 거치지 않고 바로 입력하는 건 없을까라는 생각이 들 수 있습니다. 있습니다. 이렇게 코딩을 해보죠.

 

먼저 #include 로 포함을 하겠습니다. 바로 콘솔 입출력 <conio.h>를 가지고 와서 _getch()와 _getche()를 사용해보겠습니다.

 

이렇게 코딩을 입력하고 _getch()를 사용해서 디버그를 해보면 이렇게 a를 입력하는 순간 바로 a가 출력하게 됩니다.
이건 버퍼를 통하지 않고 바로 putchar 출력을 했기 때문에 이런 결과가 나오는 것입니다.
그리고 지금 a로 출력된 건 putchar에 결과이지 우리가 입력한 값을 보여주는 게 아닙니다.
그럼 _getche는 무엇일까요?

 


똑같이 입력을 하고 결과를 보면 이렇게 우리가 입력한 a와 출력 결과 a가 보이게 됩니다. 이것도 필요한 경우가 있으니 한번 실습해주시고 기억해주시면 좋을 거 같습니다. 꼭 include를 해야 한다는 것 잊지 말아 주세요.



▣ 자 오늘은 간단하게 getchar와 putchar로 입출력을 진행해보았습니다.
버퍼에 대한 개념도 나와서 조금 어려우실 수도 있지만, 입출력은 프로그램을 만들 때 너무 중요한 개념이기 때문에 오늘 이것만 집중적으로 다뤄봤습니다.
아직 scanf, gets, puts까지 다루지는 않았지만 지금까지 한 개념이랑 비슷하기 때문에 먼저 집중적으로 한 글자만 입출력할 수 있는 함수를 다뤘습니다.
그럼 다른 것들은 당연히 한 글자가 아닌 여러 글자들을 입력받는 것이겠죠? 네 맞습니다.
scanf는 형식에 맞게 입력을 받는 것이고 gets는 문자열을 받는 것이고, puts문자열을 출력한다고 생각하시면 될꺼같습니다.
이걸 왜 굳이 나누었냐라고 하시면 문자열에 대한 부분은 결국 배열과 포인터에 대한 이야기를 해야 하기 때문입니다.
여기까지 꼭 실습해보시고 숙제는 char 변수 여러 개를 만들어 문자 하나씩을 받아와 나만에 암호가 출력될 수 있게 만들어 보는 것입니다. 이걸 해보시게 되면 배열에 필요성을 알 수 있을 겁니다.
결국 배열은 모음이기 때문이죠.
그럼 다음장에서 뵙겠습니다.



▣ 포기하지  마세요!!! 저도  했습니다.!!! 그럼 다음장에서  뵙겠습니다.

728x90
반응형

댓글