김펭귄 관찰일기
article thumbnail

https://www.acmicpc.net/problem/11720

 

11720번: 숫자의 합

첫째 줄에 숫자의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄에 숫자 N개가 공백없이 주어진다.

www.acmicpc.net

 

 

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);
}

 

 세상에 나쁜 개는 없고 세상에 나쁜 코드도 없다. 주인이 문제인 것이다. 그렇다. 내가 문제였다.

 

what the..

 코알못인 나는 당연히 scanf로 값을 넣어주면 한 글자씩 알아서 각 테스트 케이스의 배열의 각 자리에 넣어줄 것이라 생각했다. 이런 멍청이가 또 있을까.

https://modoocode.com/32

 

 

씹어먹는 C 언어 - <15 - 2. 일로와봐, 문자열(string) - 버퍼에 관한 이해>

 

modoocode.com

 내 소중한 친구 '부기부기 (맥북)'은 입력을 받을 때 버퍼를 사용한다. 버퍼란, 입출력 데이터 등의 정보를 전송할 때 일시적인 데이터 저장 장소로 사용되는 기억 장소를 일컫는 말이다. 그중에 키보드 입력을 처리해야 하기에 입출력 버퍼 (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번의 문자열 입력을 받을 때까지.

 

0123456789를 10번 입력해주니 정상적으로 다음 코드가 실행되는 것을 볼 수 있다.

 


 

test_Case #2

 

 이제 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에서 한 글자씩 읽어와 각 인덱스에 한 글자씩 저장하게 되는 것이다.


test_Case #3

// 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을 써야 한다.

 


 

test_Case #4

 

// 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의 세계는 심오하지만 정말 너무 미치도록 재밌는 것 같다.

 

profile

김펭귄 관찰일기

@Penguin.Kim