관리 메뉴

공부 기록장 💻

명품 C++ Programming 6장 실습 문제 - 함수/생성자 중복 정의, 디폴트 매개 변수, static 멤버, 참조 매개 변수, 난수 생성 본문

# Language & Tools/C++

명품 C++ Programming 6장 실습 문제 - 함수/생성자 중복 정의, 디폴트 매개 변수, static 멤버, 참조 매개 변수, 난수 생성

dream_for 2021. 4. 15. 03:15

(명품 C++ 프로그래밍 6장)

 

1.

(1)

 

#include <iostream>
using namespace std;

int add(int* a, int size) {
	int sum=0;
	for (int i = 0;i < size;i++) sum += a[i];
	return sum;
}

int add(int* a, int size, int* b) {
	return add(a, size) + add(b, size); // 반환 문장에서 두 개의 함수를 호출하여 얻은 결과 값 저장하고 리턴
}

int main() {
	int a[] = { 1,2,3,4,5 };
	int b[] = { 6,7,8,9,10 };
	int c = add(a, 5);
	int d = add(a, 5, b);
	cout << c << endl;
	cout << d << endl;
}

 

(2)

디폴트 매개 변수를 가진 한 개의 함수로 변경

 

세번째 매개 변수의 값을 NULL 디폴트 값으로 초기화 해준다.

함수 내에서 for문을 두 번 돌아야 한다는 것..

 

#include <iostream>
using namespace std;

int add(int* a, int size, int *b=NULL) // b포인터 값 초기화
{
	int sum = 0;
	for (int i = 0;i < size;i++) sum += a[i];
	if(b==NULL) return sum; // b에 대한 포인터가 전달되지 않은 경우
	for (int i = 0;i < size;i++) sum += b[i];
	return sum;
}

int main() {
	int a[] = { 1,2,3,4,5 };
	int b[] = { 6,7,8,9,10 };
	int c = add(a, 5); // (a, 5, NULL) 값 전달
	int d = add(a, 5, b); // (a,5,b) 값 전달
	cout << c << endl;
	cout << d << endl;
}

 

 

 

 

2. 

(1)

 

 

#include <iostream>
#include <string>
using namespace std;

int big(int x, int y) {
	return	x > y ? (x < 100 ? x : 100) : (y < 100 ? y : 100);
}
int big(int x, int y, int max) {
	return x > y ? (x < max ? x : max) : (y < max ? y : max);
}
int main() {
	int x = big(3, 5); // 큰 값 5가 100보다 작으므로 5 리턴
	int y = big(300, 60); // 큰값 300이 100보다 크므로 100 리턴
	int z = big(30, 60, 50); // 마지막 인자 최대값
	cout << x << ' ' << y << ' ' << z << endl;
}

 

 

다음과 같이 함수에서 3개의 매개 변수를 전달 받는 함수를 

리턴문에서 호출하여 얻은 결과값을 호출하도록 만들 수 있다.

 

#include <iostream>
#include <string>
using namespace std;

int big(int x, int y, int max) {
	return x > y ? (x < max ? x : max) : (y < max ? y : max);
}
int big(int x, int y) {
	return	big(x, y, 100);
}
int main() {
	int x = big(3, 5); // 큰 값 5가 100보다 작으므로 5 리턴
	int y = big(300, 60); // 큰값 300이 100보다 크므로 100 리턴
	int z = big(30, 60, 50); // 마지막 인자 최대값
	cout << x << ' ' << y << ' ' << z << endl;
}

 

(2)

디폴트 매개 변수를 이용해 하나의 함수로 간소화 하기

 

#include <iostream>
#include <string>
using namespace std;

int big(int x, int y, int max=100) {
	return x > y ? (x < max ? x : max) : (y < max ? y : max);
}

int main() {
	int x = big(3, 5); // 큰 값 5가 100보다 작으므로 5 리턴
	int y = big(300, 60); // 큰값 300이 100보다 크므로 100 리턴
	int z = big(30, 60, 50); // 마지막 인자 최대값
	cout << x << ' ' << y << ' ' << z << endl;
}

 

 

4. 

#include <iostream>
#include <string>
using namespace std;

class MyVector {
	int* mem;
	int size;
public:
	MyVector(int n, int val); // MyVector(int n = 100, int val = 0);
	~MyVector() { delete[]mem; }
	void show() {
		for (int i = 0;i < size;i++) cout << mem[i] << ' ';
		cout << endl;
	}
};

MyVector::MyVector(int n=100, int val=0) {
	mem = new int[n];
	size = n;
	for (int i = 0;i < size;i++)mem[i] = val;
}
int main() {
	MyVector a;
	MyVector  b(10, 1);

	a.show();
	b.show();
}

 

 

5. 

#include <iostream>
using namespace std;

class ArrayUtility {
public:
	static void intToDouble(int source[], double dest[], int size); // int 배열을 double 배열로 변환
	static void doubleToInt(double source[], int dest[], int size); // double 배열을 int 배열로 변환
};

// 구현부에서는 static 지정자 쓰면 안됨
void ArrayUtility::intToDouble(int source[], double dest[], int size) {
	for (int i = 0;i < size;i++)
		dest[i] = (double)source[i];
}

// double, float - > int (반올림 X, 소수점 버림)
void ArrayUtility::doubleToInt(double source[], int dest[], int size) {
	for (int i = 0;i < size;i++)
		dest[i] = (int)source[i];
}
int main() {
	int x[] = { 1,2,3,4,5 };
	double y[5];
	double z[] = { 9.9, 8.8, 7.7, 6.6, 5.6 };

	// 클래스를 이용해 static 함수에 접근
	ArrayUtility::intToDouble(x, y, 5); // x[] -> y[] 
	for (int i = 0; i < 5; i++) cout << y[i] << ' ';
	cout << endl;

	ArrayUtility::doubleToInt(z, x, 5); // z[] -> x[]
	for (int i = 0; i < 5; i++) cout << x[i] << ' ';
	cout << endl;
}

 

 

 

6. 배열을 변환하는 프로그램

(동일한 크기의 배열을 합치고, 첫번째 배열의 요소에서 두번째 배열 요소를 빼는 프로그램)

 

 

** 첫번째 배열에서 두번째 배열을 빼는 함수에서

초깃값으로 설정되어 있는 flag, check값을 바꾸어 첫번째 배열의 요소가 두번째 배열에 저장되어 있는지 확인하는 방법말고,

따로 변수를 설정하지 않고 두번째 반복문의 제어 변수가 일정 값까지 도달한 경우

같은 값이 없었다는 것으로 판단하여 새로운 배열에 저장하는 방법을 사용하자.

 

 

1. ArrayUtility2 클래스 선언부

 

ArrayUtility2 클래스에는 두 배열과 배열의 크기를 전달 받아, 두 배열을 이어 붙여 새로운 배열을 동적 생성하여 반환하는 concat함수,

두 배열과 배열의 크기, 새로운 배열의 크기를 정할 변수를 전달 받아 첫번째 배열에서 두번째 배열에 있는 요소를 모두 삭제한 새로운 배열을 동적 생성하여 반환하는 remove함수가 선언되어 있다.

 

class ArrayUtility2 {
public:
	static int* concat(int s1[], int s2[], int size);
	static int* remove(int s1[], int s2[], int size, int& retSize);
};

 

 

2. static 멤버 함수 구현부

 

(1) concat 함수

 

두 배열을 이어 붙이게 되므로, 새로운 배열의 크기는 기존 배열의 크기의 두 배이다.

따라서 새로운 배열을 동적 생성할 때 그 크기는 2*size가 된다.

먼저 size 크기만큼 첫번째 배열의 요소들을 새로운 배열에 저장하고,

이후 size부터 2*size까지는 두번째 배열의 요소들을 저장하도록 한다.

 

int* ArrayUtility2::concat(int s1[], int s2[], int size) {
	int* p = new int[2 * size];

	for (int i = 0;i < size;i++)
		p[i] = s1[i];
	for (int i = 0;i < size;i++)
		p[size + i] = s2[i];
	return p;
}

 

(2) remove 함수

 

두 배열과 배열의 size, 그리고 참조 매개변수인 retSize를 전달받는다.

먼저 tmp 포인터에 기존의 배열 크기만큼 배열을 동적 생성한다.

 

이중 반복문을 이용하여, s1[] 배열의 요소가 s2[] 배열에 존재하는지 탐색한다.

같은 값이 발견되면 바로 break문이 실행된다. 반복문을 빠져나왔을 때,

만약 j가 size와 값이 동일한 경우는 끝까지 s1[]의 요소가 s2[]에서 발견되지 않았다는 뜻이므로

해당 값을 배열에 저장하도록 한다.

 

tmp 배열에 요소들이 저장된 후에는, retSize 크기의 배열 p를 다시 동적 생성하여 tmp배열을 p 배열에 복사한다.

(size크기만큼의 배열을 모두 사용하지 않기 때문에 메모리 공간 낭비가 생기므로)

 

사용 완료한 배열 tmp에 대해서는 해당 동적 메모리를 반환한다.

 

int* ArrayUtility2::remove(int s1[], int s2[], int size, int& retSize) {
	int* tmp = new int[size]; // size 크기의 임시 배열 동적 할당
	retSize = 0;

	for (int i = 0;i < size;i++) {
		int j;
		for (j = 0;j < size;j++)
			if (s1[i] == s2[j]) break; // 동일한 값이 발견되면 break
		
		if (j == size) // j 값이 size에 도달한 경우에는 임시 배열에 해당 값 저장
			tmp[retSize++] = s1[i];
	}
	
	int* p = new int[retSize]; // 최종 retSize 크기의 배열 동적 생성
	for (int i = 0;i < retSize;i++)
		p[i] = tmp[i]; // tmp의 값들을 p에 저장
	
	delete[]tmp; // 사용 완료한 tmp 배열 메모리 해제
	return p;
}

 

 

전체 코드:

 

#include <iostream>
using namespace std;

class ArrayUtility2 {
public:
	static int* concat(int s1[], int s2[], int size);
	static int* remove(int s1[], int s2[], int size, int& retSize);
};

int* ArrayUtility2::concat(int s1[], int s2[], int size) {
	int* p = new int[2 * size];

	for (int i = 0;i < size;i++)
		p[i] = s1[i];
	for (int i = 0;i < size;i++)
		p[size + i] = s2[i];
	return p;
}

int* ArrayUtility2::remove(int s1[], int s2[], int size, int& retSize) {
	int* tmp = new int[size]; // size 크기의 임시 배열 동적 할당
	retSize = 0;

	for (int i = 0;i < size;i++) {
		int j;
		for (j = 0;j < size;j++)
			if (s1[i] == s2[j]) break; // 동일한 값이 발견되면 break
		if (j == size) tmp[retSize++] = s1[i]; // j 값이 size에 도달한 경우에는 임시 배열에 해당 값 저장
	}
	
	int* p = new int[retSize]; // 최종 retSize 크기의 배열 동적 생성
	for (int i = 0;i < retSize;i++)
		p[i] = tmp[i]; // tmp의 값들을 p에 저장
	
	delete[]tmp; // 사용 완료한 tmp 배열 메모리 해제
	return p;
}

int main() {
	int x[5], y[5];
	int retSize;

	cout << "정수를 5 개 입력하라. 배열 x에 삽입한다 >> ";
	for (int i = 0;i < 5;i++)
		cin >> x[i];
	cout << "정수를 5 개 입력하라. 배열 y에 삽입한다 >> ";
	for (int i = 0;i < 5;i++)
		cin >> y[i];

	int* arr1 = ArrayUtility2::concat(x, y, 5);
	int* arr2 = ArrayUtility2::remove(x, y, 5, retSize);

	cout << endl << "힙친 정수 배열을 출력한다" << endl;
	for (int i = 0;i < 10;i++) cout << arr1[i]<<' ';
	cout << endl << "배열 x[]에서 y[]를 뺀 결과를 출력한다. 개수는 " << retSize << endl;
	for (int i = 0;i < retSize;i++)cout << arr2[i]<<' ';
	cout << endl;
}

 

 

결과:

 

 

7. 

 

 

a부터 b까지의 랜덤 정수 난수 출력(디폴트 매개 변수 값 지정)

 

매개변수 min과 max에 각각 디폴트 값을 지정해주었다.

따라서 함수를 호출하는 부분에서 전달되는 실인자 값의 유무에 따라 해당 디폴트값으로 초기화될지 안될지가 결정될 것이다.

min과 max에 대한 실인자값이 없이 nextInt() 가 호출된다면,

디폴트값으로 지정된 전체 정수 범위(0~32767) 안에서 정수 난수가 반환된다.

 

int Random::nextInt(int min=0, int max=32767) {
	return rand() % max + min;
}

 

 

알파벳 랜덤 출력

 

(1) 직접 static char[] 배열을 생성하어 해당 배열의 크기 내에서 랜덤한 숫자를 추출하고 출력하는 방법

 

char Random::nextAlphabet() {
	static const char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	
	return alpha[rand()%sizeof(alpha)-1];

 

 

(2) 아스키코드값을 이용하는 방법

 

대문자 아스키코드는 65부터, 소문자 아스키코드는 97부터 시작하고

전체 알파벳의 개수가 26개임을 응용하여 다음과 같이 작성할 수도 있다.

 

char Random::nextAlphabet() {
	int n = rand() % 2; // 대문자, 소문자 판별
	if (n) return rand() % 26 + 65; // 대문자
	else return rand() % 26 + 97; // 소문자
}

 

 

랜덤 실수 난수 출력

 

double Random::nextDouble() {
	return (double)rand()/RAND_MAX;
}

 

 

 

 

전체 코드:

 

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

class Random {
public:
	static void seed() { srand((unsigned)time(0)); }
	static int nextInt(int min, int max);
	static char nextAlphabet();
	static double nextDouble();
};

int Random::nextInt(int min=0, int max=32767) {
	return rand() % max + min;
}

// 알파벳이 모두 입력되어 있는 char 배열 요소들 중 랜덤 추출
/*char Random::nextAlphabet() {
	static const char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	return alpha[rand()%sizeof(alpha)-1];
}*/

// 알파벳의 아스키코드 이용
char Random::nextAlphabet() {
	int n = rand() % 2; // 대문자, 소문자 판별
	if (n) return rand() % 26 + 65; // 대문자
	else return rand() % 26 + 97; // 소문자
}

double Random::nextDouble() {
	return (double)rand()/RAND_MAX;
}

int main() {
	Random::seed();
	
	cout << "1에서 100까지 랜덤한 정수 10개를 출력합니다" << endl;
	for (int i = 0;i < 10;i++)
		cout << Random::nextInt(1,100)<< ' ';
	
	cout << endl<<endl << "알파벳을 랜덤하게 10개를 출력합니다"<<endl;
	for (int i = 0;i < 10;i++)
		cout << Random::nextAlphabet() << ' ';

	cout << endl<<endl << "랜덤한 실수를 10개를 출력합니다" << endl;
	for (int i = 0;i < 10;i++)
		cout << Random::nextDouble() << ' ';
	cout << endl;

}

 

결과:

 

 

728x90
반응형
Comments