본문 바로가기
[ C언어 ]/- C언어 실습연습

C언어 - [구조체, 구조체 포인터, 구조체배열, 구조체포인터배열]

by MRG 2021. 5. 16.
728x90
반응형
728x90

▣ 구조체는 쉽게 생각하면 

c언어로 배열을 만들 때 하나에 자료형으로 선언하고 사용합니다.

int game[10] 이렇게 하나에 자료형으로 사용하게 되면 우리가 game에 대한 

여러 가지 정보를 관리하려면 이렇게 

char gameName [10], int gameNumber [10], int gameScore [10] 이런 식으로 하나하나

선언해주고 관리해야합니다. 

이렇게 되면 코드가 너무 길어지고 관리하는 게 복잡할 수 있습니다.

그래서 사용하는게 바로 구조체입니다. 

 

▣ 먼저 구조체는 함수 외부에서 선언해야 합니다. 

struct라는 자료형식으로 지정해주고 이름을 정해줍니다. 

구조체 이름은 나중에 함수안에서 선언할 변수와 이름이 헷갈릴 수 있기 때문에 

대문자로 시작해주세요. 

이 시작이 나중에 객체지향언어에서 클래스와 동일하게 적용됩니다. 

 

▣ 그리고 {} 스코프로 범위를 정의해주시고, 안에 내가 Game이라는 구조체에서 관리할 자료들을 

선언해줍니다. 

struct에 끝에는 꼭 }; 세미콜론을 붙어주세요.

 

▣ 그리고 이제 이 구조체를 사용하려면 main함수에서 동일하게 선언을 해줘야 합니다. 

struct를 자료형식을 붙여주시고 Game 구조체 이름 그리고 game 변수 이름으로 지정해줍니다. 

그럼 game이라는 변수에서는 Game에 구조체를 접근하고 사용하게 됩니다. 

배열과 동일하게 { 스코프 안에 초기값을 지정해주시면 됩니다.

 

▣ 여기서 주의해야할껀 배열은 배열[0] 이렇게 인덱스 번호로 접근했다고 하면  

구조체에서는. 점 접근 연산자로 접근해야 합니다. 그리고. gameNumber 접근할 변수를 적어주시고 = 대입 연산자로

값을 넣어주시면 됩니다. 그럼 우리가 변수를 접근하는 것과 동일하게 값을 넣을 수 있고

출력할 수 있습니다. 

 

▣ 그럼 이제 초기화가 아닌 직접 값을 대입해보겠습니다. 

 

▣ game.gameName = "Good Game"으로 접근하면 이상하게 오류가 나오게 됩니다. 

이건 우리가 배열을 생각해보면 됩니다. 

혹시 배열에 대해 모르는 분은 C언어 공부에 배열 부분을 공부해주세요.

 

▣ 배열은 이렇게 하나하나 기준 주소를 기준으로 지정한 변수이기 때문에 

game.gameName 배열에 이름으로 대입해서 넣을 수 없습니다.

이건 gameName을 주소이기 때문입니다. 

그럴 때에는 

 

▣ #include <string.h> 문자열에 관한 헤더 파일을 먼저 선언해주세요.

그리고 strcpy()라는 함수를 작성합니다. 

그럼 이렇게 어떤 걸 입력해야 할지 예시가 나옵니다. 

 

▣ strcpy(내가 복사해서 넣을 대상 문자열 , 그리고 복사할 문자열) 이렇게 매개변수를 넣어주시면 

문자열을 복사해서 하나하나 메모리에 복사가 됩니다. 

그리고 game.gameNumber = 2, game.gameScore = 94.5를 각각 대입해서 값을 확인해주세요.

그럼 잘 들어가는 걸 확인할 수 있습니다. 

 

▣ 자 이번에는 구조체에 struct Game game; 이렇게 선언하기가 번거롭습니다. 

그럴 때 구조체 } 끝에 game;으로 선언해주세요.

그럼 전역 변수로 선언되기 때문에 바로 main함수에서 사용할 수 있습니다. 

 

▣ 그런데 위에 있는 방법처럼 하면 전역 변수이기 때문에 문제가 될 수 있습니다.

그럴 때에는 typedef으로 구조체에 별칭을 지정할 수 있습니다.

typedef struct _Game으로 지정해주고

마지막에 } Game; 구조체에 별칭을 정해줍니다. 

그럼 main에서 Game == struct_Game이 됩니다. 

그럼 main함수에서 Game game으로 선언하면 바로 선언하고 사용할 수  있습니다. 

 

▣ 이번에는 직접 메모리를 할당해서 만들어보겠습니다. 

이렇게 하는 이유는 뒤에서 메모리에 관해 설명할 때 이어서 하겠습니다.

우선 메모리를 할당해서 만들어보겠습니다. 

#include <stdlib.h>을 선언해주세요.

그래야 메모리를 할당하는 함수를 사용할 수 있습니다.

 

▣ Game *game을 포인터를 선언해주세요. 

malloc(sizeof(Game)); Game 구조체 크기만큼 사이즈를 선언해주세요.

malloc함수는 동적 할당하는 함수입니다. 쉽게 이야기하면 *game 포인터 주소에

malloc(구조체 크기)만큼 선언해서 포인터 주소에 선언해주세요.

 

▣ 그런데 여기서 중요한 건 game은 주소를 저장하는 변수이기 때문에 

포인터에서 대입되어 있는 값을 접근하려면 *game으로 접근했던 것처럼 

->로 접근해줘야 합니다. 

 

 

▣ 이제 메모리를 확인해보겠습니다. F9를 이용해서 중단점을 찍고 

F5로 컴파일을 한 후에 메모리를 확인해보면 *game에 d8 4c b7 00에 값이 들어있습니다. 

그걸 확인해보면 

 

▣ 반대로 입력을 하면 Good Game이 들어있는 메모리를 확인할 수 있습니다.

 

▣ 그리고 이렇게 sizeof() 함수로 메모리 크기를 확인해보면 구조체 크기가 큰 메모리 기준으로 정렬이 되어 사용되는 걸 확인할 수 있습니다. 

정리해보자면 구조체를 사용할 때 메모리가 가장 큰 메모리 기준으로 사용하기 때문에 사용하지 않는 메모리가 있게 됩니다. 

 

▣ 그렇기 때문에 메모리를 힙 영역으로 직접 활 당해서 해야 메모리를 좀 더 효율적으로 사용할 수 있습니다. 

 

▣ 그럼 메모리에 있는 값들을 한꺼번에 0으로 초기화하려면 어떻게 해야 할까요

memset() 함수로 메모리에 있는 값을 초기화할 수 있습니다.

memset(메모리, 초기화할 값, 크기)를 넣어주시고 

printf() 함수로 출력해보면 0으로 초기화되는 걸 확인할 수 있습니다.

 

▣ 그리고 이렇게 메모리끼리 복사할 수 도 있습니다.

memcpy(대상, 원본, 크기)로 하게 되면 원본에 있는 값을 대상 메모리에 복사해서 넣어줍니다.

그리고 printf() 함수로 출력해주시면 메모리에 들어 있는 값이 복사돼서 출력되는 걸 확인할 수 있습니다.

 

▣ 그런데 여기서 문제가 있습니다. 구조체를 만들면 하나에 하나에 구조체만 관리할 수 있습니다. 

이렇게 Game game [5] 배열로 여러 개에 구조체를 관리할 수 있습니다. 

그럼 배열처럼 game [0]. gameNumber로 관리할 수 있습니다. 

 

▣ 그리고 이렇게 *game [5] 포인터 배열로 하나하나 선언해서도 사용할 수 있습니다. 

 

728x90
반응형

댓글