본문 바로가기

programming study/C

[나도코딩]C 프로그래밍 - 입문부터 게임 개발까지 (8)(2020.12.29)

본 내용은 해당 강의 토대로 작성


구조체

많은 변수가 있을 때, 그 변수들을 관련있는 것끼리 묶어서 선언할 수 있다. 이를 구조체라고 한다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  return 0;
}

구조체의 선언은 main 함수 전에 한다. GameInfo라는 구조체는 name,year,price,company라는 정보를 받는다.

구조체 사용

생성한 구조체는 변수 생성시 자료형처럼 앞에 붙여준다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  struct GameInfo gameInfo1; //struct GameInfo가 자료형처럼 앞에 붙여준다.

  gameInfo1.name = "나도게임";
  gameInfo1.year = 2017;
  gameInfo1.price = 50;
  gameInfo1.company = "나도회사";
  return 0;
}

나도게임 이라는 한 게임을 등록한다고 했을 때, 그 게임에 관련된 정보를 gameInfo1 라는 변수에 넣는다고 선언 하면 기존 구조체 GameInfo에 있는 name,year,price,company에 그 값들을 넣을 수 있다.

구조체 출력

저장한 값들을 구조체를 불러서 출력할 수 있다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  struct GameInfo gameInfo1; //gameInfo1 입력

  gameInfo1.name = "나도게임";
  gameInfo1.year = 2017;
  gameInfo1.price = 50;
  gameInfo1.company = "나도회사";

  printf("-- 게임 출시 정보 --\n"); //gameInfo1 출력
  printf(" 게임명    : %s\n", gameInfo1.name);
  printf(" 발매년도  : %d\n", gameInfo1.year);
  printf(" 가격     : %d\n", gameInfo1.price);
  printf(" 제작사    : %s\n", gameInfo1.company);
  return 0;
}

앞서 등록했던 나도게임에 대한 정보는 구조체에 의해서 각각 gameInfo1.name,gameInfo1.year,gameInfo1.price,gameInfo1.company에 있다.

스크린샷 2020-12-29 오후 7.37.33

구조체를 배열처럼 초기화

똑같은 종류의 데이터들을 가진 너도게임구조체로 넣을 수 있다. 배열을 선언하는 것처럼 초기화 할 수 있다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{

  struct GameInfo gameInfo2 = {"너도게임",2017,100,"너도회사"}; //gameInfo2 입력

  printf("-- 또다른 게임 출시 정보 --\n"); //gameInfo2 출력
  printf(" 게임명    : %s\n", gameInfo2.name);
  printf(" 발매년도  : %d\n", gameInfo2.year);
  printf(" 가격     : %d\n", gameInfo2.price);
  printf(" 제작사    : %s\n", gameInfo2.company);
  return 0;
}

스크린샷 2020-12-29 오후 7.41.17

구조체 배열

나도게임의 정보와 너도게임의 정보를 배열을 선언하는 것처럼 구조체에 한번에 넣을 수 있다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  struct Gameinfo gameArray[2] = 
  {
    {"나도게임",2017,50,"나도회사"},
    {"너도게임",2017,100,"너도회사"}
  }
  return 0;
}

gameArray에 두 개의 공간이 생기고 그 곳에 각각의 데이터가 들어간다.

구조체 포인터

포인터를 사용해서 구조체의 정보를 불러올 수 있다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  ---위 생략---
  gamePtr = &gameInfo1;
  printf("\n\n-- 미션맨의 게임 출시 정보 --\n");
  printf(" 게임명    : %s\n", (*gamePtr).name);
  printf(" 발매년도  : %d\n", (*gamePtr).year);
  printf(" 가격     : %d\n", (*gamePtr).price);
  printf(" 제작사    : %s\n", (*gamePtr).company);
  return 0;
}

gamPtr은 선언된 포인터 변수이다. 입력했던 &gameInfo1의 값들을 가져오는데, 불러올 때는 (*gamePtr) 처럼 괄호와 별을 사용해준다.

화살표를 사용한 더 직관적이고 편한 방법이 있다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  ---위 생략---
  gamePtr = &gameInfo1;
  printf("\n\n-- 미션맨의 게임 출시 정보 --\n");
  printf(" 게임명    : %s\n", gamePtr->name);
  printf(" 발매년도  : %d\n", gamePtr->year);
  printf(" 가격     : %d\n", gamePtr->price);
  printf(" 제작사    : %s\n", gamePtr->company);
  return 0;
}

별도의 기호없이 화살표 만으로 값들을 가져올 수 있다.

스크린샷 2020-12-29 오후 8.27.00

구조체 안의 구조체

구조체 안에 구조체를 만들 수 있다. 연관 업체 게임을 저장하기 위해 구조체 선언에 아래처럼 추가한다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
  struct GameInfo * friendGame; //연관 업체 게임(포인터)
};
int main(void)
{
  ---위 생략---
  gameInfo1.friendGame =  &gameInfo2;
  printf("\n\n-- 연관 업체의 게임 출시 정보 --\n");
  printf(" 게임명    : %s\n", gameInfo1.friendGame->name);
  printf(" 발매년도  : %d\n", gameInfo1.friendGame->year);
  printf(" 가격     : %d\n", gameInfo1.friendGame->price);
  printf(" 제작사    : %s\n", gameInfo1.friendGame->company);
  return 0;
}

연관 업체 게임 friendGame은 선언할 때, 포인터로 되어있었다. 그러므로 &gameInfo2를 받아와서 포인터처럼 화살표로 값들을 불러올 수 있다.

스크린샷 2020-12-29 오후 8.43.45

typedef

typedef는 쓰기 길고 복잡한 자료형을 별명을 지정할 수 있다.

#include <stdio.h>
int main(void)
{
  typedef int 정수;
  typedef float 실수;
  정수 정수변수 = 3; // int i = 3;
  실수 실수변수 = 3.23f; // float f = 3.23f;
  return 0;
}

이렇게, int, float를 간단하게 한글로 바꿔 사용할 수 있다. typedef로 새로운 별명을 지정했어도 기존의 자료형도 사용할 수 있다.

구조체에서 응용

구조체에서 typedef를 사용할 수 있다.

#include <stdio.h>
struct GameInfo 
{
  char * name;
  int year;
  int price;
  char * company;
};
int main(void)
{
  typedef struct GameInfo 게임정보;
  게임정보 game1;
  game1.name = "한글 게임";
  game1.year = 2015;
  return 0;
}

GameInfo게임정보로 사용할 수 있게 된다.

구조체 선언에서 사용하기

typedef와 함께 선언할 수 있다.

#include <stdio.h>
typedef struct GameInformation {
  char * name;
  int year;
  int price;
  char * company;
  struct GameInfo * friendGame;
} GAME_INFO;
int main(void)
{
  GAME_INFO game2;
  game2.name ="한글 게임2";
  game2.year = 2014;
  return 0;
}

구조체 GameInformationtypedef에 의해서 GAME_INFO 로 사용할 수 있다. 선언문에서, GameInforamtion이라는 구조체 명이 없어도 GAME_INFO를 쓸 수 있다.

너, 내 집사가 되어라

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

//5마리의 고양이가 있다.
//아무 키나 눌러서 랜덤으로 고양이를 뽑는다.
//5마리 모두 다 수집을 해서 열심히 키우면 되는 게임.
//중복발생 가능. 

//고양이
//이름, 나이, 성격, 키우기 난이도(레벨)

typedef struct {
  char * name; //이름
  int age; //나이
  char * character; //성격
  int level; //키우기 난이도 (1~5, 올라갈 수록 어려움)
} CAT;

//현재까지 보유한 고양이
int collection[5] = {0,0,0,0,0};

//전체 고양이 리스트
CAT cats[5];

void initCats(); //고양이 정보 초기화

void printCat(int selected);

int checkCollection();



int main(void)
{
  srand(time(NULL));

  initCats();
  while (1)
  {
    printf("두근두근~! 어느 고양이의 집사가 될까요?\n아무 키나 눌러서 확인하세요!");
    getchar(); //키입력 대기

    int selected = rand() % 5; //0~4 사이의 숫자 반환
    printCat(selected);    //뽑은 고양이 정보 출력
    collection[selected] =1;//고양이 뽑기 처리

    int collectAll = checkCollection(); //고양이를 다 모았는지 검사한 후 break
    if(collectAll== 1)
    {
      break;
    }


  }

  return 0;
}

void initCats() //선택될 고양이
{
  cats[0].name = "깜냥이";
  cats[0].age = 5;
  cats[0].character = "온순";
  cats[0].level = 1;

  cats[1].name = "귀요미";
  cats[1].age = 3;
  cats[1].character = "예민";
  cats[1].level = 2;

  cats[2].name = "수줍이";
  cats[2].age = 7;
  cats[2].character = "잠만잠";
  cats[2].level = 3;

  cats[3].name = "까꿍이";
  cats[3].age = 2;
  cats[3].character = "시끄러움";
  cats[3].level = 4;

  cats[4].name = "시루";
  cats[4].age = 1;
  cats[4].character = "욕심쟁이";
  cats[4].level = 5;
}

void printCat(int selected) //선택된 고양이의 정보
{
  printf("\n\n===당신은 이 고양이의 집사가 되었어요! ===\n\n");
  printf(" 이름      : %s\n", cats[selected].name);
  printf(" 나이      : %d\n", cats[selected].age);
  printf(" 특징(성격) : %s\n", cats[selected].character);
  printf(" 성격      : ");
  for(int i=0;i<cats[selected].level;i++)
  {
    printf("%s", "★");
  }
  printf("\n\n");
}

int checkCollection()
{
  //1.현재 보유한 고양이 목록 출력 2.다 모았는지 여부 반환
  int collectAll = 1;  //기본값 1

  printf("\n\n ===보유한 고양이 목록입니다=== \n\n");
  for(int i=0; i<5; i++)
  {
    if(collection[i]==0) // 고양이 수집 X
    {
      printf("%10s", "(빈 박스)");
      collectAll = 0; //다 모으지 못한 상태
    }
    else //고양이 수집 O
    {
      printf("%10s", cats[i].name);
    }

  }
  printf("\n=============================================\n\n");

  if (collectAll) 
  {
    printf("\n\n 축하합니다! 모든 고양이를 다 모았어요. 열심히 키워주세요\n\n");
  }

  return collectAll;   

}

스크린샷 2020-12-29 오후 10.48.48

느낀점

무난하게 잘 이해하고 해낼 수 있었다! struct의 개념이 객체와 조금 비슷하다고 생각했다.

마지막 프로젝트에는 시루를 넣어봤다 ㅎㅎ