C언어 입출력 함수 파헤치기
입출력이 너무나도 헷갈린다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h> int main(void){ int number = 0; char cData = 'a'; char sData[20] = { 0 }; printf("숫자를 입력하세요:"); scanf("%d", &number); printf("문자를 입력하세요:"); scanf("%c", &cData); printf("문자열을 입력하세요:"); scanf("%s", sData); //배열은 주소이기에 '&'를 사용하지 않는다. printf("숫자 : %d\n문자 : %c\n문자열 : %s\n", number, cData, sData); return 0; } | //cs |
결과값은 위와 같이 나오게 된다.
왜 문자를 입력받지 않을까????
왜 문자를 그냥 무시하고 넘어가는 것일까?
궁금증이 생긴다.
정상적인 결과이다.
이유는 우리가 입력하는 문자열 혹은 정수형태나
마지막에는 "\0" , "NULL"값이 들어가게 되기 때문입니다.
의심이 들면 디버거로 한번 자세히 살펴보겠습니다.
일단 상단에 입력 버퍼를 확인하기 위해
FILE *fp = stdin; 을 추가하였습니다.
디버거 모드 진입
1. 정수 10을 입력합니다.
number메모리에는 정수 10 이 16진수 형태 0x0a로 들어갑니다.
2. 문자를 입력하기위해 진입합니다.
3. 문자를 입력하려 하지만?? 다음 printf() 함수로 넘어가 버렸습니다.
의문이 생깁니다
4. 문자는 무시하고 문자열을 받습니다.
이쯤 종료하여서 3번에서의 원인을 파악하겠습니다.
그 전에 scanf의 동작 원리를 한번 설명하고 넘어가겠습니다..
1. scanf 는 사용자로 부터 형식 문자의 값을 받습니다.
2. 받은 값은 버퍼에 들어가고 버퍼의 값을 읽어서 변수의 주소에 저장합니다.
모든 형태문자를 첫 값을 자신이 받아들일 수 있는 값을 받아들인다.
%d 와 %s같은 형태문자들은 '\n' 이러한 이스케이프 문자를 보고 그냥 넘어간다
그러나 %c 형태문자의 경우에는 ASCII 표에 있는 \n 개행 문자를 읽어들인다.
2번의 경우와 3번의 경우를 비교해보아야 합니다
2번의 경우
1. scanf("%d",&number); 함수는 사용자 입력값을 버퍼에 저장합니다.
2. 저장한 버퍼의 값을 number주소에 값을 저장합니다.
3. 이때 파일의 입력 부분을 보게되면 사용자 입력값은 카운트 되어 넘어가고
_ptr 가르키는 값이 \n 개행문자라는 것을 볼 수 있습니다.
3번의 경우
1. 현재 버퍼에 값 '\n' 를 가르치며 버퍼 호출 함수를 사용하면 '\n' 을 받아 갑니다.
2. scanf("%c",cData); 문자를 하나 받겠다 하는데, '%c' 형태문자는 이스케이프 문자를 읽어들입니다.
'\n' 문자를 1byte 읽어 냅니다.
3. 읽어낸 결과는 바로 printf 함수에 찍어서 보여줍니다.
이 과정 때문에 우리가 입력하려하였던 문자를 입력하지 못하고 그냥 넘어갔던 것입니다.
해결방안
첫번째
1 2 3 4 5 6 | printf("숫자를 입력하세요:"); scanf("%d", &number); getchar(); printf("문자를 입력하세요:"); scanf("%c", &cData); | cs |
개행 문자를 getchar() 함수를 이용하여 넘겨 버립니다.'
getchar() 함수의 특성은 버퍼에 값이 있으면 한 글자를 읽어 오는 것입니다.
이 특성을 이용하여서 야매;..? 로 개행 문자를 받아 넘어가는 방식입니다.
성공였다면 이러한 결과값이 반환 되었을 것입니다.
두 번째
fflush(stdin); 함수를 이용해 버퍼를 비웁니다.
1 2 3 4 5 6 | printf("숫자를 입력하세요:"); scanf("%d", &number); fflush(stdin); printf("문자를 입력하세요:"); scanf("%c", &cData); | cs |
코드에 fflush(stdin) 함수를 추가하여 코드를 실행하면 첫 번째와 동일하게 실행된다.
하지만 이 방법은 windows계열에서만 사용가능하다는 단점이 있다.
리눅스에서는 fpurge()함수를 사용합니다.
결과값은 동일하게 나타날 것입니다.
세 번째
%d%*c 형태문자 %*c를 이용합니다.
1 2 3 4 5 | printf("숫자를 입력하세요:"); scanf("%d%*c", &number); printf("문자를 입력하세요:"); scanf("%c", &cData); | cs |
scanf() 함수를 호출할 때, 형태문자에 %*c를 붙여주면 입력문자를 버퍼에서 하나 읽어와서 버린다는 뜻이 됩니다.
'*' 이 버려준다는 뜻으로 해석됩니다.
다양한 환경에서 사용하려면 형식문자를 사용하는 것이 바람직합니다.
'훈, IT 공부 > C,C++,MFC' 카테고리의 다른 글
[실습코딩] 나이에 따른 분류 및 요금계산 ( 2분할 방식, 단계별 분류) (2) | 2017.12.25 |
---|---|
삼항 연산자와 IF문 (별찍기) (6) | 2017.12.21 |
[실습코딩]서바이벌 구조 만들기 (1) | 2017.12.21 |
[실습코딩]세 정수 중에서 가장 큰 수 구하기 (2) | 2017.12.21 |
문자입출력 메모리값으로 이해하기 (0) | 2017.12.10 |
댓글