Unit 48 구조체 사용하기
-구조체 struct-
구조체는 관련 정보를 하나의 의미로 묶을 때 사용한다.
구조체는 자료를 체계적으로 관리하기 위해 c언어가 제공하는 문법이다. 구조체는 struct로 정의한다.
만드는 것은
struct <구조체 명>
{
<구조체 멤버들 선언>
};
으로 하면 된다.
예를 들어 학생 구조체가 있다 가정하면
struct Student
{
char name[20]; // 이름
int classNum; // 학번
int grade; // 학년
char gender; // 성별
};
이런식으로 만들 수 있다.
이렇게 구조체로 학생에 사용되는 변수들을 만든다면, 한 학생을 만들 때마다 name1, name2 이런식으로 변수를 여러 개 만들 필요없이 하나로 손쉽게 관리 가능하다.
또한 구조체 안에 들어있는 변수를 멤버라고 부른다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
};
int main()
{
struct Student s1; // 구조체 변수 선언
strcpy(s1.name, "dypar");
s1.classNum = 31510;
s1.gender = 1;
// 구조체 멤버에 값 저장
printf("%s %d %d", s1.name, s1.classNum, s1.gender);
// 구조체 멤버의 값 출력
}
위는 Student 구조체를 만들어 학생에 필요한 정보들을 멤버로 만든 후, main 함수안에서 구조체 변수를 선언했다. 그 후 만들어진 구조체 변수로 구조체 멤버에 접근에 각각의 값을 저장한 후 출력하는 코드다.
실행 결과를 보면 구조체 멤버에 저장한 값이 그대로 잘 출력된 것을 볼 수 있다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
} s1; // 구조체 정의 동시에 변수 선언
int main()
{
strcpy(s1.name, "dypar");
s1.classNum = 31510;
s1.gender = 1;
// 구조체 멤버에 값 저장
printf("%s %d %d", s1.name, s1.classNum, s1.gender);
// 구조체 멤버의 값 출력
}
이런식으로 구조체 정의문 뒤에 변수명을 적는다면 구조체를 정의하는 동시에 구조체 변수를 선언할 수 있다. 다른점은 main 함수에서 구조체 변수 선언 없이 선언한 변수로 구조체 멤버에 접근하여 값을 저장할 수 있다는 것이다.
결과는 같다.
struct Student s1 = {.name = "dypar", .classNum = 31510, .gender = 1};
위처럼 작성한다면 구조체 변수 선언과 동시에 값을 초기화 시킬 수 있다.
-typedef
typedef는 자료형의 별칭을 만들어주는 역할을 한다. 구조체 뿐만 아니라 모든 자료형의 별칭을 만들 수 있다 한다.
typedef <자료형> <별칭>으로 사용하면 된다.
구조체 변수 선언시 struct 키워드를 일일이 붙여야한다는 번거로움(?)이 있는데, 이 typedef로 구조체를 정의하면서 별칭을 지정해준다면 struct 키워드를 생략할 수 있다고 한다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
typedef struct Student
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
} Stu; // 구조체 별칭 지정
int main()
{
Stu s1 = { .name = "dypar",.classNum = 31510,.gender = 1 };
// 구조체 정의와 동시에 멤버의 값 초기화
printf("%s %d %d", s1.name, s1.classNum, s1.gender);
// 구조체 멤버의 값 출력
}
위처럼 구조체 정의전에 typedef를 붙여주고 구조체 정의 후 별칭을 지정해주니, 구조체 변수 선언시 struct student s1으로 길게 쓰지 않고 Stu s1 이렇게 별칭만으로 구조체 변수를 선언할 수 있다.
결과도 똑같은 것을 볼 수 있다.
-익명 구조체
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
typedef struct
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
} Stu; // 구조체 별칭 지정
int main()
{
Stu s1 = { .name = "dypar",.classNum = 31510,.gender = 1 };
// 구조체 정의와 동시에 멤버의 값 초기화
printf("%s %d %d", s1.name, s1.classNum, s1.gender);
// 구조체 멤버의 값 출력
}
어디에 쓰이는지는 잘 모르겠지만(단순 번거로움 때문에?) 위처럼 struct의 이름을 지정해주지 않고 typedef만으로 별칭을 지정해주는 식으로 사용할 수 있다고 한다.
결과는 역시 같다.
Unit 49 구조체 포인터 사용하기
-구조체 포인터-
구조체도 포인터를 선언할 수 있고 malloc 함수로 동적 메모리를 할당할 수 있다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
struct Student
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
};
int main()
{
struct Student *s1 = malloc(sizeof(struct Student));
// 구조체 포인터 변수 선언 및 동적 메모리 할당
strcpy(s1->name, "dypar");
s1->classNum = 31510;
s1->gender = 1;
// 구조체 멤버에 값 저장
printf("%s %d %d", s1->name, s1->classNum, s1->gender);
// 구조체 멤버의 값 출력
free(s1);
}
위는 포인터로 구조체 변수를 선언하고 Student 구조체의 크기만큼 메모리를 동적할당한 모습이다. 일반 구조체 변수와 달리 구조체 멤버에 접근하려면 .이 아닌 ->로 해야한다. 또한 메모리를 할당했으므로 마지막에 free로 메모리를 해제시켜 줬다.
결과는 일반 구조체와 똑같은 것을 볼 수 있다.
참고로 (*s1) 이런식으로 구조체 변수에 역참조 연산자를 써주면 .으로도 멤버에 접근할 수 있다고 한다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct Student
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
} Stu; // 구조체 별칭 지정
int main()
{
Stu *s1 = malloc(sizeof(Stu));
strcpy(s1->name, "dypar");
s1->classNum = 31510;
s1->gender = 1;
printf("%s %d %d", s1->name, s1->classNum, s1->gender);
// 구조체 멤버의 값 출력
free(s1);
}
당연하지만 이런식으로 구조체 별칭으로 포인터를 선언하고 메모리를 동적할당할 수 있다. 메모리의 크기 같은 경우 sizeof(Stu); 이렇게 별칭으로 해주면 된다.
결과는 똑같으니 생략하겠다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct Student
{
char name[20]; // 이름
int classNum; // 학번
int gender; // 성별, 1 : 남 2 : 여
} Stu; // 구조체 별칭 지정
int main()
{
Stu s1; // 구조체 변수 선언
Stu *p = &s1; // 위에서 선언한 구조체 변수의 메모리 주소를 포인터에 저장
strcpy(p->name, "dypar");
p->classNum = 31510;
p->gender = 1;
printf("%s %d %d", p->name, p->classNum, p->gender);
// 구조체 멤버의 값 출력
free(p);
}
위 코드처럼 일반 구조체 변수를 선언하고, 선언한 이 구조체의 메모리 주소를 구조체 포인터에 넣는 방법도 있다. &으로 메모리 주소를 구해서 넣어준 순간 해당 구조체 포인터는 ->를 통해 멤버에 접근할 수 있다. 다 사용한 후 free는 꼭 해줘야한다.
위 코드 같은 경우 s1의 주소를 포인터 p에 할당했으니 p ->로 멤버의 값을 변경했을 때 s1의 멤버의 값이 변경된다.
결과는 똑같으니 생략하겠다.
Unit 50 두 점 사이의 거리 구하기
-두 점 사이의 거리 구하기 feat : 구조체-
말 그대로 파이썬 코딩도장에서 했던 거리 구하기 문제를 c언어에서 구조체를 이용하여 풀어보는 것이다.
먼저 두 점 사이의 거리를 구할 때는 피타고라스의 정리가 유용하다.
a^2 + b^2 = c^2 =
c = 루트(a^2+b^2)
결국 두 점 사이의 거리 구하기는 피타고라스의 정리를 이용해서 c를 구하는 것과 같다.
따라서 p1, p2의 x 길이의 차로 a를 구하고, p1, p2의 y 길이의 차로 b를 구한 후 피타고라스의 정리를 활용하여 c(거리)를 구하면 된다.
-sqrt
sqrt는 math.h에 선언돼 있는 함수로 제곱근을 구해준다.
루트(a^2 + b^2)는 이 sqrt 함수를 이용해서 쉽게 구할 수 있을 것 같다.
-abs
abs도 마찬가지로 math.h에 선언돼 있고 절대값을 구해주는 역할을 한다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
typedef struct
{
int x;
int y;
} Pos;
// Pos 구조체 정의
int main()
{
Pos p1, p2;
// 구조체 변수 선언
scanf("%d %d", &p1.x, &p1.y);
scanf("%d %d", &p2.x, &p2.y);
// p1, p2의 x, y 좌표 입력
int a = p2.x - p1.x; // a(가로)의 길이
int b = p2.y - p1.y; // b(세로)의 길이
printf("%f\n", sqrt((a * a) + (b * b))); // a^2+b^2의 제곱근을 sqrt로 구해서 출력
return 0;
}
위 코드가 직접 작성해본 두 점 사이의 거리를 구하는 알고리즘이다.
먼저 좌표를 나타내줄 구조체 Pos를 정의하고 구조체 변수를 선언한 후 p1, p2의 x, y 좌표를 구조체 멤버에 입력 받는다.
그리고 가로 길이를 p2.x - p1.x로 구하고, 세로 길이를 p2.y - p1.y로 구한 후 sqrt로 a^2 + b^2의 제곱근을 구해서 출력해준다.
결과를 보면 두 점사이의 거리를 제대로 출력해주는 것을 볼 수 있다.
Unit 48 ~ Unit 50 문제
구조체 정의시 사용하는 키워드는 struct다.
답 : c
첫 째칸에는 struct가 들어가야하고 두 번째 칸에는 };가 들어가야한다.
답 : c
구조체 별칭을 정의할 때 사용하는 키워드는 typedef다.
답 : d
이름 없이 정의하는 구조체는 익명 구조체라고 부른다.
답 : 익명 구조체
x, y를 표현하는 구조체 Point2D를 정의하고 p1 구조체 변수를 선언하고 x, y 멤버에 10, 20을 저장하는 것이 목적이다.
1번 칸에는 구조체를 Point2D라는 이름과 x, y 멤버로 정의하고 2번 칸에는 Point2D 구조체 변수를 선언하면 될 것 같다. 3번은 p1의 x 멤버에 접근해 10을 저장하면 될 것 같다.
#include <stdio.h>
struct Point2D {
int x;
int y;
};
int main()
{
struct Point2D p1; // 구조체 변수 p1 선언
p1.x = 10; // p1의 멤버 x에 10 저장
p1.y = 20;
printf("%d %d\n", p1.x, p1.y);
return 0;
}
typedef로 별칭을 붙여서 구조체를 선언하는 것이 목적이다. 48.5 문제와 똑같이 작성하되 별칭만 붙여주면 될 것 같다.
#include <stdio.h>
①
typedef struct{
int x;
int y;
} Point2D;
// 익명 구조체 정의
int main()
{
Point2D p1; // 구조체 변수 선언
p1.x = 10;
p1.y = 20; // p1의 y 맴버에 20 저장
printf("%d %d\n", p1.x, p1.y);
return 0;
}
구조체 이름을 정해주지 않고 별칭만 붙여준 익명 구조체로 정의했다.
익명 구조체 문제다. 48.6번 문제와 똑같이하면 될 것 같다.
#include <stdio.h>
typedef struct {
int x;
int y;
} Point2D;
int main()
{
Point2D p1;
p1.x = 10;
p1.y = 20;
printf("%d %d\n", p1.x, p1.y);
return 0;
}
계기판 구조체가 정의돼 있으니 각 멤버에 결과에 출력된 대로 출력되도록 값을 넣어주면 될 것 같다.
#include <stdio.h>
struct Dashboard {
int speed;
char fuel;
float mileage;
int engineTemp;
int rpm;
};
int main()
{
struct Dashboard d1; // 구조체 변수 선언
d1.speed = 80;
d1.fuel = 'F';
d1.mileage = 5821.442871f;
d1.engineTemp = 200;
d1.rpm = 1830;
// 구조체 멤버에 각각 값을 저장
printf("Speed: %dkm/h\n", d1.speed);
printf("Fuel: %c\n", d1.fuel);
printf("Mileage: %fkm\n", d1.mileage);
printf("Engine temp: %d℃\n", d1.engineTemp);
printf("RPM: %d\n", d1.rpm);
return 0;
}
구조체 변수를 선언한 후 speed 멤버에는 80, fuel에는 'F', mileage에는 5821.442871f, engineTemp에는 200, rpm에는 1830을 저장해줬다.
별칭 혹은 익명 구조체로 구조체를 정의하는 것이 목적이다.
#include <stdio.h>
typedef struct
{
int speed;
char fuel;
float mileage;
int engineTemp;
int rpm;
} Dashboard;
// 익명 구조체 정의
int main()
{
Dashboard d1;
d1.speed = 80;
d1.fuel = 'F';
d1.mileage = 5821.442871f;
d1.engineTemp = 200;
d1.rpm = 1830;
printf("Speed: %dkm/h\n", d1.speed);
printf("Fuel: %c\n", d1.fuel);
printf("Mileage: %fkm\n", d1.mileage);
printf("Engine temp: %d℃\n", d1.engineTemp);
printf("RPM: %d\n", d1.rpm);
return 0;
}
typedef를 사용해 익명 구조체를 정의하고 Dashboard라는 별칭을 붙여줬다.
1 : 포인터 변수로 선언해야 한다. X
2 : 포인터 변수로 선언해야 한다. X
3 : sizeof로 구조체의 크기를 구해야 한다. X
5 : 포인터의 크기를 구하면 안된다... X
답 : 4
구조체 포인터의 맴버는 ->를 통해 접근할 수 있다.
답 : d
a : p1에 &을 붙여줘야하고 ptr은 포인터로 선언해야한다.
b : p1에 &을 붙여줘야하고 ptr은 포인터로 선언해야한다.
c : p1에 &을 붙여줘야한다.
e : p1에 &을 붙여줘야하고 ptr은 포인터로 선언해야한다.
답 : d
1번 칸에는 malloc으로 메모리를 동적 할당하고 2번 칸에는 실행 결과에 맞는 값을 구조체 멤버에 접근하여 값을 할당하면 될 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char name[20];
int grade;
int class;
float average;
};
int main()
{
struct Student *s1 = malloc(sizeof(struct Student)); // 메모리 동적 할당
strcpy(s1->name, "고길동");
s1->grade = 1;
s1->class = 3;
s1->average = 65.389999f;
// 구조체 멤버에 ->로 접근해 값 할당
printf("이름: %s\n", s1->name);
printf("학년: %d\n", s1->grade);
printf("반: %d\n", s1->class);
printf("평균점수: %f\n", s1->average);
free(s1);
return 0;
}
1번 칸에는 malloc으로 sizeof(Point3D) 만큼 메모리를 동적할당한 후 ->로 멤버에 접근해 x에는 10, y에는 20, z에는 30을 할당해주면 될 것 같다.
#include <stdio.h>
#include <stdlib.h>
typedef struct _Point3D {
float x;
float y;
float z;
} Point3D;
int main()
{
Point3D *p1 = malloc(sizeof(Point3D)); // 메모리 동적 할당
p1->x = 10.0f;
p1->y = 20.0f;
p1->z = 30.0f;
// 구조체 멤버에 ->로 접근해 값 할당
printf("%f %f %f\n", p1->x, p1->y, p1->z);
free(p1);
return 0;
}
구조체 변수 item1의 주소를 구조체 포인터 ptr에 저장해 limited를 true로 바꾸는게 목적인 것 같다. 1번 칸에는 구조체 변수 ptr을 선언하고 2번 칸에서 item1의 주소를 ptr에 저장하면 될 것 같다.
#include <stdio.h>
#include <stdbool.h>
struct Item {
char name[100];
int price;
bool limited;
};
int main()
{
struct Item item1 = { "베를린 필하모닉 베토벤 교향곡 전집", 100000, false };
struct Item *ptr;
ptr = &item1;
ptr->limited = true;
if (ptr->limited == true)
printf("한정판\n");
else
printf("일반판\n");
return 0;
}
Person 구조체와 Car 구조체를 포인터로 선언하고 동적 메모리 할당을 받은 후 각 멤버에 출력 값에 맞는 값을 할당해주는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[20];
int age;
char address[100];
};
typedef struct {
char name[20];
int number;
int displacement;
} Car;
int main()
{
struct Person *p1 = malloc(sizeof(struct Person));
Car *c1 = malloc(sizeof(Car));
// 구조체 포인터 선언 및 메모리 동적 할당
strcpy(p1->name, "고길동");
p1->age = 40;
strcpy(p1->address, "서울시 서초구 반포동");
strcpy(c1->name, "스텔라");
c1->number = 3421;
c1 -> displacement = 2000;
// 구조체 멤버들을 ->로 접근해 값 할당
printf("이름: %s\n", p1->name);
printf("나이: %d\n", p1->age);
printf("주소: %s\n", p1->address);
printf("자동차 이름: %s\n", c1->name);
printf("자동차 번호: %d\n", c1->number);
printf("배기량: %dcc\n", c1->displacement);
free(p1);
free(c1);
return 0;
}
구조체 포인터를 선언하고 malloc으로 메모리를 동적할당 한 후 ->로 멤버들에 접근해 결과 값에 맞는 값들을 할당해줬다.
너무 쉬운 문제다. 그냥 구조체 포인터 ptr에 p1의 주소를 할당해주면 끝이다.
#include <stdio.h>
struct Point3D {
float x;
float y;
float z;
};
int main()
{
struct Point3D p1 = { 10.0f, 20.0f, 30.0f };
struct Point3D *ptr;
ptr = &p1;
printf("%f %f %f\n", ptr->x, ptr->y, ptr->z);
return 0;
}
사각형의 넓이를 구하는 것이 목적이다. 사각형의 넓이는 가로 * 세로이므로 (x2 - x1) * (y2 - y1)으로 가로, 세로의 길이를 구한 후 그 둘을 곱한 값을 출력하면 된다.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct Rectangle {
int x1, y1;
int x2, y2;
};
int main()
{
struct Rectangle rect;
int area;
rect.x1 = 20;
rect.y1 = 20;
rect.x2 = 40;
rect.y2 = 30;
int w = abs(rect.x2 - rect.x1); // x2 - x1의 절대 값을 w에 초기화
int h = abs(rect.y2 - rect.y1); // y2 - y1의 절대 값을 h에 초기화
area = w * h; // w * h로 사각형의 넓이를 구한 후 area에 저장
printf("%d\n", area);
return 0;
}
입력 된 두 점의 x, y 좌표를 바탕으로 두 점의 길이를 구해서 출력하는 것이 목적이다.
먼저 가로의 길이(p2.x - p1.x)와 세로의 길이(p2.y - p1.y)를 구한 후 그 둘의 제곱을 더한 값에 제곱근을 구해주면 될 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
struct Point2D {
int x;
int y;
};
int main()
{
struct Point2D p1;
struct Point2D p2;
double distance;
scanf("%d %d %d %d", &p1.x, &p1.y, &p2.x, &p2.y);
int a = abs(p2.x - p1.x); // p2.x - p1.x의 절대 값을 a에 저장
int b = abs(p2.y - p1.y); // p2.y - p1.y의 절대 값을 b에 저장
distance = sqrt(a*a + b*b); // a^2 + b^2의 제곱근을 distance에 저장
printf("%f\n", distance);
return 0;
}
먼저 a(p2.x - p1.x의 절대 값), b(p2.y - p1.y의 절대 값)를 구한 후 a의 제곱 + b의 제곱의 제곱근을 구해서 distance에 넣어주도록 작성했다.
'Old (2021.01 ~ 2021.12) > Programming' 카테고리의 다른 글
c언어 코딩도장 Unit 54 ~ Unit 55 (0) | 2021.03.27 |
---|---|
c언어 코딩도장 Unit 51 ~ Unit 53 (0) | 2021.03.27 |
c언어 코딩도장 Unit 45 ~ Unit 47 (0) | 2021.03.13 |
c언어 코딩도장 Unit 42 ~ Unit 44 (0) | 2021.03.13 |
c언어 코딩도장 Unit 39 ~ Unit 41 (0) | 2021.03.13 |