본문 바로가기
c언어

c언어 변수 이용하여 문제 풀기(은행 계좌 구현하기, 초기화를 한 번만 하기, 난수 발생기 만들기, 10진수를 2진수로 출력하기, 하노이의 탑 문제 풀기)

by 개발자 L 2022. 12. 6.
반응형

c언어 변수 이용하여 문제 풀기(은행 계좌 구현하기, 초기화를 한 번만 하기, 난수 발생기 만들기, 10진수를 2진수로 출력하기, 하노이의 탑 문제 풀기)

네 안녕하세요, 이번 포스팅에서는 여러 가지 변수를 이용하여 문제들을 풀어보며 코딩 실력을 향상하는 시간을 가져보려 합니다.

변수의 사용은 소스 코드를 연결을 하는 것과도 관련이 있기 때문에 정말 중요합니다.

그럼 바로 시작해보도록 하겠습니다.

 

1. static 지정자, extern 지정자 이용하여 문제 풀기

첫 번째 파트에서는 정적 변수 지정자인 static 지정자와 외부 참조 연결 지정자인 extern 지정자를 이용하여 문제를 풀어보도록 하겠습니다.

저장 유형 지정자 중에서는 이 둘이 제일 많이 쓰이기 때문에 정말 중요합니다.

그럼 바로 시작하겠습니다.

 

1 - 1. 은행 계좌 구현하기

제일 처음으로 은행 계좌를 구현해보도록 하겠습니다.

정적 변수를 이용을 하여 지금까지 사용자가 입금을 한 총액을 기억하게 만들 것입니다.

그래서 함수가 호출이 되어 금액이 추가로 입력이 될 때 마다 금액이 늘어나도록 만들 것입니다.

그럼 바로 시자하도록 하겠습니다.

#include <stdio.h>

void save();

int main()
{
    printf("====================\n");
    printf("입금\t출금\t잔고\n");
    printf("====================\n");

    save(10000);
    save(50000);
    save(-20000);
    save(40000);
    printf("====================");

    return 0;

}

void save(int amount)
{
    static long bal = 0;

    if(amount >= 0)
    {
        printf("%d\t\t", amount);
    }

    else
    {
        printf("\t%d\t", -amount);
    }

    bal += amount;

    printf("%d\n", bal);
}

이렇게 static 지정자를 이용하여 계속 누적이 되도록 구현을 했습니다.

그럼 결과도 한 번 보도록 하겠습니다.

====================
입금    출금    잔고
====================
10000           10000
50000           60000
        20000   40000
40000           80000
====================

이렇게 잘 나오는 것을 볼 수가 있습니다.

 

1 - 2. 초기화를 한 번만 하기

이번에는 초기화를 시키는 예제를 한 번 작성을 해볼 건데,

초기화는 한 번만 하게 설정을 할 것입니다.

여기서는 static 지정자를 이용하여 시도 횟수를 저장을 하고,

사용자가 초기화를 할 때 이 변수를 1로 만듭니다.

그럼 바로 해보도록 하겠습니다.

#include <stdio.h>

void init();

int main()
{
    init();
    init();
    init();

    return 0;
}

void init()
{
    static int inited = 0;

    if(inited == 0)
    {
        printf("init(): 네트워크 장치를 초기화합니다.\n");

        inited = 1;
    }

    else
    {
        printf("init(): 이미 초기화가 되어있으므로 초기화를 진행하지 않습니다.\n");
    }
}

이렇게 구현을 했습니다.

여기서는 static 지정자로 인하여 init()에 있는 데이터가 그대로 살아있기 때문에 초기화는 한 번만 진행이 되고,

그 이후로는 초기화가 진행되지 않는다는 메시지를 받을 수 있습니다.

그럼 결과를 보도록 하겠습니다.

init(): 네트워크 장치를 초기화합니다.
init(): 이미 초기화가 되어있으므로 초기화를 진행하지 않습니다.
init(): 이미 초기화가 되어있으므로 초기화를 진행하지 않습니다.

이렇게 잘 나온 것을 볼 수가 있습니다.

 

1 - 3. 난수 발생기 만들기

이번에는 난수 발생기를 만들건대, 전에는 하나의 파일로만 만들었지만, 이번에는 외부 참조를 이용하여 만들어보도록 하겠습니다.

extern 지정자를 이용을 할 것이고, 두 개의 소스 파일을 필요로 합니다.

그래서 두 개의 소스 파일을 하나의 폴더에 저장을 한 후에, 함수를 호출하는 방식으로 구현을 할 것입니다.

그럼 바로 시작을 하도록 하겠습니다.

제일 먼저 난수를 발생시킬 때 쓸 소스파일입니다.

#define SEED 17

int MUL = 25173;
int INC = 13849;
int MOD = 65536;

static unsigned int seed = SEED;

// 정수 난수 생성 함수
unsigned rand_i()
{
    seed = (MUL * seed + INC) % MOD; // 난수의 시드값 설정

    return seed;
}

// 실수 난수 생성 함수
double rand_f()
{
    seed = (MUL * seed + INC) % MOD; // 난수의 시드값 설정

    return seed / (double)MOD; // 0.0에서 1.0 사이로 제한
}

이렇게 작성을 했고요,

이번에는 이 소스 내에 있는 함수나 변수 등을 불러오는 소스파일입니다.

#include <stdio.h>

extern unsigned rand_i();
extern double rand_f();

extern int MOD; 

int main()
{
    MOD = 10;

    for(int i = 0; i < 10; i++)
    {
        printf("%d", rand_i());
    }

    return 0;
}

 

이렇게 한 번 작성을 해봤습니다.

그럼 결과도 한 번 보도록 하겠습니다.

0 9 6 7 0 9 6 7 0 9

숫자가 이렇게 규칙성이 없이 나온 것을 볼 수가 있습니다.

반응형

 

2. 순환 호출을 이용하여 문제 풀기

이번에는 순환 호출을 이용하여 문제를 풀어보겠습니다.

함수는 자기 자신을 호출할 수 있다는 특성을 이용하여 문제를 해결하는 겁니다.

그럼 바로 시작하도록 하겠습니다.

 

2 - 1. 10진수를 2진수로 출력하기

이번에는 10진수를 2진수로 출력하는 방법을 알아보겠습니다.

기본적으로 c언어에는 10진수를 2진수로 출력을 해주는 기능이 없습니다.

그래서 이러한 기능을 순환 호출을 이용하여 구현을 해야 합니다.

우리가 10진수를 2진수로 변환을 할 때 어떤 임의의 숫자를 계속 2로 나누어서 나머지가 있으면 1을 쓰고, 없으면 0을 썼죠?
바로 그러한 방법을 써서 구현을 할 건데,

그 과정에서 순환 호출이 쓰입니다.

계속 2로 나누어 나머지가 있고 없고의 여부에 따라 1과 0으로 나열을 해주는 것입니다.

그럼 바로 작성을 해보도록 하겠습니다.

#include <stdio.h>

void binary_number();

int main()
{
    binary_number(50);

    printf("\n");

    return 0;
}

void binary_number(int n)
{
    if(n > 0)
    {
        binary_number(n / 2);

        printf("%d", n % 2);
    }
}

이렇게 작성을 했습니다.

저는 2진수로 변환하고 싶은 숫자에 50을 적었습니다.

그럼 결과가 어떻게 나오는지 한 번 보도록 하겠습니다.

110010

결과가 잘 나온 것을 확인할 수가 있습니다.

 

2 - 2. 최대 공약수 구하기

이번에는 최대 공약수를 구해보도록 하겠습니다.

이 역시도 순환 호출을 이용을 할 건데,

우리가 순환 호출을 이용하여 구현할 수학적 방법의 이름은 '유클리드 호제법'입니다.

이 방법은 이런 특징을 이용한 수학적 접근법입니다.

두 수 a와 b의 최대 공약수는 b와 a, b를 나눠서 얻은 나머지의 최대 공약수와 같고, a와 0의 최대 공약수는 a이다.

이걸 이용하여 구현을 해보도록 하겠습니다.

#include <stdio.h>

int gcd();

int main()
{
    printf("%d\n", gcd(50, 28));
}

// a는 b보다 커야 한다.
int gcd(int a, int b)
{
    if(b == 0)
    {
        return a;
    }

    else
    {
        return gcd(b, a % b);
    }
}

이렇게 소스를 작성을 했습니다.

제가 알아볼 숫자는 50과 28입니다.

그럼 결과가 어떻게 나오는지 한 번 보도록 하겠습니다.

2

결과도 문제없이 잘 나오는 것을 볼 수가 있습니다.

 

2 - 3. 하노이의 탑 문제

이번에는 하노이의 탑을 직접 구현을 해보도록 하겠습니다.

다들 하노이의 탑을 아시리라 생각합니다.

하노이의 탑은 고대 인도 신화에 나오는 탑인데,

고대 인도의 바라나시(영어식으로는 베나레스임)라는 성지에 세계의 중심이 있으며,

그곳에는 다이아몬드 기둥이 3개가 박혀있는데,

그중에는 신이 천지창조를 할 때 구멍이 뚫린 64장의 순금으로 된 크기가 다른 원판이 크기가 큰 순서대로 쌓여있다고 합니다.

그리고 이를 사원에 있는 승려들에게 하루에 원판을 하나씩 옮겨서 나머지 두 개의 기둥 중 아무 곳이든 좋으니 한 곳에 전부 넣으라고 그랬습니다.

그리고 거기에서 절대로 지켜야 하는 룰이 있는데,

그건 바로 '크기가 더 큰 원판을 절대 크기가 더 작은 원판 위에 쌓지 말 것'입니다.

그래서 이 규칙대로 한 번 코드를 작성해보도록 하겠습니다.

#include <stdio.h>

void hanoi_tower(int n, char from, char tmp, char to);

int main()
{
    hanoi_tower(5, 'A', 'B', 'C');
}

void hanoi_tower(int n, char from, char tmp, char to)
{
    if(n == 1)
    {
        printf("원판 1을 %c에서 %c로 옮깁니다.\n", from, to);
    }

    else
    {
        hanoi_tower(n - 1, from, to, tmp);

        printf("원판 %d를 %c에서 %c로 옮깁니다.\n", n, from, to);

        hanoi_tower(n - 1, tmp, from, to);
    }
}

64개는 너무 많아서 5개로 해봤습니다.

그럼 결과가 어떻게 나오는지 한 번 보도록 하겠습니다.

원판 1을 A에서 C로 옮깁니다.
원판 2를 A에서 B로 옮깁니다.
원판 1을 C에서 B로 옮깁니다.
원판 3를 A에서 C로 옮깁니다.
원판 1을 B에서 A로 옮깁니다.
원판 2를 B에서 C로 옮깁니다.
원판 1을 A에서 C로 옮깁니다.
원판 4를 A에서 B로 옮깁니다.
원판 1을 C에서 B로 옮깁니다.
원판 2를 C에서 A로 옮깁니다.
원판 1을 B에서 A로 옮깁니다.
원판 3를 C에서 B로 옮깁니다.
원판 1을 A에서 C로 옮깁니다.
원판 2를 A에서 B로 옮깁니다.
원판 1을 C에서 B로 옮깁니다.
원판 5를 A에서 C로 옮깁니다.
원판 1을 B에서 A로 옮깁니다.
원판 2를 B에서 C로 옮깁니다.
원판 1을 A에서 C로 옮깁니다.
원판 3를 B에서 A로 옮깁니다.
원판 1을 C에서 B로 옮깁니다.
원판 2를 C에서 A로 옮깁니다.
원판 1을 B에서 A로 옮깁니다.
원판 4를 B에서 C로 옮깁니다.
원판 1을 A에서 C로 옮깁니다.
원판 2를 A에서 B로 옮깁니다.
원판 1을 C에서 B로 옮깁니다.
원판 3를 A에서 C로 옮깁니다.
원판 1을 B에서 A로 옮깁니다.
원판 2를 B에서 C로 옮깁니다.
원판 1을 A에서 C로 옮깁니다.

결과가 이렇게 잘 나오는 것을 볼 수가 있습니다.

 

여기까지 여러 가지 변수들을 이용하여 문제를 풀어보는 시간을 가져보았는데요,

다음 포스팅부터는 배열에 대하여 다루도록 하겠습니다.

긴 글 읽어주신 독자분들께 진심으로 감사드립니다 ~

반응형

댓글