IT 프로그래밍/객체지향프로그래밍

객체지향프로그래밍 그룹액티비티 6

기술1 2024. 6. 10. 21:51

객체지향프로그래밍 1-1

#include <iostream>
using namespace std;


void fun(int* ptr) {
	*ptr = 30;
}

int main()
{
	int y = 20;
	fun(&y);
	cout << y << endl;
	return 0;
}

y값이 30으로 변경되고 출력은 30이 됩니다. 

 

객체지향프로그래밍 1-2

 

#include <iostream>
using namespace std;


int main() {
	int* ptr;
	int x;

	ptr = &x;
	*ptr = 0;

	cout << "x = " << x << endl;
	cout << "*ptr = " << *ptr << endl;


	*ptr += 5;
	cout << "x = " << x << endl;
	cout << "*ptr = " << *ptr << endl;

	(*ptr)++;
	cout << "x = " << x << endl;
	cout << "*ptr = " << *ptr << endl;

	return 0;
}

포인터를 사용하여 변수의 값을 제어하는 간단한 것입니다. 

 

먼저 포인터와 변수를 설ㅇ정해주었는데요. ptr은 정수를 가리키는 포인터이며 x는 정수형 변수입니다. 

 

ptr = &x; 을 통해 ptr에 x의 주소를 저장함으로서 이제 ptr은 x를 가리키게 됩니다. *ptr = 0은 ptr이 가리키는 변수를 0으로 바꿔준 것입니다. 

 

출력값 
x = 0
*ptr = 0
x = 5
*ptr = 5
x = 6
*ptr = 6

이런 식으로 나오게 됩니다. 

 

그리고 *ptr += 5를 통해 x의 값을 증가시키는 것을 볼 수 있습니다. (*ptr)++을 통해 1을 증가시키는 것을 볼 수도 있습니다.  

 

이런 것처럼 ptr은 x의 주소를 저장하여 x를 간접적으로 조작할 수 있게 합니다. *ptr을 통해 x의 값을 변경하고, x의 현재 값을 확인할 수 있습니다. 

 

객체지향프로그래밍 1-3

#include <iostream>
using namespace std;


int main()
{
	float arr[5] = { 12.5, 10.0, 13.5, 90.5, 0.5 };
	float* ptr1 = &arr[0];
	float* ptr2 = ptr1 + 3;

	cout << *ptr2 << endl;
	cout << ptr2 - ptr1 << endl;

	return 0;
}

이 프로그램은 배열과 포인터를 사용하여 배열의 요소에 접근하는 예제입니다. 

 

배열은 float arr을 통해 초기화가 되어 있습니다 .그리고 float *ptr1 = &arr[0]; float* ptr2 = ptr1 + 3;으로 ptr1은 배열 arr의 첫 번째 요소의 주소를 가리킵니다. ptr2는 ptr1에 3을 더한 것입니다. 이는 배열 arr의 네 번째 요소의 주소를 가리키게 됩니다. 

 

*ptr2는 ptr2가 가리키는 주소의 값을 의미합니다. ptr2는 arr[3]의 주소를 가리키므로 arr[3]의 값인 90.5가 출력됩니다. 

ptr2 - ptr1은 두 포인터 간의 거리를 나타냅니다. 여기서는 ptr2가 ptr1보다 3만큼 앞서므로 3이 됩니다. 

 

포인터 산술에서 ptr + n은 포인터가 가리키는 타입의 크기를 고려합니다. ptr이 가리키는 타입이 float인 경우 ptr + 3은 세 번째 float 요소를 가리키게 됩니다. 

 

ptr1이 float 타입이므로 ptr1 + 3은 첫 번째 float 요소에서 세 번째 float 요소로 이동합니다.\

 

객체지향프로그래밍 1-4

int main()
{
	int a;
	char* x;
	x = (char*)&a;
	a = 512;
	x[0] = 1;
	x[1] = 2;
	cout << a << endl;
	return 0;
}

결과 : 513

 

포인터를 사용하여 메모리 내용을 직접 수정하였는데요.

 

x = (char*)&a; 를 통해 이 주소를 char* 형태로 변환합니다. 

 

a = 512는 512를 할당합니다. 512는 int형 정수로 4바이트에 속합니다. 그러면 메모리에 다음과 같은 방식으로 저장이 되게 됩니다. [00] [02] [00] [00] 이는 512의 리틀 엔디안 표현입니다.

 

x[0] = 1;

x[1] = 2;

이것은 a의 첫 번째 바이트를 1로 설정합니다. [01] [02] [00] [00] 이 됩니다.

이후 a의 두 번째 바이트를 2로 설정합니다. [01] [02] [00] [00]이 됩니다. 

 

a를 출력하면 해당 엔디안 방식으로 ( 01 + (02 * 256)) = 1 + 512 = 513을 의미합니다. 

 

객체지향프로그래밍 1-5

#include <iostream>
using namespace std;

void f(int* p, int* q) {
	p = q;
	*p = 2;
}

int i = 0, j = 1;
int main() {
	f(&i, &j);
	cout << i << " " << j;
	return 0;
}

함수 호출에서 포인터가 어떻게 작동하는지를 나타내고 있습니다. 

 

int i =0, j= 1;은 i는 0으로, j는 1로 초기화를 해주었습니다. 

 

그리고 함수에서 정수형 포인터를 매개변수로 받습니다. p = q;는 p가 가리키는 주소를 q가 가리키는 주소로 바꿉니다. *p = 2;는 p가 가리키는 주소의 값을 2로 설정합니다. 

 

따라서 f(&i, &j);의 함수 호출은 i의 주소와 j의 주소를 전달합니다. 

 

f(&i, &j); 가 호출되면 p는 i의 주소를, q는 j의 주소를 받습니다. p = q는 p를 q와 같은 주소를 가리키도록 변경합니다. 이제 p는 j의 주소를 나타냅니다. *p= 2; 는 p가 가리키는 주소의 값을 2로 설정합니다. p가 j의 주소를 가리키므로 j가 2로 서렂ㅇ됩니다. 

 

i의 값은 함수 호출 내내 변경되지 않고 그대로 0이며 j는 함수 호출에서 2로 변경됩니다. 

 

결과값 : 0 2 

 

이 예제는 함수 내에서 포인터를 통해 다른 변수의 값을 어떻게 수정할 수 있는지, 그리고 포인터 자체의 값을 변경하는 것이 함수 외부의 포인터 변수에는 영향을 미치지 않는다는 것을 보여줍니다. 

객체지향프로그래밍 1-6

#include <iostream>
using namespace std;

int f(int x, int* py, int** ppz) {
	int y, z;
	**ppz += 1;
	z = **ppz;
	*py += 2;
	y = *py;
	x += 3;
	return x + y + z;
}

int main() {
	int c, * b, ** a;
	c = 4;
	b = &c;
	a = &b;
	cout << f(c, b, a);
	return 0;
}

결과값 : 19

 

**ppz += 1; 은 ppz가 가리키는 포인터가 가리키는 값을 1을 증가합니다. 

z = **ppz; 는 증가된 값을 z에 저장합니다. 

*py +=2 는 py가 가리키는 값을 2 증가시킵니다. 

y = *= py는 증가된 값을 y에 저장합니다. 

 

메인함수에서는 변수를 선언하고 초기화합니다. 

int c 는 정수형 변수로 값은 4로 초기화됩니다.

int *b는 c의 주소를 가리키는 포인터입니다. 

int **a는 'b'의 주소를 가리키는 이중 포인터입니다. 

 

 f(c, b, a)가 호출되면 c의 값(4), 'b'가 가리키는 주소(&c), 'a'가 가리키는 주소(&b)가 전달됩니다. 

**ppz += 1은 c의 값을 1을 증가시킵니다. 따라서 해당 c는 5가 됩니다. 

z = **ppz;은 증가된 c의 값(5)를 z에 저장합니다. 

*py += 2;l은 c의 값을 2 증가시킵니다. 이제 c는 7이 됩니다. 

y = *py은 증가된 c의 값(7)을 y에 저장합니다. 

x+=3은 x의 값을 3 증가시킵니다. x는 7이 됩니다. 

객체지향프로그래밍 1-7

#include <iostream>
using namespace std;

void fun(int* p) {
	int q = 10;
	p = &q;
}

int main() {
	int r = 20;
	int* p = &r;
	fun(p);
	cout << *p;
	return 0;
}

포인터가 어떻게 작동하는지 이유를 보여줍니다. 

 

p는 r을 가리키고 *p는 r의 값을 나타냅니다.

 

fun(p)를 통해 p를 인수로 전달하고 호출하는데요.

 

int q = 10;은 q라는 지역변수를 선언하고 값을 10으로 초기화합니다. p = &q; 은 p를 q의 주소로 설정합니다. 하지만 이 변경은 함수 fun 내부에서만 유효합니다. 

이유

함수 fun에서 p는 값을 전달받는 매개변수입니다. 이는 포인터의 복사본을 전달받기 때문에, 함수 내부에서 p를 변경해도 원래의 포인터 p는 영향을 받지 않습니다.

- main 함수에서 'p'는 'r'의 주소를 가리킵니다. 

- fun 함수가 호출될 때, 'p'의 값(즉 'r'의 주소)이 복사되어 함수 'fun' 매개 변수 'p'로 전달됩니다.

-함수 'fun' 내부에서 p를 q의 주소로 변경하지만 복사된 포인터의 주소를 벼녁ㅇ하는 것이므로 원래 p에는 영향을 미치지 않습니다. 

수정된 코드

#include <iostream>
using namespace std;

void fun(int** p) {
    int q = 10;
    *p = &q;
}

int main() {
    int r = 20;
    int* p = &r;
    fun(&p); // p의 주소를 전달
    cout << *p; // q의 값인 10이 출력됨
    return 0;
}

이 방식에서는 q가 함수 fun의 지역 변수임을 유의해야 합니다. main 함수에서 q의 주소를 사용하려고 할 때, fun 함수가 종료되면 q는 더 이상 유효하지 않습니다. 이를 해결하려면 동적 할당을 사용하거나, q를 전역 변수로 선언해야 합니다

 

#include <iostream>
using namespace std;

void fun(int** p) {
    *p = new int; // 동적 메모리 할당
    **p = 10;
}

int main() {
    int r = 20;
    int* p = &r;
    fun(&p); // p의 주소를 전달
    cout << *p; // 10이 출력됨
    delete p; // 동적 메모리 해제
    return 0;
}

객체지향프로그래밍 1-8

#include <iostream>
using namespace std;

void fun(int* a) {
	a = new int(4);
}

int main() {
	int* p;
	fun(p);
	*p = 6;
	cout << *p;
	return 0;
}

포인터와 동적 메모리 할당을 다루고 있으며 포인터를 변경하려는 시도를 가지고 있습니다. 

 

int *p;

여기서 p는 정수형 포인터로 선언되었지만 초기화되지 않았습니다. 따라서 p는 현재 쓰레기값을 가지고 있는 상태입니다. 

 

함수 fun(p); 를 호출하여 p의 값을 인수로 전달합니다.

 

void fun(int* a) {
    a = new int(4);
}

 fun 함수는 정수형 포인터 a를 매개변수로 받습니다. 

 

a = new int(4);는 새로운 정수 메모리를 할당하고, 그 주소를 a에 저장합니다. 그러나 이 변경은 fun 함수 내부에서만 유효합니다. 즉 'a'는 새로운 메모리를 가리키게 되지만, 이는 함수 fun의 지역 변경일 뿐, main 함수에서 p에는 영향을 미치지 못합니다. 

 

*p = 6;

해당 p는 아직도 초기화되지 않은 상태입니다. *p = 6을 시도하면 정의되지 않은 동작으로 프로그램이 오류가 날 수 있습니다. 그래서 실행이 되지 않을 수 있습니다. 

 

a는 포인터의 복사본을 받기 때문에 a를 변경해도 main 함수의 p에는 영향을 미치지 않습니다. 

 

수정된 코드

#include <iostream>
using namespace std;

void fun(int** a) {
	*a = new int(4);
}

int main() {
	int* p;
	fun(&p);
	*p = 6;
	cout << *p;
	delete p;
	return 0;
}

 

a를 이중포인터를 해주었습니다.

void fun(int** a) {
    *a = new int(4);
}

a는 이중 포인터이며 *a = new int(4); 는 이중 포인를 통해 원래 포인터 p가 새로운 메모리를 가리키게 됩니다. 

 

fun(&p); p의 주소를 fun 함수에 전달합니다. 이렇게 할 경우 fun 함수가 p 자체를 변경할 수 있습니다. 

 

*p = 6; 은 이제 p는 fun 함수에서 할당한 메모리를 가리키므로 안전하게 값을 설정할 수 있습니다. 

객체지향프로그래밍 1-9

#include <iostream>
using namespace std;

int main() {
	int arr[10];
	arr[0] = 10;
	int* ptr = &arr[0];
	arr[1] = 20;
	arr[0] = 30;
	cout << *ptr << endl;
	return 0;
}

배열 int arr[10]; 으로 선언을 했습니다. 그 다음 arr[1] = 20; arr[2] = 30;으로 변경합니다. 

 

cout << *ptr << endl;을 해서 30이 나오게 됩니다. 

 

ptr은 arr[0] 의 주소를 가리키는 포인터입니다.

 

arr[0]은 초기값이 10이지만, 이후 30으로 변경됩니다. 

*ptr은 arr[0]의 값을 가지므로 최종 출력 값은 30입니다. 

 

 

객체지향프로그래밍 1-10

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

int main() {
	vector<int> vec;
	vec.push_back(10);
	int* ptr = &vec[0];
	vec.push_back(20);
	vec[0] = 30;
	cout << *ptr << endl;

	return 0;
}

vec.push_back 을 한다면 벡터에 새 요소가 추가될 때 벡터가 재할당될 수 있습니다. 벡터가 재할당되면 기존에 벡터의요소를 가리키던 포인터는 더 이상 유효하지 않게 됩니다. 

 

즉 vector가 push_back으로 재할당되었다면, 포인터 ptr은 더 이상 유효하지 않으며 정의되지 않은 동작을 가리키게 됩니다. 따라서 이는 안전하지 않은 코드입니다. 

 

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

int main() {
    vector<int> vec;
    vec.push_back(10);
    vec.push_back(20);  // 먼저 두 개의 요소를 추가하여 재할당을 방지
    int* ptr = &vec[0]; // 첫 번째 요소의 주소를 저장
    vec[0] = 30;        // 첫 번째 요소의 값을 30으로 변경
    cout << *ptr << endl; // 포인터 ptr이 가리키는 값 출력

    return 0;
}

위 코드는 코드를 안전하게 바꿔준 것입니다. 

 

벡터의 요소에 추가하는 순서를 바꾸어 포인터가 무효화하지 않도록 한 것입니다. 하지만 이 경우 문제를 제대로 해결하는 코드는 아니기에 제대로 해결하고 싶으면 인덱스를 두는 방법이 있습니다. 

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

int main() {
    vector<int> vec;
    vec.push_back(10);
    vec.push_back(20);  // 두 번째 요소 추가
    size_t index = 0;   // 첫 번째 요소의 인덱스를 저장
    vec[0] = 30;        // 첫 번째 요소의 값을 30으로 변경
    cout << vec[index] << endl; // 인덱스를 사용하여 첫 번째 요소 출력

    return 0;
}

 

객체지향프로그래밍 1-11

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

class Foo {
public:
	int x;
	Foo() = default;
	Foo(int a) : x(a) {}
};

int main() {
	Foo f(10);
	Foo* ptr = &f;
	cout << *ptr.x << endl;
	return 0;
}

해당  코드는 *ptr.x 에서 오류가 발생합니다. 이는 문법적으로 잘못된 표현입니다. ptr이 Foo 객체를 가리키고 있으므로 변수 x에 접근하기 위해선 ptr->x를 사용해야 합니다. 또한 ptr 앞에 있는 *는 사용할 필요가 없습니다. ptr->x는 int 타입이므로 역참조 연산자 *를 사용할 필요가 없기 떄문입니다. 

 

ptr은 Foo 객체를 가리키는 포인터입니다.

 

ptr->x는 ptr이 가리키는 Foo 객체의 x 멤버 변수의 값을 의미합니다. 이는 int 타입의 값입니다.

 

*ptr->x는 ptr->x가 이미 int 값이기 때문에 * 연산자가 의미가 없습니다. * 연산자는 포인터를 역참조하여 포인터가 가리키는 값을 가져오는 연산자입니다. 그러나 ptr->x 자체가 이미 값이므로 *를 사용할 필요가 없습니다.

 

객체지향프로그래밍 1-12

#include <iostream>
using namespace std;

class Foo {
public:
	int x;
	Foo() = default;
	Foo(int a) : x(a) {}
};

int main() {
	Foo* f = new Foo(20);
	cout << f->x << endl;
	return 0;
}

 

결과값 : 20

 

Foo 클래스로 정의되어 있으며 main에서 Foo 객체를 동적으로 생성한 후, 객체의 멤버 변수를 출력하는 예제입니다. 

 

Foo* f = new Foo(20);

여기서 동적 메모리를 할당합니다.

 

new 연산자를 사용해 힙 영역에 Foo 객체를 동적으로 생성한 후  생성자의 인수로 20을 전달하여 객체의 x 멤버 변수를 20으로 초기화합니다. 

 

생성된 객체의 주소를 포인터 f에 저장합니다. 

 

cout << f->x << endl;

여기서 f가 가리키는 객체의 x 멤버 변수 값을 출력합니다. f->x 표현식은 포인터 f가 가리키는 객체의 x 멤버 변수에 접근하는 것을 의미합니다.

 

따라서 출력은 20이 됩니다. 

 

객체지향프로그래밍 1-13

 

#include <iostream>
using namespace std;

class Foo {
public:
	int x;
	Foo() = default;
	Foo(int a) : x(a) {}
};

class Bar {
public:
	Foo* ptr;
	int z;
	Bar() = default;
	Bar(Foo* p, int a) : ptr(p), z(a) {}
};

int main() {
	Bar b(new Foo(10), 20);
	cout << (*b.ptr).x << endl;
	cout << b.ptr->x << endl;
	return 0;
}

Foo 클래스와 Bar클래스를 정의하고 main 함수에서 객체를 생성하여 동작을 확인하는 예제입니다. 

 

class Foo {
public:
    int x;
    Foo() = default;  // 기본 생성자
    Foo(int a) : x(a) {}  // 매개변수가 있는 생성자
};

이런식으로 해줍니다.

 

int main() {
    Bar b(new Foo(10), 20);  // Foo 객체를 동적으로 생성하여 Bar 객체를 초기화
    cout << (*b.ptr).x << endl;  // 포인터 dereference 후 x 출력
    cout << b.ptr->x << endl;  // 포인터 멤버 변수의 x 값 출력
    return 0;
}

메인함수를 설명하면 Bar b(new Foo(10, 20); 에서 new Foo(10) 은 힙 영역에 Foo 객체를 동적으로 생성하고, 'x'멤버 변수를 10으로 초기화합니다. 

 

Bar 객체 b를 생성하며, ptr 멤버 변수는 new Foo(10)이 반환하는 포인터를 가리키고 z 멤버 변수는 20으로 초기화합니다.

 

cout << (*b.ptr).x << endl 은 Foo 객체를 가리키는 포인터이며 x 멤버 변수에 접근해 10이 출력이 됩니다.

 

cout << b.ptr->x << endl;은 b.ptr이 가리키는 Foo 객체의 x 멤버 변수에 접근하는 또 다른 방법입니다. -> 연산자는 포인터를 통해 멤버 변수에 접근할 때 사용합니다.

 

이 경우 delete를 해주지 않았는데 마지막에 delete b.ptr을 해주어야 메모리 누수를 방지할 수 있습니다.

 

객체지향프로그래밍 1-14

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

class Foo {
public:
	int x;
	Foo() = default;
	Foo(int a) : x(a) {}
};

int main() {
	vector<Foo *> vec{ new Foo(1), new Foo(2),
	new Foo(3), new Foo(4) };

	auto it = vec.begin() + 2;
	cout << (*it)->x << endl;
	return 0;
}

일단 멤버변수는 x로 두고 기본생성자와 매개변수가 있는 생성자를 초기화를 해주었습니다.

 

메인함수에서 벡터를 초기화 해주었습니다. new Foo(1), new Foo(2) ... new Foo(4)와 같이 동적으로 생성된 Foo 객체 포인터로 초기화됩니다.

 

각 Foo 객체는 x멤버 변수를 각각 1, 2, 3, 4 로 초기화합니다.

 

auto it = vec.begin() + 2;

auto it = vec.begin() + 2는 벡터의 세 번째 요소를 가리키는 반복자를 it에 저장합니다. 

 

출력으로 *it는 세 번째 요소를 의미하며 (*it) -> x 는 객체 포인터가 가리키는 객체의 x 멤버 변수에 접근합니다. 따라서 x의 값은 3이므로 출력은 3이 됩니다. 

 

for (auto ptr : vec) {
    delete ptr;
}

번외로 이런식으로 메모리 누수를 방지하기 위해 delete를 해주어야 합니다. 

 

객체지향프로그래밍 1-15

 

int* g() {
	int x = 10;
	return &x;
}

int* g() {
	int* px;
	*px = 10;
	return px;
}

int g() {
	int* px;
	px = new int;
	*px = 10;
	return *px;
}

int* g() {
	int* px;
	px = new int;
	*px = 10;
	return px;
}

 

 

int* g() {
    int x = 10;
    return &x;
}

이 함수는 지역변수 x의 주소를 반환합니다. 지역 변수는 함수가 종료되면 소멸하므로 함수가 반환하는 포인터 유효하지 않을 것입니다. 즉 함수가 종료된 후 소멸하므로 &x는 가리키는 메모리 위치가 더 이상 유효하지 않은 것입니다.                                                                                                        

int* g() {
	int* px;
	*px = 10;
	return px;
}

 

문제점 : 이 함수는 포인터 px 를 초기화하며 사용하고 있습니다.int *px는 선언되었지만 어디를 가리키는지 모르는 상황ㅇ빈다. 그런 다음 *px = 10으로 접근하므로 정의되지 않은 동작을 가리킵니다.

 

객체지향프로그래밍 3

#include <iostream>
using namespace std;

const int init_capacity = 1;
int *arr = nullptr;
int capacity = 0; // 배열 arr의 현재 용량
int n = 0;       // 배열 arr에 저장된 정수의 개수

void add_to_array(int k) {
    if (capacity == 0) {
        // 용량이 0이면, 초기 용량으로 배열을 할당
        capacity = init_capacity;
        arr = new int[capacity];
    } else if (n == capacity) {
        // 배열이 가득 차면, 용량을 2배로 증가
        capacity *= 2;
        int *new_arr = new int[capacity];
        // 기존 배열의 요소를 새 배열로 복사
        for (int i = 0; i < n; i++) {
            new_arr[i] = arr[i];
        }
        // 기존 배열을 삭제하고 arr이 새 배열을 가리키도록 함
        delete[] arr;
        arr = new_arr;
    }
    // 새로운 요소를 배열에 추가
    arr[n++] = k;
}

int main() {
    int k;
    while (1) {
        cin >> k;
        if (k == -1) break; // -1이 입력되면 루프 종료
        add_to_array(k);    // 정수를 배열에 추가
    }
    for (int i = 0; i < n; i++)
        cout << arr[i] << " "; // 배열의 모든 요소 출력
    cout << endl;
    
    // 동적으로 할당된 메모리 해제
    delete[] arr;
    
    return 0;
}

 

 

배열 초기 용량 변경한 예제

#include <iostream>
using namespace std;

int *arr = nullptr;
int capacity = 0; // 배열 arr의 현재 용량
int n = 0;       // 배열 arr에 저장된 정수의 개수

void add_to_array(int k) {
    if (capacity == 0) {
        // 용량이 0이면, 초기 용량으로 배열을 할당
        cin >> capacity;
        arr = new int[capacity];
    } else if (n == capacity) {
        // 배열이 가득 차면, 용량을 2배로 증가
        capacity *= 2;
        int *new_arr = new int[capacity];
        // 기존 배열의 요소를 새 배열로 복사
        for (int i = 0; i < n; i++) {
            new_arr[i] = arr[i];
        }
        // 기존 배열을 삭제하고 arr이 새 배열을 가리키도록 함
        delete[] arr;
        arr = new_arr;
    }
    // 새로운 요소를 배열에 추가
    arr[n++] = k;
}

int main() {
    int k;
    cout << "초기 배열 용량을 입력하세요: ";
    cin >> capacity;
    arr = new int[capacity]; // 초기 용량 설정
    while (1) {
        cin >> k;
        if (k == -1) break; // -1이 입력되면 루프 종료
        add_to_array(k);    // 정수를 배열에 추가
    }
    for (int i = 0; i < n; i++)
        cout << arr[i] << " "; // 배열의 모든 요소 출력
    cout << endl;
    
    // 동적으로 할당된 메모리 해제
    delete[] arr;
    
    return 0;
}

 

배열 요소 합계 계산하기

#include <iostream>
using namespace std;

const int init_capacity = 1;
int *arr = nullptr;
int capacity = 0; // 배열 arr의 현재 용량
int n = 0;       // 배열 arr에 저장된 정수의 개수

void add_to_array(int k) {
    if (capacity == 0) {
        // 용량이 0이면, 초기 용량으로 배열을 할당
        capacity = init_capacity;
        arr = new int[capacity];
    } else if (n == capacity) {
        // 배열이 가득 차면, 용량을 2배로 증가
        capacity *= 2;
        int *new_arr = new int[capacity];
        // 기존 배열의 요소를 새 배열로 복사
        for (int i = 0; i < n; i++) {
            new_arr[i] = arr[i];
        }
        // 기존 배열을 삭제하고 arr이 새 배열을 가리키도록 함
        delete[] arr;
        arr = new_arr;
    }
    // 새로운 요소를 배열에 추가
    arr[n++] = k;
}

int main() {
    int k;
    while (1) {
        cin >> k;
        if (k == -1) break; // -1이 입력되면 루프 종료
        add_to_array(k);    // 정수를 배열에 추가
    }
    for (int i = 0; i < n; i++)
        cout << arr[i] << " "; // 배열의 모든 요소 출력
    cout << endl;

    // 배열 요소의 합계 계산
    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += arr[i];
    cout << "배열 요소의 합계: " << sum << endl;
    
    // 동적으로 할당된 메모리 해제
    delete[] arr;
    
    return 0;
}

 

 

특정 값의 개수 세기

#include <iostream>
using namespace std;

const int init_capacity = 1;
int *arr = nullptr;
int capacity = 0; // 배열 arr의 현재 용량
int n = 0;       // 배열 arr에 저장된 정수의 개수

void add_to_array(int k) {
    if (capacity == 0) {
        // 용량이 0이면, 초기 용량으로 배열을 할당
        capacity = init_capacity;
        arr = new int[capacity];
    } else if (n == capacity) {
        // 배열이 가득 차면, 용량을 2배로 증가
        capacity *= 2;
        int *new_arr = new int[capacity];
        // 기존 배열의 요소를 새 배열로 복사
        for (int i = 0; i < n; i++) {
            new_arr[i] = arr[i];
        }
        // 기존 배열을 삭제하고 arr이 새 배열을 가리키도록 함
        delete[] arr;
        arr = new_arr;
    }
    // 새로운 요소를 배열에 추가
    arr[n++] = k;
}

int main() {
    int k;
    while (1) {
        cin >> k;
        if (k == -1) break; // -1이 입력되면 루프 종료
        add_to_array(k);    // 정수를 배열에 추가
    }
    for (int i = 0; i < n; i++)
        cout << arr[i] << " "; // 배열의 모든 요소 출력
    cout << endl;

    // 특정 값의 개수 세기
    int target = 5;
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (arr[i] == target) {
            count++;
        }
    }
    cout << target << "의 개수: " << count << endl;
    
    // 동적으로 할당된 메모리 해제
    delete[] arr;
    
    return 0;
}