티스토리 뷰

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");
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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 29 30
글 보관함