분명 포인터만 정리하고 안하려고했는데 구조체를 만나서 이것도 정리할겸 글을 하나 더 쓰기로 하였다.
파이썬에서도 쓸수는 있는 기능이라고 알고있는데 한번도 써본적이 없고, 자바의 class랑 매우 비슷하다고 생각된다.
우선 기본 사용예부터 보겠다.
#include <stdio.h>
int copy_str(char *dest, char *src);
struct book {
char name[20];
char auth[20];
char pub[20];
int borrowed;
};
int main() {
struct book bk;
copy_str(bk.name, "Book Name");
copy_str(bk.auth, "Author");
copy_str(bk.pub, "Publisher");
bk.borrowed = 0;
printf("%s \n", bk.name);
printf("%s \n", bk.auth);
printf("%s \n", bk.pub);
printf("%d \n", bk.borrowed);
return 0;
}
int copy_str(char *dest, char *src) {
while (*src) {
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return 1;
}
책 제목、작가, 출판사를 받고 기록하는 구조체이다. java의 class와 매우 유사하다. class처럼 상속구조를 만들수도 있다 (뒤에 나온다.)
이처럼 복수의 자료형을 한번에 정리할때 유용하게 사용할 수 있는 도구이다. struct book bk를 bk02로 설정한다면 또 다른 구조체를 쓸 수 있는것이다.
명심할점은 구조체 struct역시 자료형으로 취급되며
구조체도 포인터가 있다.
#include <stdio.h>
int copy_str(char *dest, char *src);
struct human {
char name[20];
int age;
int gender;
};
int main() {
struct human hm;
struct human *ph = &hm;
return 0;
}
human 구조체를 hm이라 선언하고 똑같이 구조체 자료형포인터를 설정하고 그 포인터에 hm의 주소 (&hm)을 넣어준다.
그렇다면 이를 어떻게 활용할 수 있을까? 방법은 두개이다.
#include <stdio.h>
int copy_str(char *dest, char *src);
struct human {
char name[20];
int age;
int gender;
};
int main() {
struct human hm;
struct human *ph = &hm;
(*ph).age = 30;
return 0;
}
이러면 ph의 age가 30으로 지정된다.
하지만 좀 불편해서 우리는 다른 방법을 주로 사용한다
#include <stdio.h>
int copy_str(char *dest, char *src);
struct human {
char name[20];
int age;
int gender;
};
int main() {
struct human hm;
struct human *ph = &hm;
ph->age = 30;
return 0;
}
-> 화살표로 보이는 이 기호를 통해 지정할 수 있는것이다.
여기까지가 구조체의 포인터이다. 기존의 포인터와 크게 다를게 없다.
#include <stdio.h>
struct test {
int c;
int *pointer;
};
int main() {
struct test t;
struct test *pt = &t;
int i = 0;
t.pointer = &i;
*t.pointer = 3;
printf("%d \n", i);
*pt->pointer = 4;
printf("%d \n", i);
return 0;
}
구조체 내부에 포인터가 있는 경우도 기존의 포인터와 동일하게 작동한다.
구조체 포인터가 구조체를 포인팅하고(pt = &t)
pointer의 값을 구조체 선언 t, 혹은 구조체 포인터 pt를 통해서 수정할 수 있다.
유의할점은 pt->pointer는 (pt->pointer)의 값이라는 뜻이다. ->, .같은 연산자들은 *보다 우선순위에 있다.
#include <stdio.h>
struct test {
int c;
int *pointer;
};
int main() {
struct test t, t2;
t1.c = 1;
t2 = t1;
}
구조체도 기존의 변수로 int a = 0; b = a; 하는것처럼 동일하게 할 수 있다.
#include <stdio.h>
struct test {
int age;
int gender;
};
int add_one(int *a);
int set_human(struct test *a, int age, int gender);
int main() {
struct test ta;
set_human(&ta, 10, 1);
printf("%d, %d\n", ta.age, ta.gender);
return 0;
}
int add_one(int *a) {
*a += 1;
return 0;
}
int set_human(struct test *a, int age, int gender) {
a->age = age;
a->gender = gender;
return 0;
}
구조체를 변수처럼 취급하기에 우리는 구조체를 함수의 변수로 사용할 수 있다.
인자로 구조체 포인터를 설정하고, 구조체 변수 ta의 주소 &ta를 함수의 인자로 넣어서 작동하게 만드는것이다.
#include <stdio.h>
struct employee {
int age;
int wage;
};
struct company {
struct employee data;
char name[10];
};
int main() {
struct company TS;
TS.data.age = 31;
TS.data.wage = 10000;
printf("%d, %d\n", TS.data.age, TS.data.wage);
return 0;
}
Java의 상속처럼 구조체도 구조체안에 구조체가 있을 수 있다.
위의 예시처럼, company 구조체 안에 employee 구조체를 data로 선언하고 이를 main함수에서 company.data.age같은 방식으로 접근할 수 있는것이다.
#include <stdio.h>
struct test {
int a;
int b;
} t;
int main() {
t.a = 10;
t.b = 20;
return 0;
}
이런식으로 구조체 뒤에 변수명을 써주면 해당 변수가 바로 구조체로 선언되게 된다.
#include <stdio.h>
struct test {
int a;
int b;
} t = {10, 20};
int main() {
t.a = 10;
t.b = 20;
return 0;
}
또 이런식으로 뒤에 struct안의 변수들의 값을 순서대로 적어주면 선언과 동시에 값 설정도 가능하다.
공용체는 그렇게 자주사용하는 기능은 아니라는데 생각보다 유용하다고 하다. 공용체 안에 선언된 변수가 같은 주소를 공유하는것이다. 즉 하나의 값을 바꾸면 다른값도 변한다.
#include <stdio.h>
union A {
int i;
char j;
};
int main() {
union A a;
a.i = 0x12345678;
printf("%x", a.j);
return 0;
}
// 출처 https://modoocode.com/71
이와 관련해서 빅엔디안, 리틀엔디안같은 메모리 읽는 방식에 관한 설명이 있는데 나중에 따로 하겠다.
파이썬에서는 Dict기능을 써서 키 별로 값을 정해줄 수 있는데, c에서는 dict를 만들기 쉽지 않다.
dx dy문제들을 풀때 이 dict형이 유용하게 쓰일 수 있는데, c에서는 enum을 쓰면 쉽게 풀 수 있다.
enum = { N, E, W, S };
이런식으로 선언하게되면 N은 0, E는 1..같은 값을 가지게 된다.
만약
enum = { N = 4, E, W, S };
로 선언하게 된다면, E = 5, W = 6 같이 선언되게 된다.
이제 c의 핵심기능은 대부분 배웠으니, 알고리즘 문제를 풀어보면서 언어에 적응하고 cpp를 공부해봐야한다.