아임'준
[C언어 기초] 구조체 본문
C언어 / 구조체 / 구조체 배열 / 함수에의 구조체 사용 / strcpy, strcmp
*해당 글에 있는 코드들은 모두 복사해서 사용할 수 있게끔 만들어두었습니다. 주석만 보고 이해하려고 하지 말고 코드를 복사해서 직접 실행하며 그 결과를 통해 이해하고자 하면 더 도움이 될것입니다. 물론 그냥 복사 붙여넣기 하는 것보다 본인이 직접 코드를 타이핑하는 것이 이해와 후에 사용할 때에 더 큰 도움이 될 것이니 이 점 명심하고 공부해주시기 바랍니다.
이제 구조체에 대해서 배워보도록 하겠다.
구조체는 우리가 직접 필요한 자료형을 새로 만드는 것이라고 생각하면 된다.
다음과 같은 상황을 생각해보자.
당신은 고등학교 담임 선생님이다. 당신은 반 아이들의 정보를 저장하고 싶다. 저장하고 싶은 정보는 이름, 나이, 키 등을 저장하고 싶다. (당신 반에 1년 꿇은 아이도 있고 빠른년생인 아이도 있다고 생각하자) 그러면 해당 내용들을 어떻게 저장해야할까? 다음과 같이 하나하나 변수를 선언하여 저장해야할까?
char name1[20];
char name2[20];
.
.
.
char name30[20];
int age1;
int age2;
.
.
.
int age30;
float height1;
float height2;
.
.
.
float height30;
지금까지 우리는 많은 자료형을 배워왔지만 위와 같은 상황에 적합한 방법은 딱히 생각나지 않는다. 이러한 문제를 해결하기 위해 우리는 구조체를 쓸 수 있다. 위의 상황 같은 경우 구조체를 다음과 같이 쓸 수 있다.
struct student{
char name[20];
int age;
float height;
};
여기서 student가 구조체이다. 이제 우리는 이름, 나이, 키를 따로 저장하지 않고 student라는 구조체를 통해 한번에 처리할 수 있다. 우리는 기본 자료형들을 이용하여 새로운 자료형을 만들어낸 것이다. 참고로 구조체 안의 char name[20] 등 내부에 선언된 것들을 우리는 멤버라고 부른다.
위와 같은 경우 우리는 새로운 자료형인 student를 만든 것이며 student의 멤버로는 name, age, height가 있다.
struct (구조체 이름){
(멤버 선언)
};
그럼 이렇게 만든 구조체를 어떻게 쓸 수 있을까? 아래 예시를 보자.
struct (구조체 이름) (변수명);
//위에서 만든 예시로 생각해보면
struct student info;
우리는 이제 info라는 이름의 student 타입 변수를 만든 것이다. 그럼 이제 한 학생에 대한 정보를 하나로 묶어서 관리할 수 있다.
우리가 원하는 내용을 저장할 곳은 구조체의 멤버인데 구조체의 멤버에는 다음과 같이 접근할 수 있다.
변수명.멤버명 = (값)
//위의 예시를 적용하였을 때
strcpy(info.name, "June");
info.age = 18;
info.height = 185;
strcpy()라는 처음 보는 함수가 나와서 당황했을 수도 있다. 혹시 0.5 배열 글에서 문자열은 선언할 때 초기화 안하면 대입을 못 한다고 했던 것 기억하는가? 그렇기 때문에 쓰이는 것이 strcpy() 함수이다.
strcpy() 함수는 string.h에 들어있기 때문에 사용하기 전에 #include <string.h>를 해줘야한다
#include <string.h>
strcpy(a,b)
//string copy
//문자열 b를 문자열 a에 복사, 붙여넣기
strcmp(a,b)
//string compare
//문자열 a와 b의 앞부터 아스키코드값을 비교해서 a<b일 때 음수, a=b일 때 0, a>b일 때 양수를 반환한다
//대소문자도 아스키 코드 값이 다르기 때문에 완전히 같은 문자열만 0을 반환한다
사용방법은 위에 나와있다.
strcpy(info.name,"June"); 이라고 적혀있으니 June이라는 문자열을 student구조체의 변수 info 안의 멤버 name 배열에 복사해서 저장한것이다.
strcmp()는 지금은 굳이 설명할 이유 없지만 다음 포스트에서 다뤄보도록 하겠다.
이제 자료형의 별칭에 대해서 말해보도록 하겠다.
우리가 자료형을 사용할 때 다음과 같이 사용한다.
int a;
char b; //기본 내장 자료형들
struct student info; //student라는 구조체를 사용하기 위해 struct student라고 적음
기본 내장 자료형들은 짧고 간결한데 우리가 만든 구조체를 사용하기 위해서는 앞에 struct라고 붙여줘야 한다. 물론 별로 신경쓰이지 않을수도 있지만 우리는 모든 자료형의 별칭을 지정할 수 있다.
typedef는 다음과 같이 자료형의 별칭을 지정할 수 있게 해준다.
typedef int newint; //int를 myint라는 별칭을 사용하여 부르기
typedef int* pnewint //int*를 pnewint라는 별칭을 사용하여 부르기
int a; //오류
int* b; //오류
newint a; //정상적으로 작동하는 코드
pnewint b; //정상적으로 작동하는 코드
그럼 이것을 구조체를 선언할 때 다음과 같이 쓸 수 있다.
typedef struct student{
char name[20];
int age;
float height;
} stu;
stu info;
이제 변수를 선언할 때 struct student 가 아닌 stu 라고 적음을 통해 변수를 선언할 수 있다.
사실 위처럼 사용하면 처음에 student라는 이름을 굳이 지정해줄 필요조차 없어진다. 이름이 무엇이든 그냥 stu라는 별칭으로 불리게 되기 때문에 typedef struct{} stu; 로 바로 진행해도 된다,
다시 처음의 문제를 생각해보자. 아무리 구조체 선언하여 사용한다고 해도 각각의 정보를 하나로 묶지 못하면 의미가 없다. 당연히 구조체도 배열로 선언하여 사용할 수 있다. 이제 다음과 같이 구조체를 사용할 수 있다.
#include <stdio.h>
#include <string.h>
typedef struct student{
char name[20];
int age;
float height;
} stu;
int main(){
stu info[30];
for(int i=0;i<30;i++){
char *temp;
printf("%d번째 학생 이름은?",i+1);
scanf("%s",temp);
strcpy(info[i].name,temp);
printf("%d번째 학생 나이는?",i+1);
scanf("%d",&info[i].age);
printf("%d번째 학생 키는?",i+1);
scanf("%f",&info[i].height);
printf("%s %d %.1f\n",info[i].name,info[i].age,info[i].height);
}
}
배열로 선언된 문자열을 선언 단계에서 초기화를 못했으니 temp를 이용하여 strcpy 함수로 저장해주었다. 이런식으로 구조체도 배열로 사용할 수 있으며 여러 상황에서 유용하게 쓰일 수 있다. 나중에 자료구조 포스팅을 올릴 때 여러모로 쓰일 것이다.
구조체를 함수에서 쓰는 것에도 주의가 필요하다. 예를 들어 구조체를 반환하는 함수일 때는 그 함수의 자료형은 당연히 해당 구조체로 적어야 한다.
또한 구조체 역시 다른 자료형과 마찬가지로 내부 데이터를 변경하고 싶을 때는 포인터형 매개변수를 사용해야하며 이때 포인터형 매개변수로 선언된 구조체의 멤버에 접근할 때는 stu.name이 아니라 stu->name과 같이 . 대신 ->를 사용하여야 한다.
아래는 후에 자료구조에서 다룰 힙을 사용하는 코드 중 하나를 가져온 것인데 내용이 중요한 것이 아니라 아래처럼 heaptype* 과 line* 이라고 포인터형 구조체 매개변수로 선언된 것들에 대해서 -> 라는 멤버 접근 방식을 사용했음을 보여주기 위함이다. 나머지는 나머지는 배열과 비슷한 주의사항을 가지고 있으니 이를 잘 천천히 생각하며 함수에서 구조체를 사용하면 될 것이다.
void insert(heaptype *h,line *ori) // length 값 기준 힙 정렬 삽입
{
int i;
i=++h->hcount;
while((i != 1) && (ori->length < h->lines[i/2].length)){
h->lines[i] = h->lines[i/2];
i /= 2;
}
h->lines[i] = *ori;
}
이번 포스팅이 내가 작성하려고 한 마지막 C언어 기초 포스팅이 될 것이다. 당연히 내가 알고 있는 것을 전부 담지는 못했지만 평소 헷갈리는 개념이 있다거나 할 때 내가 쓴 글을 다시 보면 도움이 될 것이라고 생각했다. 자주 쓰는 헤더파일에 대해서는 설명을 담고 싶었으나 글 내용이 너무 길어질 것 같아 나중에 추가로 올릴 것이다. 자료구조도 다뤄보고 싶은데 계획만 있고 언제 실행에 옮길지는 아직 미정이다. 내 포스팅을 통해 얻어가는 것이 많았으면 한다.
질문, 오타 지적, 오류 지적 등은 댓글로 환영합니다.
'[C] > [C : 개념]' 카테고리의 다른 글
[C언어] getchar / putchar (0) | 2021.02.15 |
---|---|
[C언어] 파일 입출력 (0) | 2021.02.15 |
[C언어 기초] 함수 (0) | 2021.01.28 |
[C언어 기초] 포인터 : 배열과 포인터, 메모리 할당 (0) | 2021.01.09 |
[C언어 기초] 배열 : 일차원 배열, 다차원 배열, 배열로 선언된 문자열 (2) | 2021.01.05 |