https://www.acmicpc.net/problem/11720
1. 문제
💡 문제
N개의 숫자가 공백 없이 쓰여있다. 이 숫자를 모두 합해서 출력하는 프로그램을 작성하시오.
💡 입력
첫째 줄에 숫자의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄에 숫자 N개가 공백없이 주어진다.
💡 출력
입력으로 주어진 숫자 N개의 합을 출력한다.
2. 풀이
#include <stdio.h>
int main(){
int input = 0, sum = 0;
scanf("%d", &input);
int num[100] = {0,};
for (int i = 0 ; i < input ; i++){
scanf("%1d", &num[i]);
sum += num[i];
}
printf("%d\n", sum);
}
3. 메모
11720번 문제를 통해 알게 된 것은 바로 scanf를 통해 다양하게 입력을 받아올 수 있다는 것이다. 역시 기본기는 탄탄할수록 좋다.
P.S. 심지어 확인해보려고 만든 테스트 케이스 상태가 이상하다.. 세상에..! 산 넘어 산이다.
#include <stdio.h>
int main(){
int test1[100] = {0,};
int test2[100] = {0,};
int test3[100] = {0,};
int test4[100] = {0,};
int sum_1 = 0, sum_2 = 0, sum_3 = 0, sum_4 = 0;
// Case #1
printf("Case #1\n");
for (int i = 0 ; i < 10 ; i++){
scanf("%d", &test1[i]);
sum_1 += test1[i];
}
for (int j = 0 ; j < 10 ; j++) printf("test1[%d] = %d\n", j, test1[j]);
printf("sum :: Case #1 : %d\n\n", sum_1);
// Case #2
printf("Case #2\n");
for (int i = 0 ; i < 10 ; i++){
scanf("%1d", &test2[i]);
sum_2 += test2[i];
}
for (int j = 0 ; j < 10 ; j++) printf("test2[%d] = %d\n", j, test2[j]);
printf("sum :: Case #2 : %d\n\n", sum_2);
// Case #3
printf("Case #3\n");
for (int i = 0 ; i < 10 ; i++){
scanf("%2d", &test3[i]);
sum_3 += test3[i];
}
for (int j = 0 ; j < 10 ; j++) printf("test3[%d] = %d\n", j, test3[j]);
printf("sum :: Case #3 : %d\n\n", sum_3);
// Case #4
printf("Case #4\n");
for (int i = 0 ; i < 10 ; i++){
scanf("%3d%*d", &test4[i]);
sum_4 += test4[i];
}
for (int j = 0 ; j < 10 ; j++) printf("test4[%d] = %d\n", j, test4[j]);
printf("sum :: Case #4 : %d\n\n", sum_4);
}
세상에 나쁜 개는 없고 세상에 나쁜 코드도 없다. 주인이 문제인 것이다. 그렇다. 내가 문제였다.
코알못인 나는 당연히 scanf로 값을 넣어주면 한 글자씩 알아서 각 테스트 케이스의 배열의 각 자리에 넣어줄 것이라 생각했다. 이런 멍청이가 또 있을까.
내 소중한 친구 '부기부기 (맥북)'은 입력을 받을 때 버퍼를 사용한다. 버퍼란, 입출력 데이터 등의 정보를 전송할 때 일시적인 데이터 저장 장소로 사용되는 기억 장소를 일컫는 말이다. 그중에 키보드 입력을 처리해야 하기에 입출력 버퍼 (stdin)가 사용된다.
scanf가 사용된 코드를 컴파일하게 되면, 부기부기는 코드 첫 번째 줄부터 쭉쭉 읽어나간다. 그러다 scanf를 만나면 잠시 프로그램을 멈추고 입력을 기다린다. 자, 그럼 대체 왜 4개를 입력했음에도 버퍼가 입력을 기다리고 있을까. 아주 간단했다.
니가 scanf를 10번 반복하라며...
for(int i = 0 ; i < 10 ; i++) scanf("%d", test1[i]);
부기부기는 입력받은 문자열을 쭉 읽다가 ' ', '\n', '\t'를 만나게 되면 지금까지 읽어온 값을 test 1 [0]에 저장할 것이다. 자, 부기부기는 네 번째 문자열 '0123456789\n'까지 읽었고 test 1 [0]부터 test 1 [3]에 무사히 값을 저장했다. 그 후로 정수 입력이 없었으니 (% d는 정수 값만 읽으니까..!) 개행 문자를 아무리 입력해도 아무런 반응이 없는 것이다. 언제까지? 나머지 6번의 문자열 입력을 받을 때까지.
이제 Case #2를 보자. [0] ~ [9]에 저장된 값이 Case 1번과는 많이 다르다.
// Case #1
scanf("%d", &test1[i]);
// Case #2
scanf("%1d", &test2[i]);
둘의 차이는 % 와 d 사이 1의 유무이다. scanf의 인자는 다음과 같이 구성되어 있다.
% [ * ] [ width ] [ 한정자 ] (type)
여기서 width는 stdin에서 읽어 들일 최대 문자 수를 의미한다. 즉, Case 2번의 width 값이 1이기에 우리 부기부기는 stdin에서 한 글자씩 읽어와 각 인덱스에 한 글자씩 저장하게 되는 것이다.
// Case #1
scanf("%d", &test1[i]);
// Case #2
scanf("%1d", &test2[i]);
// Case #3
scanf("%2d", &test3[i]);
Case #3도 #2와 크게 다르지 않다. 단지, width 값이 1에서 2가 되었을 뿐이다... 가 아니다. 이번에도 문제다. scanf("% d", &test 3 [i])라고 작성했으니, 분명 부기부기는 두 자리씩 읽어와서 배열에 넣을 것이다. 그렇다면 왜 test 3 [0]과 test 3 [5]의 값이 '01'로 나오지 않고 '1'로 나오는 걸까. 이 부분은 printf와 관련이 있다.
부기부기는 분명 두 자리씩 받아왔을 것이다. 정확히는 두 자릿수 정수로 받아왔을 것이다. 그 말인즉슨 test 3 [0]에 들어간 값이 '0', '1'이 아닌 '01'이라는 뜻이고, 출력할 때 자릿수를 지정하지 않았으니 '1'이 출력되는 것이었다..! 우와!
printf("Case #3\n");
for (int i = 0 ; i < 10 ; i++){
scanf("%2d", &test3[i]);
sum_3 += test3[i];
}
// "%d"에서 "%02d"로 바꾸면?
for (int j = 0 ; j < 10 ; j++) printf("\ntest3[%d] = %02d", j, test3[j]);
printf("\nsum :: Case #3 : %d\n\n", sum_3);
정리하자면
scanf("%(x)d", A);
-> x 자릿수만큼 받아와 A에 저장
printf("%(x)d", A);
-> x 자릿수만큼 A의 값을 출력
printf("%.(x)f", A);
-> A를 출력하되, 소수점 아래 x 자릿수까지 표기
// 참고로 정수는 소수점 아래 수가 없기에 이 경우에는 float나 double을 써야 한다.
// Case #1
scanf("%d", &test1[i]);
// Case #2
scanf("%1d", &test2[i]);
// Case #3
scanf("%2d", &test3[i]);
// Case #4
scanf("%3d%*d", &test4[i]);
마지막 케이스다... 드디어 이것만 해결하면 집을 갈 수 있다. Case #4를 보면, 이전 Case에서 없던 '%*d'가 뒤에 붙어있다. '%d' 가운데에 '*'를 넣게 되면, stdin가 버퍼에서 데이터를 읽어오긴 하지만 그 값을 무시한다.
그렇다면 '%*d'의 위치에 따라 값이 다를까? 바로 확인해보자...!!
int a = 0, b = 0;
scanf("%2d%*d", &a);
printf("a의 값 : %d\n", a);
scanf("%*d%2d", &b);
printf("b의 값 : %d\n", b);
a와 b의 결과값이 다른 것을 확인할 수 있다..!! 어떻게 된 일일까?
자, 우리가 '12345'라는 값을 입력했으니 부기부기는 버퍼로부터 값을 읽어오기 시작한다. 어떻게? 두 자리씩 끊어서! 그런데 그 뒤에 '%*d'가 있다. 앞서 말했지만 '%*d'를 사용하면 데이터를 읽어오지만 그 값을 무시한다. 고로 '12까지만 읽고 '3'과 '4', '5'를 무시하는 것이다.
b도 이와 굉장히 유사하다. 우리는 버퍼에 '12345'라는 값을 넣어줬지만 b의 경우 '%*d'가 앞에 위치한다. 그렇기에 부기부기는 '12345'를 전부 무시하고 다음 정수값을 입력하길 기다리는 것이다. '54321'을 입력하니 정상적으로 앞에 두 자리를 출력하는 것을 볼 수 있다.
P.S. C의 세계는 심오하지만 정말 너무 미치도록 재밌는 것 같다.
'프로그래밍 > 백준 알고리즘' 카테고리의 다른 글
[C] 단어공부 (백준 알고리즘 1157번) (0) | 2021.07.23 |
---|---|
[C] 문자열 반복 (백준 알고리즘 2675번) (0) | 2021.07.23 |
[C] 알파벳 찾기 (백준 알고리즘 10809번) (0) | 2021.07.23 |
[C++] 문제 1 - 아이디 추천 (2021 카카오 신입공채 1차 온라인 코딩 테스트) (0) | 2021.07.20 |
[C ] OX 퀴즈 (백준 알고리즘 8958번) (0) | 2021.07.15 |