개발 Study

#21 입출력(2), 열거체(enum) 및 함수포인터

HYuk 2021. 4. 21. 01:31
728x90

#20 스트림 개방 및 입출력 (tistory.com)

 

#20 스트림 개방 및 입출력

#스트림개방 스트림 개방을 통해 stdin, stdout 외에 파일로 입출력을 해보려고 한다. 파일로 입출력을 하기 위해서는 스트림 개방을 해야한다. 개방은 fopen_s(1. 스트림 개방 후 저장 할 포인터변수

hyukee.tistory.com

#바이너리 입출력

위글에 이어 이번에는 바이너리 형태로 입출력을 해보려고 한다.

바이너리 입출력은

기존 rt, wt (텍스트)로 출력했던 것을 rb, wt로 작성하면 바이너리로 입출력이 가능하다.

 

바이너리 모드로 입출력을 할 때는

fwritefread를 사용할 수 있다.

 

fwrite와 fread 매개변수는 단순 입력인지 출력인지 차이일뿐 동일하다.

fwrite 기준으로 보면

fwrite(1. 출력할메모리시작주소, 2. 얼마나출력할지크기, 3. 몇개출력할지, 4. 어떤 스트림을 사용할지)

그리고 리턴되는 값으로는 함수호출 성공시, 3번의 값이 반환되며,  실패시 그보다 작은 값이 반환된다.

 

fopen을 wb인지 wr인지에 맞춰 fwrite와 fread를 사용하면 된다.

	int		iArr[5] = {1,2,3,4,5};

	FILE*	fp = nullptr;

	errno_t err = fopen_s(&fp, "../Data/Text.txt", "wb");

	if (0 == err)
	{
		fwrite(iArr, sizeof(iArr), 1, fp);
		fclose(fp);
		cout << "성공!" << endl;
	}
	else
		cout << "실패!" << endl;

위 코드는 iArr의 숫자들을 바이너리 형태로 Text.txt파일로 내보내는 것이다.

 

텍스트 파일을 확인하면 binary 형태로 쓰여있는 것을 확인 할 수 있다.

 

 

바이너리 형태는 txt 뿐만 아니라 다른형태로도 출력 가능한데, 아래는 Image.jpg 파일을 불러와서,

Copy.jpg 파일에 쓰는 형태이다.

즉, image.jpg를 복사하는 코드이다.

#include <iostream>

using namespace std;

void main()
{
	FILE* fp = nullptr;
	FILE* fp2 = nullptr;
	int i = 1;
	errno_t err = fopen_s(&fp, "../Image.jpg", "rb");
	errno_t err2 = fopen_s(&fp2, "../Copy.jpg", "wb");
	while (i!=EOF)
	{
		if (err == 0)
			i = fgetc(fp);
		else
			cout << "실패" << endl;
		if (err2 == 0)
			fputc(i, fp2);
		else
			cout << "실패" << endl;
	}
	fclose(fp);
	fclose(fp2);
	cout << "복사 완료" << endl;
}

 

위의 코드를 작성하기전에 while문을 확인하면

i가 EOF일때 작업을 중지 하는데 이게 없다면, 쓸데없는 값을 계속 jpg에 쓰기때문에 용량이 계속 불어난다.

 

while문을 작성하기 전에, 중간 저장값을 i가 아닌 배열을 하나 큰것을 만들어서 거기에 저장하려고

int iArr[1000000]={}; 을 작성하니 프로그램이 터져 버렸다.

지난번에 fclose를 이용해서 닫지 않으면, 이어서 작성이 된다는 것을 깨닫고, 파일이 open 된 상태에서 while문을 돌려서 위와 같은 코드를 작성하게 되었다.

 

-----------------------------------------------------------------------------------------------------------------------------------

 

 

#열거체

열거체는 아래와 같이 사용한다.

enum 변수명 {STOP, JUMP, RUN, WALK, ..등등..,  END};

 

이때 따로 안의내용 STOP=1 이런식으로 지정해주지 않는한, 왼쪽부터 0이 부여되서 0, 1, 2, ... 이 부여된다.

 

이때 부여 되는 것은 상수로 부여되는데, 그래서 switch 문과 같이 쓰이기에 좋다.

case 0:

case 1: 

이 아닌

case STOP:

case JUMP:

등과 같이 사용할 수 있어 가독성이 좋다.

 

여기서 주의 해야 할 것은 열거체 선언시에, 초기화는 열거자로만 진행해야된다.

ex) enum MAN {STOP, JUMP, RUM, END};

MAN eState = STOP;

 

#union(공용체)

union은 구조체(struct)와 비슷하다.

구조체와 다른점은 union은 내부에 있는 변수중 가장 큰 메모리를 하나 가지고 그 메모리를 공용으로 사용 한다는 점이다.

선언은

union 변수

{

멤버변수1;

멤버변수2'

};

로 진행되며 같은 메모리를 사용하기 때문에 멤버변수1이 바뀌면 멤버변수2도 바뀌어 버린다.

 

잘 사용되지는 않는다.

 

-----------------------------------------------------------------------------------------------------------------------------------

#함수포인터

 

함수를 불러올때

함수명(); 를 사용한다.

이때 () <- 이것은 함수 호출자 이다.

 

이것을 빼고 함수명; 만 사용 했을 때는 함수의 주소값이 반환된다.

그럼 그 주소값을 포인터 변수에 넣어줄 수 있는데, 이것을 함수포인터라고 한다.

 

함수포인터를 선언해줄때는 다음과 같다.

반환타입(*변수명)(매개 변수 정보(자료형만))

 

포인터 함수를 불러올때는 다음과 같다.

포인터변수명(매개변수);

 

아래와 같이 함수포인터 배열을 사용하여 간단하게 코드를 작성하는 것이 가능하다.

int Add(int _a, int _b)
{
	return _a + _b;
}

int Min(int _a, int _b)
{
	return _a - _b;
}

int Mul(int _a, int _b)
{
	return _a * _b;
}

int Div(int _a, int _b)
{
	return _a / _b;
}
    
void main()
    {
    int		iA = 0, iB = 0, iSelect = 0;
	
	int(*ptr[4])(int, int) = { Add, Min, Mul, Div };

	cout << "두 정수 값 입력: ";
	cin >> iA >> iB;

	cout << "1.더하기 2.빼기 3.곱하기 4.나누기" << endl;
	cout << "==============================" << endl;
	cout << "입력: ";
	cin >> iSelect;

	cout << "연산 결과: " << ptr[iSelect - 1](iA, iB) << endl;
    }
728x90