문타쿠, 공부하다.
[독하게 시작하는 C 프로그래밍] 섹션 9. 표준 입/출력 본문
콘솔(Console)이란 무엇일까?
콘솔(Console)
- 텍스트 기반의 사용자 인터페이스
- 컴퓨터에서 텍스트로 명령을 입력하고 출력을 확인하는 환경을 의미
- 콘솔은 여러 OS에서 사용될 수 있으며, 사용자와 컴퓨터 간의 상호작용을 텍스트 형식으로 제공한다.
cmd
- Windows 운영체제에서 사용하는 CLI(Command Line Interface) 프로그램
Console과 CLI
- CLI기반 HCI(Human Computer Interface)는 키보드 입력으로 구현
- 키보드 입력 시 그 값은 메모리의 I/O Buffer에 연속적으로 저장
- I/O Buffer에서 한 글자 단위로 처리
인터럽트
- 컴퓨터 = CPU + RAM + 주변기기
- CPU와 주변기기들은 서로 상호작용/통신을 하며 정보를 주고받는다.
- 이때 CPU와 주변기기들의 원활한 상호작용/통신을 지원하는 역할을 인터럽트라고 한다.
문자 입/출력
getchar() 함수
- 여러 개의 문자를 입력해도 첫 번째 문자 즉, 한 글자만 메모리에 저장하는 함수
putchar() 함수
- getchar() 함수와 대응하는 함수로, 한 글자만 출력하는 함수
getchar() / putchar()
- Buffered I/O
- 값이 저장된 메모리의 값을 읽거나 출력
#include <stdio.h>
int main(void)
{
char ch = getchar();
putchar(ch);
printf("\n\n");
putchar('Y');
return 0;
}
_getch() / _getche()
- Non-Buffered I/O
- 키보드 입력 자체에 대한 감지
- 함수 사용 시 conio.h 헤더파일 추가하기
- _getch() 함수는 화면상에 내가 문자를 입력한게 안보이고, _getche() 함수는 보임
#include <stdio.h>
#include <conio.h>
int main(void)
{
char ch = _getch();
printf("입력한 키는 ");
putchar(ch);
printf("입니다.");
return 0;
}
#include <stdio.h>
#include <conio.h>
int main(void)
{
char ch = _getche();
printf("\n입력한 키는 ");
putchar(ch);
printf("입니다.");
return 0;
}
문자열 입/출력
scanf(), scanf_s() / printf()는 아래에서 따로 다루겠슴
문자열 입력
- gets()
- 보안 결함 문제로 사용하지 말라고 알려져 있음
- gets_s()
- 윈도우 계열에서 권장
- 크기를 명시해야 함
- fgets()
- 리눅스, 유닉스 계열에서 권장
문자열 출력
- puts()
- 개행문자가 포함된 상태로 실행된다.
#include <stdio.h>
int main(void)
{
char name[10] = { 0 };
printf("키미노 나마에와? ");
gets_s(name, sizeof(name));
printf("와타시노 나마에와 ");
puts(name);
puts("입니다요.");
return 0;
}
gets() 함수와 보안 결함 (feat. 시큐어 코딩)
gets() 함수의 보안 결함
- 매개변수로 메모리의 주소를 받지만 얼마나 써도 되는지 크기를 확인하지 않아 발생
- 메모리 경계를 벗어난 쓰기를 수행
- 보안 문제가 발생하지 않도록 코드 수준에서 대응하는 것이 중요(시큐어 코딩)
형식 문자와 이스케이프 시퀀스
형식 문자
형식문자 | 설명 | 자료형 |
%d | 정수 | int |
%o | 8진수 정수 | |
%x, %X | 16진수 정수 | |
%u | 부호 없는 정수 | unsigned int |
%f | 부동 소수점 | float, double |
%e, %E, &g, &G | 부동 소수점 과학적 표기 | |
%c | 문자 | char, int |
%s | 문자열 | char* |
%p | 포인터 | 포인터 자료형 |
%zd | 크기 | size_t |
등등 |
이스케이프 시퀀스
문자 | 의미 | 문자 | 의미 |
\a | 경고음 | \\ | \ |
\b | Backspace | \? | ? |
\f | Form feed | \' | ' |
\n | New line | \" | " |
\r | Carriage return | \ooo | 8진수 |
\t | Tab | \xhh | 16진수 |
\v | Vertical tab | 등등 |
실수 출력
단정도 float 말고 배정도 double 사용하기
문자, 정수 입력과 개행문자 제거
scanf_s()로 문자를 입력받을 때
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char array[5] = { 0 };
// %5c: char를 5번 읽어서 배열에 집어 넣겠다는 뜻
// _countof(array): sizeof()가 크기라면 _countof()는 개수를 의미
// 공백문자도 입력 값으로 인식함
scanf_s("%5c", array, _countof(array));
printf("%c, %c, %c, %c, %c\n", \
array[0], array[1], array[2], array[3], array[4]);
return 0;
}
scanf_s()로 연속된 값을 입력받을 때 어떤 형식 지정자를 사용하든 형식 지정자 사이에는 공백이 음슴 주의
#include <stdio.h>
int main(void)
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
// 연속된 값을 입력받을 때 형식 지정자 사이에 공백 ㄴㄴ
scanf_s("%d%d%d", &num1, &num2, &num3);
printf("입력한 숫자는 %d, %d, %d입니다.", num1, num2, num3);
return 0;
}
scanf_s() 함수로 값을 입력할 때 우리는 마지막에 입력이 끝났다는 의미로 엔터키(=개행문자)를 누른다.
그리고 scanf_s() 함수는 엔터키 즉, 개행문자를 꺼내지 않고 입력 버퍼에 그대로 남겨둔 상태로 종료된다.
그런데 이때 scanf_s() 함수로 문자열의 형태가 아닌 문자를 입력받는 함수를 사용하게 되면 문제가 발생한다.
바로 사용자에게 문자를 입력받지 않고 버퍼에 남아있던 개행문자를 인식하면서 문자 입력을 종료하게 된다는 것...!
문제코드1
#include <stdio.h>
int main(void)
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
scanf_s("%d%d%d", &num1, &num2, &num3);
printf("입력한 숫자는 %d, %d, %d입니다.\n", num1, num2, num3);
char ch = 0;
scanf_s("%c", &ch, sizeof(ch));
printf("입력한 문자는 %c입니다.\n", ch);
return 0;
}
문제코드2
#include <stdio.h>
int main(void)
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
scanf_s("%d%d%d", &num1, &num2, &num3);
printf("입력한 숫자는 %d, %d, %d입니다.\n", num1, num2, num3);
char ch = getchar();
printf("입력한 문자는 %c입니다.\n", ch);
return 0;
}
이와 같은 문제를 해결하려면 버퍼에 남아있는 개행문자를 제거해야하는데, 형식 지정자 뒤에 %*c라는 형식 문자를 붙여주면된다.
문제해결1
#include <stdio.h>
int main(void)
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
scanf_s("%d%d%d%*c", &num1, &num2, &num3);
printf("입력한 숫자는 %d, %d, %d입니다.\n", num1, num2, num3);
char ch = 0;
scanf_s("%c", &ch, sizeof(ch));
printf("입력한 문자는 %c입니다.\n", ch);
return 0;
}
문제해결2
#include <stdio.h>
int main(void)
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
scanf_s("%d%d%d%*c", &num1, &num2, &num3);
printf("입력한 숫자는 %d, %d, %d입니다.\n", num1, num2, num3);
char ch = getchar();
printf("입력한 문자는 %c입니다.\n", ch);
return 0;
}
형식 문자 기반 문자열 입력
문자열 입력 시 scanf_s() 함수를 사용하면 공백 문자를 사용할 수가 없다.(%[^\n]s라면 가능하긴 함..!)
그러기에 행 단위로 뭔가를 써야한다면 그냥 gets_s() 함수를 사용하는 것을 권장!
[필수 실습 문제] 나이와 이름 입/출력하기
#include <stdio.h>
int main(void)
{
int age = 0;
char name[10] = { 0 };
/*
%*c를 사용하지 않으면 gets_s() 함수에서 버퍼에 남아있는 개행문자를 읽고 입력이 끝났다고 생각해버리기 때문에
버퍼를 비워주는 역할을 하는 형식문자 %*c를 꼭 붙여주자
*/
printf("나이를 입력하세요: ");
scanf_s("%d%*c", &age);
printf("이름을 입력하세요: ");
gets_s(name, sizeof(name));
printf("당신의 나이는 %d살이고 이름은 '%s'입니다.\n", age, name);
return 0;
}
'C언어 > 독하게 시작하는 C 프로그래밍' 카테고리의 다른 글
[독하게 시작하는 C 프로그래밍] 섹션 11. 기본 제어문 (0) | 2023.11.01 |
---|---|
[독하게 시작하는 C 프로그래밍] 섹션 10. 연산자 (0) | 2023.10.29 |
[독하게 시작하는 C 프로그래밍] 섹션 8. C언어 기초 문법 (0) | 2023.10.24 |
[독하게 시작하는 C 프로그래밍] 섹션 7. 개발환경 구축 (Part 2. C 프로그래밍의 시작) (0) | 2023.10.24 |
[독하게 시작하는 C 프로그래밍] 섹션 6. 프로그래밍 언어 분류 (0) | 2023.10.19 |