#include <stdio.h>
#include <time.h>
#include <stdlib.h>

// 물고기 6마리가 있다.
// 어항에 시간이 지나면 죽는다.
// 물이 증발하기전에 어항에 물을 줘서 물고기를 살려주세요.

int level;
int arrayFish[6];
int* cursor;

void initData();
void printFishes();
void decreaseWater(long elapsedTime);
int checkFishAlive();

int main() {


    long startTime = 0; // 게임 시작 시간
    long totalElapsedTime = 0; // 총 경과 시간
    long prevElapsedTime = 0; // 직전 경과 시간 ( 최근에 물을 준 시간 간격)

    int num; // 몇 번 어항에 물을 줄 것인지, 사용자 입력
    initData();

    cursor = arrayFish; // cursor[0], cursor[1]

    startTime = clock(); // 현재 시간을 millisecond(1000분의 1초 단위로 반환)
    while (1)
    {
        printFishes();
        printf("몇 번 어항에 물을 주시겠어요?");
        scanf_s("%d", &num);

        // 입력 값 체크
        if (num < 1 || num > 6)
        {
            printf("\n 입력값이 잘못되었습니다.\n");
            continue;
        }

        // 총 경과 시간  
        totalElapsedTime = (clock() - startTime) / CLOCKS_PER_SEC; // 초단위로 계산
        printf("총 경과시간 : %ld\n", totalElapsedTime);

        // 직전 물 준 시간 (마지막으로 물 준 시간) 이후로 흐른 시간 
        prevElapsedTime = totalElapsedTime - prevElapsedTime;
        printf("최근 경과 시간 : %ld 초\n", prevElapsedTime);

        // 어항의 물을 감소 (증발)
        decreaseWater(prevElapsedTime);

        // 사용자가 입력한 어항에 물을 준다.
        // 1. 어항의 물이 0이면? 물을 주지 않는다.
        if (cursor[num - 1] <= 0)
        {
            printf("%d 번 물고기는 이미 죽었습니다. 물을 주지 않습니다.\n", num);
        }
        // 2. 어항의 물이 0이 아닌 경우 물을 준다. (100을 넘지 않는지 체크)
        else if (cursor[num - 1] + 1 <= 100)
        {
            printf("%d 번 어항에 물을 줍니다.\n\n", num);
            cursor[num - 1] += 1;
        }

        // 레벨업을 할 것인지 확인 (레벨업은 20초마다 한번씩 수행)
        if (totalElapsedTime / 20 > level - 1)
        {
            level++; // level : 1 -> level : 2 -> level : 3
            printf(" *** 축 레벨업 ! 기존 %d 레벨에서 %d 레벨로 업그레이드 ***\n\n", level - 1, level);

            // 최종 레벨 5
            if (level == 5)
            {
                printf("\n\n축하합니다. 최고 레벨을 달성하였습니다. 게임을 종료합니다.");
                exit(0);
            }
        }

        // 모든 물고기가 죽었는지 확인
        if (checkFishAlive() == 0)
        {
            printf("모든 물고기가 죽었습니다.\n");
            exit(0);

        }
        else {
            // 최소 물고기 한 마리 이상은 살아 있음.
            printf("물고기가 아직 살아있어요!\n");
        }
        prevElapsedTime = totalElapsedTime;

        // 10초 -> 15초 (5초 : preElapsedTime -> 15초) -> 25초  (10초)
    }

    return 0;
}

void initData()
{
    level = 1; // 게임 레벨 (1~5)
    for (int i = 0; i < 6; i++)
    {
        arrayFish[i] = 100; // 어항의 물 높이 (0~100)
    }
}

void printFishes()
{
    printf("%3d번 %3d번 %3d번 %3d번 %3d번 %3d번\n", 1, 2, 3, 4, 5, 6);
    for (int i = 0; i < 6; i++)
    {
        printf(" %4d ", arrayFish[i]);
    }
    printf("\n\n");
}

void decreaseWater(long elapsedTime)
{
    for (int i = 0; i < 6; i++)
    {
        arrayFish[i] -= (level * 3 * (int)elapsedTime); // 3 난이도 조절을 위한 값 
        if (arrayFish[i] < 0)
        {
            arrayFish[i] = 0;
        }
    }
}

int checkFishAlive() {
    for (int i = 0; i < 6; i++)
    {
        if (arrayFish[i] > 0)
            return 1; // 1 = True 
    }
    return 0;
}

1. 포인터와 배열로 값 호출하기 (서로 비교)

#include <stdio.h>

int main(){
    // 배열
    int arr[3] = {5, 10, 15};
    int *ptr = arr;
    for(int i=0; i<3;i++)
    {
        printf("배열 arr[%d] 의 값 : %d\n", i, arr[i]);
    }
     for(int i=0; i<3;i++)
    {
        printf("배열 ptr[%d] 의 값 : %d\n", i, ptr[i]);
    }
    return 0;
}

실행결과 

배열 arr[0] 의 값 : 5
배열 arr[1] 의 값 : 10
배열 arr[2] 의 값 : 15
배열 ptr[0] 의 값 : 5
배열 ptr[1] 의 값 : 10
배열 ptr[2] 의 값 : 15

1. 포인터와 배열로 주소 및 값 호출하기 (서로 비교)

 

#include <stdio.h>

int main(){
    // 배열
    int arr[3] = {5, 10, 15};
    int *ptr = arr;
    for(int i=0; i<3;i++)
    {
        printf("배열 arr[%d] 의 값 : %d\n", i, arr[i]);
    }
     for(int i=0; i<3;i++)
    {
        printf("배열 ptr[%d] 의 값 : %d\n", i, ptr[i]);
    }

    ptr[0] = 100;
    ptr[1] = 200;
    ptr[2] = 300;

    for(int i=0; i<3;i++)
    {
        // printf("배열 arr[%d] 의 값 : %d\n", i, arr[i]);
        printf("배열 arr[%d] 의 값 : %d\n", i, *(arr + i));
    }
    for(int i=0; i<3;i++)
    {
        printf("배열 ptr[%d] 의 값 : %d\n", i, *(ptr + i));
    }
    // *(arr + i) == arr[i] 똑같은 표현
    // arr == arr 배열의 첫번째 값의 주소와 동일 == &arr[0]
    printf("arr 자체의 값 : %d\n", arr);
    printf("arr[0] 의 주소 : %d\n", &arr);

    printf("arr 자체의 값이 가지는 주소의 실제 값: %d\n", *arr); // *(arr + 0)
    printf("arr[0]의 실제 값: %d\n", *&arr[0]); 

    // *& 는 아무것도 없는 것과 같다. &는 주소이며, *는 그 주소의 값이기 때문에 
    // *& 는 서로 상쇄된다. 
    printf("\n\n*&는 서로 상쇄된다.\n\n");
    printf("arr[0]의 실제 값: %d\n", *&*&*&*&*&arr[0]); 
    printf("arr[0]의 실제 값: %d\n", arr[0]); 
    return 0;
}

실행결과

배열 arr[0] 의 값 : 5
배열 arr[1] 의 값 : 10
배열 arr[2] 의 값 : 15
배열 ptr[0] 의 값 : 5
배열 ptr[1] 의 값 : 10
배열 ptr[2] 의 값 : 15
배열 arr[0] 의 값 : 100
배열 arr[1] 의 값 : 200
배열 arr[2] 의 값 : 300
배열 ptr[0] 의 값 : 100
배열 ptr[1] 의 값 : 200
배열 ptr[2] 의 값 : 300
arr 자체의 값 : -427641220
arr[0] 의 주소 : -427641220
arr 자체의 값이 가지는 주소의 실제 값: 100
arr[0]의 실제 값: 100


*&는 서로 상쇄된다.

arr[0]의 실제 값: 100
arr[0]의 실제 값: 100

3. 포인터로 배열 값 변경해보기.

#include <stdio.h>

void changeArray(int * ptr);

int main(){
   int arr2[3] = {10, 20, 30};
   changeArray(arr2);
   for(int i=0; i<3; i++)
   {
       printf("%d\n", arr2[i]);
   }
   return 0;
}

void changeArray(int * ptr)
{
    ptr[2] = 50;
}

실행결과

10
20
50

#include <stdio.h>

void changeArray(int * ptr);

int main(){
   int arr2[3] = {10, 20, 30};
   changeArray(&arr2[0]);
   for(int i=0; i<3; i++)
   {
       printf("%d\n", arr2[i]);
   }
   return 0;
}

void changeArray(int * ptr)
{
    ptr[2] = 50;
}

- main함수내에서  changeArray 함수를 사용할 때 

changeArray(arr2);의 실행결과와

changeArray(&arr2[0]);의 실행결과가 같다.

 

그렇기에,

첫 번째 해당하는 배열의 주소를 던져서 거기로부터 3번째 위치의 배열의 값을 바꾸는 것은 올바른 동작이라고 볼 수 있다.

1. 연산자의 우선순위와 결합방향의 의미

3 + 4 X 5 ÷ 2 - 10

"위의 수식은 덧셈, 뺄셈 보다는 곱셈, 나눗셈을 먼저 계산해야 한다."

이것이 바로 '연산자의 우선순위' 이다.

 

그리고 곱셈과 나눗셈중에서 

"곱셈과 나눗셈은 왼쪽에 먼저 등장하는 것부터 순서대로 계산한다!"

 

이것이 바로 '결합방향' 이다.

 

즉, 우선순위가 동일한 두 연산자가 하나의 수식에 존재하는 경우,

어떠한 순서대로 연산하는가를 결정하는 것이다.

2. 연산자의 우선순위와 결합방향 표

순위 연산기호 연산자 결합방향
1위 () 함수호출 ->
[] 인덱스
-> 간접지정
. 직접지정
++ 후위증가 (postix)
-- 후위증가 (postix)
후위 증가 
후위 감소
2위 ++ 전위증가 (predix)
-- 전위증가 (predix)
전위 증가
전위 감소
<-
sizeof 바이트 단위 크기 계산
~ 비트 단위 NOT
! 논리 NOT
-, + 부호 연산(음수와 양수의 표현
& 주소연산
* 간접지정 연산
3위 (casting) 자료형 변환 <-
4위 *, /, % 곱셈, 나눗셈 관련 연산 ->
5위 +, - 덧셈, 뺄셈 ->
6위 <<, >> 비트이동 ->
7위 <, >, <=, >= 대소비교 ->
8위 ==, != 동등비교 ->
9위 & 비트 AND ->
10위 ^ 비트 XOR ->
11위 | 비트OR ->
12위 && 논리AND ->
13위 || 논리OR ->
14위 ? : 조건연산 <-
15위 =, +=, -=, *=, /=, %=,
<<=, >>=, &=, ^=, |=
대입연산 <-
16위 , 콤마연산 ->

 

+ Recent posts