본문 바로가기
[ C언어 ]/- C언어 문법공부

C언어 7장(표준입출력2 - gets, puts, scanf, 문자열)

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

안녕하세요. 오늘은 저번 시간에 이어서 표준 입출력을 진행하겠습니다.
저번장에서 숙제를 해보셨나요?
getchar()를 활용하여 암호를 만들어보는 숙제였습니다. 그래서 putchar로 출력을 하는 과정이었습니다.
숙제를 제대로 하셨다면 이런 생각을 하셨을 거라 생각합니다. 



▣ char를 한꺼번에 만들 방법은 없을까라는 생각을 하실 겁니다. 그래서 제가 그 숙제를 드린 겁니다.



네 있습니다. 바로 배열을 사용하면 됩니다.

 

이렇게 하면 char 변수 하나에 한 개에 문자를 저장하여 출력했습니다. 이걸 배열로 간단하게 만들 수 있습니다.

 

이렇게 코딩을 해서 배열을 만들 수 있습니다. 쉽게 설명하자면 char == 자료형 동일합니다. 변수만 들 때처럼요.
a == 배열 이름(변수 이름), [6] == 내가 만들 변수에 수를 의미합니다. 

 

▣ 배열을 만들게 되면 이렇게 그림처럼 만들어진다고 생각하시면 될 거 같습니다.
1byte는 char 자료형이 1byte이기 때문에 저렇게 표시를 했습니다. 제가 자료형을 이야기할 때 설명을 드렸습니다.
그런데 의문이 하나 생깁니다. 6개인데 왜 번호가 1부터가 아니라 0부터로 표현을 했습니다.
그건 컴퓨터에 숫자 시작은 0부터 시작하기 때문입니다.
그래서 index번호도 0부터 시작하게 됩니다.
index가 먼가요라고 하시면 여러 가지 의미가 있어서 간단하게 고유번호라고 생각해주시면 될꺼같습니다. 

 

이렇게 하나하나 출력하게 되면 배열 하나에 한 개에 글자가 들어있다는 걸 확인할 수 있습니다. 
그런데 여기서 주의해야 할 건 제가 5글자인데 6개에 배열을 만들었죠?라는 의문이 또 들게 됩니다. 
그건 문자열 맨 끝에는 항상 \0, Null 문자가 들어있기 때문에 딱 맞게 배열을 만들게 되면 이상하게 출력이 되는 걸 확인할 수 있습니다.
이 부분은 배열을 다룰 때 더 자세하게 다루고 끝에 항상 한 개에 공간이 남아야 한다는 것만 기억해주세요.
이번에는 주소를 확인해 보겠습니다. 
다른 장에서 배운 것처럼 형식을 %p 포인터 형식으로 주소를 확인해 보겠습니다.

 

이렇게 코딩을 하면 하나하나 주소를 확인할 수 있습니다.
쉽게 중요한 이야기를 하면 c(배열 이름)은 주소가 들어 있습니다.
변수와 다르게 변수는 변수 이름을 넣고 바로 출력해서 확인을 하면 값을 전해주는 반면 배열은 주소를 전해주게 됩니다. 그래서 나중에 scanf를 할 때 배열은 그냥 배열 이름만 적어서 진행하게 됩니다.
왜냐 그 그릇에 위치를 전달해줘서 입력값을 넣어야 하기 때문입니다.
그리고 변수는 이름 앞에 &를 넣어야 합니다. 그건 &주소를 나타내기 때문에 입력을 받을 때에는 그 그릇 자체가 필요하지 들어 있는 값이 필요한 게 아니기 때문입니다. 조금 어렵죠 갑자기 이런 이야기를 해서.
이 이야기는 scanf를 다룰 때 더 자세하게 다뤄보겠습니다.



여기서 중요한 건 배열은 주소를 가지고 있다. 그 주소는 곧 그릇에 위치가 되는 것이고 거기에 문자들을 담에서 한꺼번에 보여주는 것이 바로 문자열 == 배열이라고 생각하시면 좀 쉬우실? 꺼라 생각합니다. 
그리고 코딩을 자세하게 보면 배열 전체에 주소랑 배열 0번째 주소가 같다라는 걸 알 수 있습니다. 배열은 주소이기 때문입니다.





이해가 다 안 되셔도 좋습니다. 하지만 배열은 주소이다. 저 위에 있는 코딩 예제를 꼭 해보시고 이 글을 이어서 읽으시면 좀 이해가 되실 거라 생각합니다.
배열은 따로 장을 만들어 다루겠습니다. 걱정하지 마시고 이어서 꼼꼼하게 읽어주세요.



▣ 자 다시 멘탈 잡고 gets와 puts를 사용해보겠습니다.  gets는 문자열을 받아오고 puts는 문자열을 출력하는 것입니다. 

 


이렇게 코딩을 해보면 결과가 잘 나오게 됩니다.
아까 이야기한 데로 배열로 char 여러 개를 만들고 그 공간 안에 입력값을 넣습니다. 그런 다음에 바로 그걸 버퍼에서 하나하나 꺼내서 출력하게 됩니다. 
그런데 이상한 건 gets_s에 밑줄과 s가 붙었죠? 그리고 sizeof라는 것도 처음 보실 겁니다. 

▣ 박스 그림을 한 봐주세요 우리가 만약에 5개에 물건을 넣을 수 있는 박스를 만들었다고 생각해보겠습니다. 
이제 그걸 전달해주고 다른 사람이 물건을 5개 넣어서 포장해서 배송을 한다고 생각해보겠습니다.
그런데 우리는 5개에 물건을 넣을 수 있는 박스로 보내주었는데, 물건을 넣는 사람이 7개 10개를 생각 없이 무작위로 막 넣어서 배송을 했다고 상상해 봅시다.
그럼 어떻게 될까요? 네 당연히 훼손될 것이고 물건이 튀어나오거나 잘못 전달될 것입니다. 



입력하는 것도 마찬가지입니다. 우리가 Null을 포함해서 5개에 문자만을 입력할 수 있는 공간을 만들었는데 그 이상으로 입력을 했다고 생각해봅시다.
그럼 메모리가 초과 오버하게 되겠죠? 넘치게 됩니다. 그리고 보안에 문제가 생기게 됩니다. 



그래서 Visual Studio에서 gets와 scanf를 그냥 사용하게 되면 오류가 나는 것을 볼 수 있을 겁니다. 
그래서 이걸 해결하려면 이 경고문을 무시하는 매크로를 작성해주거나 Visual Studio에서 제공한 gets_s, scanf_s를 사용해야 합니다.
여기서 또 중요한 건 sizeof라는 함수를 활용하여 가변적으로 바뀌는 입력값이라도 그 사이즈에 맞게 메모리를 정해줄 수 있습니다.

 

 

▣ 이렇게 코딩을 해보고 확인을 해보겠습니다.
sizeof()는 이렇게 메모리 사이즈를 바로바로 반환해주는 함수입니다. 너무 중요한 함수이고 우리가 메모리를 오버하지 않게 실수를 보완해주는 함수입니다. 여러 용도로 많이 사용하니 꼭 기억해주세요.



그다음에 scanf를 사용해보겠습니다. 

 

이렇게 입력을 하고 코딩을 해보면 정상적으로 코딩이 진행이 되게 됩니다. 



▣ 아까 이 야한 것처럼 그냥 scanf를 사용하면 보안 오류가 발생합니다. 그렇기 때문에
#define _CRT_SECURE_NO_WARNINGS를 위에 입력해주시고 코딩을 하면 오류가 발생하지 않습니다. 



그리고 여기서 중요한 건 scanf도 printf와 동일하게 f는 포맷에 약자로 형식에 맞게 입력을 받아오는 것입니다.
그래서 형식을 적고 &c를 적습니다.
저건 위에서 이야기한 것처럼 우린 안에 들어있는 값을 찾아오는 게 아니라 그 그릇 메모리를 찾아 입력을 넣어줘야 하기 때문에 &c 이렇게 입력을 해줘야 합니다.
그냥 하게 되면 값을 가져오라는 의미입니다. 꼭 기억해주세요. 

▣ 저 매크로를 사용하지 않고 사용할 수 있게 gets_s와 동일하게 뒤에 메모리 사이즈를 넣어주면 됩니다. 그리고 size부분에 숫자를 그냥 넣어도 되지만 꼭 저 방법을 사용해주세요. 저렇게 하면 제대로 입력을 받을 수 있습니다. 

 

이번에는 문자열을 받아올 것입니다. 문자열을 받아야 하기 때문에 여러 char가 필요하므로 아까처럼 배열을 만들고 이번에는 문자열이니깐 %c가 아닌 %s로 형식을 바꿔서 입력을 해줘야 합니다.
그리고 putchar가 아닌 puts를 받아 문자열을 출력할 수 있게 해야 합니다. printf도 가능합니다.



▣ 자 이렇게 오늘은 표준 입출력을 사용해 보았습니다. 우리가 지금까지 꼼꼼하게 읽어서 입출력에 스트림 과정을 생각해보면 저 부분이 왜 있는지 왜 하는지를 알 수 있을 겁니다.
모르시는 분은 꼭 모든 장을 다시 꼼꼼하게 읽어서 실습하시기 바랍니다.
숙제는... 심심이라는 프로그램 아시나요? 우리가 입력을 주면 컴퓨터가 대답을 해주는 프로그램인데 그걸 비슷하게 우리가 배운 입출력 함수로 만들어 보시기 바랍니다.
예를 들어 컴퓨터가 이름부터 물어보고 이름을 입력해주면 컴퓨터가 안녕하세요 홍길동 님이라고 대답을 하겠죠? 이런 식으로 만들어 보세요. 
숙제를 해보시면 입출력 함수를 이해하는데 많은 도움이 되실 거라 생각합니다. 
그럼 다음장에서 뵙겠습니다.



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

728x90
반응형

댓글