' [C/C++] 3강 - 변수를 출력하고 입력받는 법 (printf, scanf, scanf_s)

Programming/C & C++

[C/C++] 3강 - 변수를 출력하고 입력받는 법 (printf, scanf, scanf_s)

mdisprgm 2021. 6. 5. 23:24
728x90

(1) printf로 변수 출력하기

지난 1강에서 문자열을 출력하는 것은 해보았다.

#include <stdio.h>

int main() {
	printf("Hello World!\n");
    
	return 0;
}

앞으로는 예시를 들때 include와 main 등은 꼭 필요한 경우가 아니면 생략하는 일이 빈번할 것인데 
여러분의 넓은 아량으로 이해를..
쓰다보면 굉장히 귀찮아져서.. 허허


여기에 변수를 출력하고 싶을 땐 어떻게 해야할까

 

각 타입에 맞는 서식 문자를 이용하면 된다.

 

예를 들어 정수를 출력할 때는 %d 서식 문자를 이ㅣ용한다.

int a = 10;

printf("%d\n", a);//10 출력

이렇게 하면 10이 출력될 것이다.

 

a를 int형으로 선언하고 10을 대입했으니, int형에 해당하는 서식 문자인 %d를 사용한 것이다.

 

"%d"가 위치한 자리에 a의 값 10을 문자열 형태로 치환해서 넣어준다.

 


참고로 printf 함수 이름에서 f는 format을 의미함.

여러 "형식"의 변수를 하나의 문자열로 조합해 출력하는 함수.


물론 %d는 int와 같이 4바이트 정수 타입을 출력할 때만 쓰고

 

다른 타입은 다른 서식 문자를 사용해야한다.

 

서식 문자 용도
%d signed int 타입 10진법으로 출력
%ld signed long 타입 출력
%lld signed long long 타입 출력
%f float 타입 출력
%lf double 타입 출력
%c char형 문자 출력
%s 문자열 출력
%x, %X 정수를 16진법으로 출력
%o, %O 정수를 8진법으로 출력
%p 포인터 타입을 16진법으로 출력

여기서 포인터는 많은 사람들이 아주 골치아파하는 타입인데

지금은 아니어도 언젠가는 충분히 머리를 싸맬 것이니 지금은 눈길도 주지 말자

 

 

사실 사용할 수 있는 서식 문자는 방금 본 것보다 훨씬 더 다양한데

 

그러나 지금은 이 강좌에서 당장 필요한 것과 꼭 알아야할 것들 몇가지를 적었다.

 

또 이 서식 문자들로 접두사를 붙인다든지, 여백 등을 설정할 수 있는데 이것들은

 

다른 서식 문자들과 함께 다음 강좌에서 소개하겠다.

 

 

간단하게 저 위에 있는 것들을 사용해보면

#include <stdio.h>

int main() {
      int a = 32;
      double b = 3.1415;
      printf("a를 %%d로 : %d\n", a);
      printf("b를 %%lf로 : %lf\n", b);
      printf("a를 %%x로 : %x\n", a);
}

 

이 코드를 '디버그 하지 않고 시작'의 단축키 Ctrl + F5 로 실행해보자.

이렇게 출력이 될 것.

 

보다시피 '%' 자체를 출력할 때는 %%를 쓰면 되고..

 

저번 강의부터 있던 저 '\n'은 뭘까? 분명 " " 안에 적긴 했는데 출력물을 보면

 

아무것도 보이지 않네요.

 

(글꼴 때문에 그런데 \과 \ 는 같은 문자이다, 엔터키 위에 있는 키)

 

저것은 바로 줄바꿈을 의미하는데, \n을 만나면 자동으로 줄바꿈을 해준다.

이러한 특수 기능이 있는 문자들을 이스케이프 시퀀스라고 하는데,

 

그 종류는 다음과 같다.

이스케이프 시퀀스 의미
\n 개행 문자(줄바꿈)
\t Tab
\b 백스페이스, 커서를 왼쪽으로 옮긴다.
그 위치에서 다음 문자를 덮어씌우는 형식이라
\b만 쓰면 글씨가 지워지진 않는다
\r 커서를 맨 왼쪽으로 옮긴다.
\b와 마찬가지로 옮긴 위치에서 덮어씌워진다.
\a 경고음을 낸다.

이 코드를 실행해봅시다.

#include <stdio.h>

int main() {
	printf("HelloWorld\b");
	printf("C language is great\rC++ supports OOP\a\n");
	printf("\tABC\n");
	printf("ABCD\tABC");
}

출력 결과는 이렇다.

하나씩 살펴보자면

 

1. 처음에 HelloWorld를 출력하다가 \b가 나왔다.

 

그래서 커서는 마지막으로 출력했던 d를 가리키고 있는데, 여기서 "C language is great"가 나타나

 

d를 덮어씌워버려 "HelloWorlC language is great" 가 된다..

 

그런데 여기서 또

 

2. \r을 만나 커서가 맨 왼쪽으로 이동했다가

 

"C++ supports OOP"을 출력한다.

 

이때 역시 "C++ supports OOP"가 먼저 출력했던 것을 덮어 씌우며 출력되기 때문에

 

결국 "C++ supports OOPage is great"가 출력이 된다.

 

 

3. \t(Tab?)가 조금 특이한데. Tab은 8칸을 띄우는 이스케이프 시퀀스임.

 

그런데 처음부터 \t을 하고 ABC를 출력한 것과

 

ABCD를 출력하고 \tABC를 한 것과 ABC의 위치가 같은 걸 볼 수 있다.

 

왜냐하면 사실 \t는 정확히 말하면 딱 8칸을 띄우는 것이 아니라

 

콘솔창(메모장 같은 텍스트 에디터 포함)에는 보이지 않는 단위로 8칸씩 나뉘어진 블록이 있는데 그 다음 블록으로 넘어가는 것입니다.(수평 탭).

 

"ABCD\tABC"를 할 때 이미 ABCD로 첫 블록에 4칸이 이미 채워졌기 때문에

 

\t를 만났을 때 4칸만 마저 띄운다는 뜻.

모두 처음 블록에서 두 번째 블록으로 넘어가 ABC의 위치가 같다

 

 

C언어는 일부 다른 언어와 다르게 따옴표 ', "의 구분을 명확히 해야한다.

 

예를 들어 Python이라는 언어에서는 'A'와 "A"가 서로 일치하지만

 

C에서는 다릅니다. 'A' 는 ASCII 값으로 65, "A"는 "A\0" 을 의미합니다.

 

하나는 단일문자, 하나는 문자열로 타입 자체가 호환이 안 된다.


\0 는 문자열의 끝을 의미하는 Null 문자이다.

이렇게 널 문자를 이용해 문자열의 끝을 구분하는 방식을 Null-terminated string 이라고 한다.


 

이스케이프 시퀀스들은 \n,\t,\b로 눈으로 보기엔 두 글자인데

 

그러나 각각이 줄바꿈, 탭을 의미하는 한 문자이기 때문에 '\n'과 같이 작은 따옴표로 묶어주어야 한다.

 

"\n" 처럼 쓴다면 "A"와 마찬가지로 "\n\0"이 된다.

 

 

(3) scanf 사용법

scanf로 입력받는 법..

 

지금까지는 직접 코드에서 변수에 값을 대입해 출력했는데

 

그러나 그것 뿐이면 그것은 좋은 프로그램이라 할 수 없다.

 

왜냐하면 사용자와 소통을 하지 않기 때문.

 

소통이 없으면 사용자가 원하는 일을 할 수 없게 된다.

 

 

scanf의 사용 예시는 다음과 같다.

#define _CRT_SECURE_NO_WARNINGS//scanf는 보안상의 이유로 대신 scanf_s 를 사용하는 것이 권장된다.
					//이 코드를 사용해 보안 경고를 무시한 것이다.
#include <stdio.h>

int main() {
	int a;	//아까 위에서 변수는 무조건 초기화 하라 했는데
    		//scanf로 입력받을 땐 = 로 초기화 해주지 않아도 된다            
	printf("값을 입력하시오 : ");
	scanf("%d", &a);

	printf("%d\n", a);
}

 

프로그램 실행 결과

 

1. 이렇게 입력받을 값의 서식을 정해줍니다.

이때 사용되는 서식 문자는 printf에서 사용되는 문자와 동일하다는 것을 알 수 있다.

 

2. 그리고 그 다음 값에는 변수의 '주소'라는 것을 알려줘야 한다.

 

 

모든 변수는 메모리 상에 기억되는데, 메모리 위치마다 각각 주소를 가지고 있다.

 

그리고 그 주소를 이용해서 변수에 접근할 수 있는데 scanf의 역할이 바로 이것이다. 알려준 주소에 값을 저장하는 것

 

이것은 그 어렵다는 '포인터'의 개념이라서

 

지금은 scanf로 입력받을 땐 &를 붙여야 되는구나~만 알고 있으면 된다.

 

 

이걸 활용하면 이런 것도 가능한데

#include <stdio.h>

int main() {
	int a, b;//참고로 이렇게 자료형을 한 번만 쓰고 변수 여러 개를 선언하는 것이 가능하다
			//int a = 10, b, c=10; 이렇게 일부 변수만 동시에 초기화하는 것도 가능
	printf("더할 두 수를 입력하세요 : ");
	scanf_s("%d%d", &a, &b); //한 번에 여러 개 입력

	printf("%d + %d = %d\n", a, b, a + b);//한 번에 여러 개 출력
}

입력한 두 수와 두 수의 합이 출력되는 코드이다.

 

이 코드는 처음에 쓴 코드와 다르게 맨 첫 번째 줄에 #define _CRT~~~ 이게 사라지고

 

scanf가 scanf_s로 바뀐 걸 볼 수 있다.

 

사실 scanf는 버퍼 오버플로우라는 취약점을 가지고 있다.

 

때문에 마이크로소프트는 해당 취약점을 개선한 scanf_s를 새로 만들어 추가하였다.

 

그리고 scanf는 컴파일 조차 안되게 막아버렸는데

 

위에서 설명했다시피 #define _CRT ~~ 이걸 추가해주면 보안 경고를 무시하고 scanf를 사용할 수 있게 된다.

 

그러나 역시 scanf_s를 사용하는 걸 강력 권장.

(그래도 scanf_s가 표준은 아니기 때문에, gcc를 사용해 컴파일 한다면 scanf를 사용해야 한다.)

 

 

정수를 입력하는 데는 scanf_s의 사용법이 크게 다르지 않지만

 

문자열이란 것을 입력할 때는 사용법이 다른데

 

이 역시 포인터를 설명할 때 같이 추가 설명을 하겠다.

오늘 포인터 얘기만 세 번째...ㅋㅋㅋ 포인터 포스팅을 빨리 올려야겠..

 

 

끝.

 

728x90

'