티스토리 뷰
C 프로그램으로 학생 정보를 입력하고 출력하는 문제를 생각해 보자. 학생 정보는 이름, 학년, 점수 세 개로 이루어져 있다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main()
{
FILE *fp = NULL;
char names[50][10];
int years[50];
int scores[50][3];
int count = 0;
int i, j;
fopen_s(&fp, "student.txt", "r");
if (fp == NULL) {
printf("파일 열기 실패 - %s\n", "student.txt");
system("pause");
system("exit");
}
while (!feof(fp)) {
fscanf_s(fp, "%s", names[count], 10);
fscanf_s(fp, "%d", years[count]);
for (j = 0; j < 3; j++)
fscanf_s(fp, "%d", &scores[count][j]);
count++;
}
for (i = 0; i < count; i++) {
printf("%s %d학년 [ ", names[i], year[i]);
for (j = 0; j < 3; j++) {
printf("%d ", scores[i][j]);
}
printf("]\n");
}
fclose(fp);
system("PAUSE");
}
이 프로그램은 다음과 같은 형태의 입력과 출력을 가지게 된다.
a 1 91 67 84 b 2 50 69 74 c 1 78 58 62 d 1 64 55 95 e 2 81 77 61 |
a 1학년 [ 91 67 84 ] b 2학년 [ 50 69 74 ] c 1학년 [ 78 58 62 ] d 1학년 [ 64 55 95 ] e 2학년 [ 81 77 61 ] |
이 프로그램을 구조체로 바꾸면 다음과 같다. 먼저 구조체를 정의해야 한다.
struct ST {
char name[10];
int year;
int scores[3];
} ;
이것은 이름, 학년, 점수를 가지는 구조체를 정의하고 ST라는 구조체 태그를 붙였다. 태그는 구조체가 여러 개 정의된 경우 구분하는 역할을 해준다. 이런 구조체 정의부는 보통 함수에 들어가기 전에 나타난다.
그럼 그 구조체를 이용하도록 위의 배열 코드를 고쳐보면 다음과 같다.
void main()
{
sruct ST st_arr[50];
int count = 0;
...
while (!feof(fp)) {
fscanf_s(fp, "%s", st_arr[count].name, 10);
fscanf_s(fp, "%d", &st_arr[count].year);
for (j = 0; j < 3; j++)
fscanf_s(fp, "%d", &st_arr[count].scores[j]);
count++;
}
for (i = 0; i < count; i++) {
printf("%s %d학년 [ ", st_arr[i].name, st_arr[i].year);
for (j = 0; j < 3; j++) {
printf("%d ", st_arr[i].scores[j]);
}
printf("]\n");
}
...
}
배열에서 names와 years와 scores 에서 count번째는 이제 ST 구조체 배열의 count 번째 객체에 모두 모여있다. 이것을 st_arr[count]로 접근하여 그 구조체의 name 필드에 값을 저장하거나 읽어오기 위해서는 배열에서 names[count] 대신 st_arr[count].name이라고 쓰게 된다.
이것을 구조체를 이용하는 함수로 바꿔보면 다음과 같다.
struct ST {
char name[10];
int year;
int scores[3];
};
void read_st(FILE* fp, struct ST *stptr);
void print_st(struct ST *stptr);
void main()
{
sruct ST st_arr[50];
int count = 0;
...
while (!feof(fp)) {
read_st(fp, &st_arr[count]);
count++;
}
for (i = 0; i < count; i++) {
print_st(&st_arr[i]);
}
fclose(fp);
system("PAUSE");
}
여기서 read_st 와 print_st 함수는 각각 ST 구조체 객체를 받아 그것으로 데이터를 입력하거나 출력하는 일을 담당한다. 넘겨진 &st_arr[count]는 count번째 학생의 구조체의 주소를 넘긴다. 함수는 이 구조체의 포인터를 받아 해당 학생 정보를 입력 또는 출력하게 된다.
void read_st(FILE* fp, struct ST *stptr)
{
fscanf_s(fp, "%s", stptr->name, 10);
for (j = 0; j < 3; j++)
fscanf_s(fp, "%d", &stptr->scores[j]);
}
void print_st(struct ST *stptr)
{
printf("%s ", stptr->name);
for (j = 0; j < 3; j++) {
printf("%d ", stptr->scores[j]);
}
printf("\n");
}
함수에서는 넘겨진 구조체의 포인터를 stptr라는 이름으로 받아 그 주소가 가리키는 곳에 있는 구조체의 필드를 접근하게 된다. 이때 원래 main 코드에서 st_arr[count]는 함수 안에서는 포인터가 가리키는 곳의 객체를 나타내는 (*stptr)와 같다. 그러므로 st_arr[count].name은 함수 안에서는 (*stptr).name과 같다. C언어에서는 .연산자가 간접참조 * 연산자보다 우선순위가 높으므로 *stptr.name이라고 하면 이것은 *(stptr.name)의 의미로 해석된다. 그러므로 (*stptr).name처럼 앞에 괄호를 해주어야 한다.
이러한 번거로움을 해결하기 위해 C언어에서는 구조체 포인터의 필드를 접근하기 위해 화살표(->) 연산자를 도입하였다. 즉 (*stptr).name은 좀더 간결한 표현으로 stptr->name이라고 쓸 수 있다.그래서 위의 코드와 같이 화살표를 이용하여 구조체 포인터의 필드를 접근하게 된다.
이제 우리는 구조체와 그 구조체에 관련된 두 개의 함수 read_st, print_st를 가진 코드를 만들었다. 여기서 read_st 함수는 좀더 자세히 들여다 보면 학생 구조체의 객체를 매개변수로 받아서 그 학생을 입력하라는 함수가 된다. 여기서 학생 구조체 stptr는 목적어가 된다.
이것을 c++의 클래스로 바꿔보자. 위의 구조체 코드가 훨씬 간결해짐을 알 수 있다. 클래스를 정의하게 되면 C 코드에서 다음 세 가지 부분이 달라진다.
(1) 함수의 매개변수 : read_st, print_st 함수가 클래스 멤버 함수가 되었다. 그러면서 struct ST* 매개변수가 없어진다. 이것은 클래스 멤버 함수에서는 this 라는 포인터로 숨겨져서 전달된다.
void print_st(struct ST* stptr); | void print_st(); |
(2) 함수 호출부 : print_st(st_arr[i]);가 st_arr[i].print_st();로 바뀌면서 학생 구조체가 매개변수 대신 호출할 때 점 앞에 나타난다. 이것은 C 구조체 코드에서 매개변수(목적어)가 C++ 클래스에서는 주어가 되었다라고 볼 수 있다.
print_st(st_arr[i]); | st_arr[i].print_st(); |
(3) 멤버 함수 코드 : 호출할 때의 주어는 멤버 함수 코드 안에서는 나(this)가 되는데 this.은 생략가능하다. 그래서 멤버함수의 코드 부분에서 name이나 year 앞에 사실은 this.이 생략되어 있는 것으로 볼 수 있다.
printf("%s %d학년 [", stptr->name, stptr->year); for (j = 0; j < 3; j++) { printf("%d ", stptr->scores[j]); } |
printf("%s %d학년 [", name, year); for (j = 0; j < 3; j++) { printf("%d ", scores[j]); } |
class Student {
char name[10];
int year;
int scores[3];
public:
void read_st(FILE* fp);
void print_st();
}
void Student::read_st(FILE* fp)
{
fscanf_s(fp, "%s", name, 10);
fscanf_s(fp, "%d", &year);
for (j = 0; j < 3; j++)
fscanf_s(fp, "%d", &scores[j]);
}
void Student::print_st()
{
printf("%s %d학년 [", name, year);
for (j = 0; j < 3; j++) {
printf("%d ", scores[j]);
}
printf("]\n");
}
void main()
{
Student st_arr[50];
...
while (!feof(fp)) {
st_arr[count].read_st(fp);
count++;
}
for (i = 0; i < count; i++) {
st_arr[i].print_st();
}
fclose(fp);
system("PAUSE");
}
'C++ << C & Java' 카테고리의 다른 글
C++ 클래스 예제 (1) - 음료 검색 (0) | 2019.04.13 |
---|---|
C++ 클래스 예제 (2) - 자바 코드를 C++로 바꾸기 - Store 클래스 (0) | 2019.04.05 |
C++ 객체 변수와 객체의 생성 및 소멸 (0) | 2019.04.01 |
C++의 참조형 (0) | 2019.03.28 |
C++에서 출력 포매팅 (0) | 2019.03.28 |
- Total
- Today
- Yesterday
- 동적바인딩
- contains
- follow
- 스트링
- 스트링 +
- indexof
- typedef
- Iterator
- python example
- 콜렉션
- CompareTo
- format
- rust
- APPEND
- 이터러블
- comparable
- sort key
- python exercise
- max
- zip
- TypeError
- Camel Style
- ToString
- contentEquals
- C++ 클래스
- 자바regex
- 패턴
- 지연계산
- Lazy evaluation
- 이터레이터
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |