코딩 꼭 같이 해보면서 해보세요.. ㅠㅠ 그럼 더 이해 잘 될것 같네요..
만약 학생을 데이터로 표현하고 싶다고하면, 이름, 학번, 학년을 데이터로 저장해야 한다.
이때 char name[] = "홍길동";
int id = 1871000;
int grade = 1;
이런식으로 3개씩 선언하여 사용해야한다.
하지만 학생을 100명 표현해야한다면?? --> 많이 힘들다... ㅠㅠ
그래서! 구조체가 나왔당
struct student {//구조체의 이름이 student인 구조체 선언
char name[30];//char[30] 이름 배열
int id;//학번
int grade;//학년
};
로 구조체를 만들 수 있다.
main에서 사용할때는 struct student person;
으로 선언할 수 있다.
여기서
struct student
가 자료형이고,person
이 변수명이예요 주의.
구조체를 정의하고 만들었다면, 사용도 해야겠죠!
#include <stdio.h>
struct student {//구조체의 이름이 student인 구조체 선언
char name[30];//char[30] 이름 배열
int id;//학번
int grade;//학년
};
int main(void) {
struct student person = { "홍길동", 1871000, 1 };
printf("%s\n", person.name);
printf("%d\n", person.id);
printf("%d\n", person.grade);
scanf("%s", person.name);
scanf("%d", &person.id);
scanf("%d", &person.grade);
return 0;
}
main함수에서 구조체를 선언한 후에, 값을 바로 할당하는 것을 해봤습니다. 선언하고 바로 할당하고 싶다면 중괄호로 구조체안의 내용물을 채워준다고 생각하면 될 거 같아요.
그래서 "홍길동"은 name에, 1871000은 id에, 1은 grade에 각각 맵핑됩니다. 그리고 11~13까지는 출력하는 부분입니다. 구조체변수에 접근하고 싶다면 구조체변수의이름.변수명
으로 접근할 수 있어요. 여기서는 person이 구조체의 변수명이니까, person.name
, person.id
, person.grade
로 접근하는 것이죠.
그리고 입력을 하고싶다! 하면 똑같이 scanf를 사용해서 구조체의 어디에 입력할 것인지 정하면됩니다. scanf("%s", person);
이런건 절대 안됩니다! 구조체에 직접 입력을 할 순 없습니다. 구조체의 어떤변수 에 입력할 것인지 확실하게 정해주어야 합니다.
여기서
scanf("%s", person.name);
은 왜 &가 없냐? -> 배열의 이름은? 배열의 시작주소! 가 여기서도 적용됩니다. 따라서 %s로 문자열을 입력받을 때, person.name은 구조체 안에있는 name배열의 시작주소이지요? 그래서 &가 안붙습니다. 다른변수들은 일반 변수사용시와 같이 &를 꼭! 붙여주어야 합니다.
저희가 int arr[10];
이렇게 자료형에 대한 배열을 만들었었죠. 구조체또한 가능합니다. 구조체도 엄연히 사용자 정의__자료형__ 이기 때문이죠.
struct student person[10];
으로 선언할 수 있습니다. 여기서부터는 제가 구조체좀 쉽게 쓰려고 합니다.
typedef struct student {
char name[30];
int id;
int grade;
}Student;
이렇게 하게되면 struct person 을 Person으로 맵핑해서 사용하겠다는 겁니다. 즉, typedef A B는 A를 B로 사용하겠다는 것이죠. 사용 할때에는 Student a;
로하면 struct student a;
와 같은 효과입니다.
typedef int data;
data i = 10; 이렇게 하게되면 data는 int 인 것입니다. 따라서 위의 typedef 문은 Student을 사용할 때 struct student을 사용하겠다는 것입니다.
typedef 를 적용하면,
Student person[10];
이렇게 구조체배열 을 선언할 수 있죠. 전에 저희가 int 형 배열을 선언해서 [0], [1] 이렇게 접근한 것 처럼 구조체배열도 똑같이 접근할 수 있습니다. arr[0] 이렇게하면 구조체배열의 첫번째 값에 접근한겁니다. 그렇다면 person[0].name
은 첫 번째 구조체의 name 변수가 되는거죠. 마찬가지로 person[0].id, person[0].grade
에 값을 쓰거나 읽을 수 있습니다. 배열이나오면 항상따라오는것이 반복문이죠 ㅎㅎ
#include <stdio.h>
typedef struct student {
char name[30];
int id;
int grade;
}Student;
int main(void) {
Student arr[10];//구조체 배열 선언
for (int i = 0; i < 10; i++) {//데이터 입력부분
scanf("%s %d %d", arr[i].name, &arr[i].id, &arr[i].grade);
}
for (int i = 0; i < 10; i++) {//데이터 출력부분
printf("%s %d %d", arr[i].name, arr[i].id, arr[i].grade);
}
return 0;
}
이처럼 구조체배열을 잘 이용하실 수 있어야합니다..
전에 했던 코드를 살펴볼까여
int a = 10;
int* p = &a;
이렇게 하면 p를 이용해서 a값을 변경하거나 출력할 수 있죠.
(*p)로 a의 값을 바꾸거나 얻을 수 있죠.
구조체의 포인터도 마찬가지입니다!
typedef struct student {
char name[30];
int id;
int grade;
}Student;
Student person = { "홍길동", 1871000, 1 };
Student* p = &person;
같은 방식입니다. Student 구조체 자료형인 person을 선언하고 값을 할당한 후에, Student 구조체자료형의 포인터 인 p를 선언하고 p는 person을 가리킵니다. 여기까진 같습니다.
하지만 멤버 접근시에 달라지는데요, 위에서 값에 접근할 때 *을 사용한다고 했습니다. 그렇다면 구조체에서 똑같이 적용할 수 있습니다. (*p).name
, (*p).id
, (*p).grade
로 접근하실 수 있습니다. 여기서 (*person) 을 괄호로 감싸준 이유는 . 연산자가 * 연산자보다 더 우선순위가 높기 때문입니다. 그래서 불편하죠?... ㅠㅠ 맨날 감싸줘야 되서요..
그래서 ->가 나왔습니다! 구조체 포인터한정으로 구조체 포인터가 있을 때 -> 연산자를 이용해서 구조체의 멤버에 접근할 수 있도록 했습니다.
#include <stdio.h>
typedef struct student {
char name[30];
int id;
int grade;
}Student;
int main(void) {
Student person;
Student* p = &person;
scanf("%s", p->name);
//scanf("%d", (*p).name);와 동일(왜 &안붙는지는 아시죠?)
scanf("%d", &p->id);
//scanf("%d", &(*p).id);와 동일
scanf("%d", &p->grade);
//scanf("%d", &(*p).grade);와 동일
printf("%s\n", p->name);//(*p).name
printf("%d\n", p->id);//(*p).id
printf("%d\n", p ->grade);//(*p).grade;
return 0;
}
이런식으로 말이죠.. 괄호로 감싸주고.. 별찍고 변수명 할 필요없이 ->면 바로 접근할 수 있어서 좋은겁니다!