9 분 소요

[백준]15552번 빠른 A+B

C++을 사용하고 있고, cin/cout을 사용하고자 한다면,

cin.tie(NULL)과 sync_with_stdio(false)를 둘 다 적용해주고, endl 대신 개행문자(\n)를 쓰자. 단, 이렇게 하면 더 이상 scanf/printf/puts/getchar/putchar 등 C의 입출력방식을 사용하면 안된다.

Python을 사용하고 있다면, input대신 sys.stdin.readline을 사용할 수 있다. 단, 이때는 맨 끝의 개행문자까지 같이 입력받기 때문에 문자열을 저장하고 싶을 경우 .rstrip()을 추가로 해 주는 것이 좋다.

또한 입력과 출력 스트림은 별개이므로, 테스트케이스를 전부 입력받아서 저장한 뒤 전부 출력할 필요는 없다. 테스트케이스를 하나 받은 뒤 하나 출력해도 된다.

해당 15552번 문제에 대해 해결하고자 다음과 같은 참조코드를 짜보았다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    int a[100] = { 0, };
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) {
        scanf("%d %d", &a, &b);
        a[i] = a+b;
    }
    
    return 0;
}

하지만 문제가 생겼다. 이미 a라는 변수를 정수형으로 사용하고 있었기 떄문이다.

동일한 변수명에 대해 타입이 두개면 사용이 불가능하다.


우리가 주의해야할게 함수에서는 이름이 달라고 받는 유형을 구분하는게 가능하다. (함수의 오버로딩을 생각해보자)(링크) 하지만 변수에서는 선언하는 형식이 달라질때 유형을 구분하는게 불가능하다.


내가 생각해낸 정답>

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    int result[100] = { 0, };
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        scanf("%d %d", &a, &b);
        result[i] = a+b;
    }
    for (int i = 0; i < n; i++) 
    {
        printf("%d\n", result[i]);
    }
    

    return 0;
}

근데 이걸 제출했을때는 런타임에러가 났다. 자세히 보니 OutOfBounds에 따른 런타임에러라고 한다. 근데 뭔지 이해는 못했다.

나중에 문제를 자세히 보니 이렇게 있었다.

각 테스트케이스마다 A+B를 한 줄에 하나씩 순서대로 출력한다.

그래! 한줄입력 한줄출력방식(SISO:단일입력 단일출력)방식이다.

그래서 바로 고쳐보았다.

최종정답>

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    int result[10] = { 0, };
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        scanf("%d %d", &a, &b);
        result[i] = a+b;
        printf("%d\n", result[i]);
    }

    return 0;
}

[백준]11021번 A+B - 7

처음에 이렇게 짰더니 문제가 생겼다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    //int result[10] = { 0, };
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        scanf("%d %d", &a, &b);
        //result[i] = a+b;
        //printf("%d\n", result[i]);
        printf("Case #%d: %d\n",++i, a + b);
    }
   

    return 0;
}

다시 생각해보니 당연히 틀린게, 변수 i에 값이 누적되기 때문이다.

그래서 이렇게 나온다.

5 1 1 Case #1: 2 2 3 Case #3: 5 3 4 Case #5: 7

따라서 i에는 값이 누적되지 않게, 단순히 i에서 값을 꺼내와서 그 값에 1을 임시로 더해서 출력하는 방식을 취해야 한다. 아래와 같다.

※고찰

++ii+1의 차이에 대해 생각해보는 시간을 가졌다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        scanf("%d %d", &a, &b);
        printf("Case #%d: %d\n",i+1, a + b);
    }
    return 0;
}

[백준]11022번 A+B - 8

아까랑 비슷하다 이번에는 결과뿐만 아니라 피연산자도 출력되도록 한다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        scanf("%d %d", &a, &b);
        printf("Case #%d: %d + %d = %d\n",i+1,a,b, a + b);
    }
    return 0;
}

[백준]2438번 별찍기 - 1

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        for (int j = 0; j <= i; j++)
        {
            printf("*");
        }
        printf("\n");
    }
    return 0;
}

[백준]2439번 별찍기 - 2

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++) 
    {
        for (int j = 0; j < n-i-1; j++)
        {
            printf(" ");
        }
        for (int j = 0; j < i+1; j++)
        {
            printf("*");
        }

        printf("\n");
    }
    return 0;
}

코드리뷰: n에 5가 입력되면 각 행마다 5만큼의 자리가 확보되어야 한다.

그래서 한 행안에 공백을 채우는 for문, *을 채우는 for문이 존재한다.

물론 위 코드는 가독성이 떨어지는 면이 있다.만약

0행에 대해서는 4개의 공백과 1개의 별

1행에 대해서는 3개의 공백과 2개의 별

2행에 대해서는 2개의 공백과 3개의 별

3행에 대해서는 1개의 공백과 4개의 별

4행에 대해서는 0개의 공백과 5개의 별

이렇게 패턴이 만들어지므로 일반화되는 알고리즘을 짜야 한다.

따라서 좀더 쉽게 보면 공백크기와 별 개수 크기는 5로 갖다.

그리고 행고 별은 증가하고 그 만큼 공백의 크기는 줄어든다.

그래서 다음과 같이 짤수도 있다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, a, b;
    scanf("%d", &n);
    
    for (int i = 1; i <= n; i++) 
    {
        for (int j = 1; j <= n-i; j++)
        {
            printf(" ");
        }
        for (int j = n-i; j < n; j++)
        {
            printf("*");
        }

        printf("\n");
    }
    return 0;
}

(행을 1로 두고 접근하면 더 편하다.)

[교재 8장] 9page, 배열 선언 초기화를 이용한 합과 출력

#define _CRT_SECURE_NO_WARNINGS
#define SIZE 6
#include <stdio.h>

int main(void) {
    double score[] = { 89.3, 79.2, 84.83, 76.8, 92.52, 97.4 };
    double sum = 0;

    //for문을 이용하여 합을 구함
    for (int i = 0; i < SIZE; i++)
    {
        sum += score[i];
        printf("score[%d] = %.2f\n", i, score[i]);
    }
    printf("성적의 합은 %.2f이고 평균은 %.2f이다.\n", sum, sum / SIZE);
    
    return 0;
}

위 예시에서 다음과 같이 쓸수도 있지 않을까 생각할 수 있다.

#define _CRT_SECURE_NO_WARNINGS
#define SIZE 6
#include <stdio.h>

int main(void) {
    double score[6];
    score =  = { 89.3, 79.2, 84.83, 76.8, 92.52, 97.4 };
    double sum = 0;

    //for문을 이용하여 합을 구함
    for (int i = 0; i < SIZE; i++)
    {
        sum += score[i];
        printf("score[%d] = %.2f\n", i, score[i]);
    }
    printf("성적의 합은 %.2f이고 평균은 %.2f이다.\n", sum, sum / SIZE);
    
    return 0;
}

하지만 일반 변수에서는 다음과 같이 나눠쓰는게 가능하지만 배열의 선언 및 초기화에서는 이런 구문이 불가능하다. 컴파일 시 다음과 같은 오류가 뜬다.

E0137: 식이 수정할 수 있는 value여야 합니다.

[백준]10952번 A + B - 5

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int a, b;
    while (1)
    {
        scanf("%d %d", &a, &b);
        if (a == 0 && b == 0) {
            break;
        }
        printf("%d\n", a + b);
    }

    return 0;
}

[백준]10951번 A + B - 4

문제가 너무 쉬워서 다음과 같이 작성했고, 당연히 맞을 줄 알았다. 근데,,,!?!?!

#define _CRT_SECURE_NO_WARNINGS
#define SIZE 6
#include <stdio.h>

int main(void) {
    int a, b;
    while (1)
    {
        scanf("%d %d", &a, &b);
        if (0<= a  && a <= 10) {
            if (0 <= b && b <= 10) {
                break;
            }
        }
        printf("%d\n", a + b);
    }

    return 0;
}

아니,, 출력 초과가 떴다. 살짝 쪽팔리긴 한데, 이건 내가 모르는 개념을 적용시켜야 만이 풀수 있는 문제였다. 바로 EOF에 대한 개념을 알고 있어야 풀 수 있는 문제였다.

(너무 부끄러워 할 필요는 없을 것 같다ㅇ) 다음 글을 보자.

C언어 운영체제와 상관없이 파일의 끝에 도달했을때 언제나 특별한 값을 반환하도록 한다. 이때 EOF는 “End Of File”의 약자로, 파일의 끝을 표현하기 위해 -1로 정의된 상수입니다.

따라서 아래와 같이 코드를 작성할 수 있다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int a, b;
    while (1)
    {
        if (scanf("%d %d", &a, &b) == EOF) {
            break;
        }
        printf("%d\n", a + b);
    }
    return 0;
}

코드리뷰: if문에 주목해보자. 조건문에는 입력값이 EOF이라면 참이라는 건데, 이는 파일의 끝에 도달했냐를 물어보는 구문이다. 그래서 파일의 끝에 도달했는지 확인해서 도달했으면 break를 통해 밖으로 탈출한다는 뜻이다.

이전 코드를 제출했을때 출력초과가 나온 이유는 while문의 끝을 정해놓지 않았기 때문에 scanf()가 무한으로 돌아서 결국 메모리 할당범위를 넘어섰기 떄문이다.

참고로 위 코드는 다음과 같이 간소화시킬수도 있을 것 같다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int a, b;
    while (scanf("%d %d", &a, &b) != EOF)//a,b의 값이 존재할때까지 반복
    {
        printf("%d\n", a + b);
    }
    return 0;
}

※고찰

C언어만의 고유한 특징 하나를 또 하나 알게 되어 기쁘다.

최대 몇개의 입력이 들어오는지 모를때 유용하게 쓰일 것 같으니 알아두자.

아 그리고 while의 조건문에 scanf()함수를 때린다는 아이디어가 신선했다. 좀더 찾아보니 값이 두개 들어와야 whlie문 안으로 들어가서 동작을 수행하는 코드를 짜려면 다음과 같이 짤 수도 있다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int a, b;
    while (scanf("%d %d", &a, &b) == 2)
    {
        printf("%d\n", a + b);
    }
    return 0;
}

while의 조건문에서 ==2를 넣어주어 값이 두개 들어왔는지 확인할 수 있단다.(신기ㅎ)


이제 4단계, 1차원 배열로 넘어왔다.

[백준]10807번 개수 세기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, cmp,cnt = 0;
    int result[100] = { 0, };
    scanf("%d", &n);

    for (int i = 0; i < n; i++)
    {
        scanf("%d", &result[i]);
    }
    scanf("%d", &cmp);
    for (int i = 0; i < n; i++)
    {
        if (cmp == result[i])
        {
            cnt++;
        }
    }
    printf("%d\n", cnt);
    return 0;
}

[백준]10872번 X보다 작은 수

처음에 아래처럼 짰는데 런타임에러가 났다..

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, x;
    int result[100] = { 0, };
    scanf("%d %d", &n, &x);



    for (int i = 0; i < n; i++)
    {
        scanf("%d", &result[i]);
    }
    
    for (int i = 0; i < n; i++)
    {
        if ( result[i] < 5)
        {
            printf("%d ", result[i]);
        }
    }
    printf("\n");
    return 0;
}

내 생각에 계속해서 int result[100] = { 0, };이 코드부분 떄문에 런타임에러(OutOfBounds)증상이 나타나는 것 같다.

위 구문을 쓰지 않는 방식을 문제를 해결해야 할 것 같다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int n, x, a;
    scanf("%d %d", &n, &x);
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a);
        if (a < x)
            printf("%d ", a);
    }
    return 0;
}

위 코드에서는 배열을 쓰지 않아서 런타임에러(OutOfBounds)가 발생하지 않았다.

그리고 값을 따로 저장할 필요가 없지 않나?라는 생각이 들었다.

콘솔 내부에서 어떻게 동작하는지 알아보면,

10 5를 입력하고 엔터를 치면 그 순간에서 순차적으로 변수n,x에 값이 박히는 거다.

나는 처음에 space를 치는 순간에 n에 값이 박히고 그다음 enter를 치는 순간에 x에 값이 박히는 줄로 이해했다. 하지만 그게 아니었다.

[실습]6-2번

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int x,sum=0,e=0;

    while (1)
    {

        scanf("%d", &x);
        if (x < 0)
        {
            printf("wrong\n");
            continue;
        }
        for (int i = 0; i < x; i++) {
            e = (int)pow(2.0, (float)i); // pow 함수의 반환값이 double이므로 int로 캐스팅
            printf("%d\n", e);
            sum += e;
        }
        break;
    }
    printf("=%d", sum);
    return 0;
}

에러가 발생하지 않았다. 에러가 발생해야 정상인데 말이다. pow()함수를 쓰려면 math.h헤더파일이 있어야 하는데, 없어서 이렇게 문제가 생겼다.

그래서 수정해주면,

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void) {
    int x,sum=0,e=0;

    while (1)
    {
        scanf("%d", &x);
        if (x < 0)
        {
            printf("wrong\n");
            continue;
        }
        for (int i = 0; i < x; i++) {
            e = (int)pow(2.0, (float)i); // pow 함수의 반환값이 double이므로 int로 캐스팅
            printf("%d\n", e);
            sum += e;
        }
        break;
    }
    printf("=%d", sum);
    return 0;
}

제대로 작동된다.(math헤더파일을 안넣으면 0만 출력된다.ㄷㄷ)

[실습]6-4번

image-20231230154210231
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void) {
    int c,f,cnt=0, state = 0;
    scanf("%d", &c);
    f = round(1.8 * c + 32);
    
    do
    {
        int x;
        scanf("%d", &x);
        if (x > f)
        {
            printf("large\n");
            cnt++;
        }
        else if (x < f)
        {
            printf("small\n");
            cnt++;
        }
        else
        {
            printf("correct ");
            cnt++;
            printf("%d\n", cnt);
            state = 1;
        }

    } while (state == 0);

    
    return 0;
}

[실습]7-1번

image-20231230154210231
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

int main(void) {
    int result[100] = { 0, };
    int i=0,cnt=0,temp;
    while (1)
    {
        scanf("%d", &temp);
        if (temp == 0)
        {
            break;
        }
        result[i] = temp;
        i++;
    }
    printf("%d\n", i);

    for (int k = i-1; k >= 0; k--)
    {
        printf("%d ", result[k]);
    }
    return 0;
}

[실습]7-2번

image-20231230154210231
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    float result[100] = { 0.0, };
    float temp,sum=0, mean;
    int i=0;
    while (1)
    {
        scanf("%f", &temp);
        if (temp == 0)
        {
            break;
        }
        result[i] = (float)temp;
        i++;
    }
    for (int k = 0; k <i; k++)
    {
        sum += result[k];
    }
    mean = sum / (float)i;
    printf("%.1f\n", mean);

    for (int k = 0; k < i; k++)
    {
        if (result[k] < mean)
        {
            printf("%.1f ", result[k]);
        }
    }

    return 0;
}

코드리뷰>코드 짜면서 한가지 헷갈린 부분이 캐스트연산자에 대한 부분이다.

분자를 분모로 나눈다고 하자. 10을 3으로 나누어서 3.33이 출력되도록 의도하고 싶다면, 나눠짐을 당하는? 분자를 float로 바꿔주는 작업이 필요하고 이걸 캐스트연산자가 수행할 수 있다. 참고로 이때 분모는 정수가 아니냐 이것도 바꿔줘야 하는거 아니냐 생각할 수 있는데, 내가 해본 결과, 분자만 실수이면 분모가 정수이더라도 반환값이 분자의 datatype을 따른다는 것을 알아냈다.

[실습]7-3번

image-20231230154210231
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int a[5] = { 0, };
    int b[5] = { 0, };
    for (int i = 0; i < 5; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 0; i < 5; i++)
    {
        scanf("%d", &b[i]);
    }
    for (int i = 0; i < 5; i++)
    {
        if (a[i] != b[i])
        {
            printf("not same");
            break;
        }
        if (i == 4)
        {
            printf("same");
        }
    }
    return 0;
}

[실습]7-4번

image-20231230154210231
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int temp, k = 0;
    int num[100] = { 0, };
    while (1)
    {
        scanf("%d", &temp);
        if (temp == 0)
        {
            break;
        }
        num[k] = temp;
        k++;
    }

    for (int i = 0; i < k - 1; i++)
    {
        for (int j = 0; j < k - 1 - i; j++)
        {
            if (num[j] > num[j + 1])
            {
                temp = num[j];
                num[j] = num[j + 1];
                num[j + 1] = temp;
            }
        }
    }
    for (int i = 0; i < k; i++)
    {
        printf("%d ", num[i]);
    }
    return 0;
}

자유낙하운동 코드

기존에 있던 코드에다가 다시 짜고 있다. 어쩌다 보니 예전에 동작후에 그 다음 사이크에서 값이 입력되지 않은 문제를 해결하지 못했는데, 이 코드에서는 동작이 되더라, 잘 모르겠는데, 변수 설정에 문제가 있었다. 변수i에 값을 여러개를 받다 보니 입력버퍼를 비워주지 않아 문제가 생겨 main()밖에다가 변수선언을 해주었더니 문제가 해결되었다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>

char ball[3] = "●";


void gotoxy(int x, int y)
{
    COORD Pos;
    Pos.X = x;
    Pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
}

int main(void) {
    int currentHeight = 0;
    while (1)
    {
        gotoxy(0, 0);
        printf("                                                  ");
        gotoxy(0, 0);
        printf("30이상의 값을 입력해주세요.(이외에는 break) : ");

        scanf("%d", &currentHeight);
        if (currentHeight < 30) {
            printf("Break\n");
            Sleep(1000);
            break;
        }
        do
        {
            for (int y = 25 - currentHeight; y < 24; y++)
            {
                gotoxy(20, y);
                printf("%s", ball);
                //fflush(stdout);
                Sleep(50); //시간을 지연시키는 함수(공이 내려오는 시간조절)
                gotoxy(20, y);
                printf(" ");
            }
            currentHeight /= 2;

            for (int y = 24; y > 24 - currentHeight; y -= 1)
            {
                gotoxy(20, y);
                printf("%s", ball);
                //fflush(stdout);
                Sleep(70);
                gotoxy(20, y);
                printf(" ");
            }

        } while (currentHeight != 1);
    }
    return 0;
}

하지만 위 코드에서 값을 여러개 받지만 공의 움직일이 살짝 이상해서 아래 원형코드를 보고 다시 짜려고 한다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>

void gotoxy(int x, int y)
{
    COORD Pos;
    Pos.X = x;
    Pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
}

int main(void) {
    char ball[3] = "●";
    int y, currentHeight = 24; //check - 처음 떨어질 위치

    do
    {
        for (y = 25 - currentHeight; y < 24; y++)
        {
            gotoxy(20, y);
            printf("%s", ball);
            Sleep(50); //시간을 지연시키는 함수(공이 내려오는 시간조절)
            gotoxy(20, y);
            printf(" ");
        }
        currentHeight = (currentHeight - currentHeight / 2);

        for (y = 24; y > 24 - currentHeight; y -= 1)
        {
            gotoxy(20, y);
            printf("%s", ball);
            Sleep(70);
            gotoxy(20, y);
            printf(" ");
        }

    } while (currentHeight != 1);
    printf("\n");

    return 0;
}

언어:

카테고리:

업데이트:

댓글남기기